Files
frameworks_base/tools/aapt2/optimize/MultiApkGenerator_test.cpp
Shane Farmer cb6c3f9b88 AAPT2: Push more configuration code into the parser
When parsing is complete, we now have a list of output artifacts that
have their referential integrity validated. This means that once the
configuration file is parsed, the only errors that can occur are related
to APK processing, and not the configuration itself.

This reduces the number of errors that could cause a partial output of
APK artifacts. It simplifies the public API and reduces the complexity of
the code to generate multiple APKs.

Test: Ran unit tests
Test: manually ran the optimize command to ensure it still works

Change-Id: I3f2d885b207a84c958f5348a4baa6718598184a4
2017-12-13 12:28:39 -08:00

183 lines
7.1 KiB
C++

/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "optimize/MultiApkGenerator.h"
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "LoadedApk.h"
#include "ResourceTable.h"
#include "configuration/ConfigurationParser.h"
#include "filter/Filter.h"
#include "format/Archive.h"
#include "format/binary/TableFlattener.h"
#include "process/IResourceTableConsumer.h"
#include "test/Context.h"
#include "test/Test.h"
namespace aapt {
namespace {
using ::aapt::configuration::Abi;
using ::aapt::configuration::AndroidSdk;
using ::aapt::configuration::OutputArtifact;
using ::aapt::test::GetValue;
using ::aapt::test::GetValueForConfig;
using ::aapt::test::ParseConfigOrDie;
using ::testing::Eq;
using ::testing::IsNull;
using ::testing::Not;
using ::testing::NotNull;
using ::testing::PrintToString;
using ::testing::Return;
using ::testing::Test;
/**
* Subclass the MultiApkGenerator class so that we can access the protected FilterTable method to
* directly test table filter.
*/
class MultiApkGeneratorWrapper : public MultiApkGenerator {
public:
MultiApkGeneratorWrapper(LoadedApk* apk, IAaptContext* context)
: MultiApkGenerator(apk, context) {
}
std::unique_ptr<ResourceTable> FilterTable(IAaptContext* context,
const configuration::OutputArtifact& artifact,
const ResourceTable& old_table,
FilterChain* filter_chain) override {
return MultiApkGenerator::FilterTable(context, artifact, old_table, filter_chain);
}
};
/** MultiApkGenerator test fixture. */
class MultiApkGeneratorTest : public ::testing::Test {
public:
std::unique_ptr<ResourceTable> BuildTable() {
return test::ResourceTableBuilder()
.AddFileReference(kResourceName, "res/drawable-mdpi/icon.png", mdpi_)
.AddFileReference(kResourceName, "res/drawable-hdpi/icon.png", hdpi_)
.AddFileReference(kResourceName, "res/drawable-xhdpi/icon.png", xhdpi_)
.AddFileReference(kResourceName, "res/drawable-xxhdpi/icon.png", xxhdpi_)
.AddFileReference(kResourceName, "res/drawable-v19/icon.xml", v19_)
.AddFileReference(kResourceName, "res/drawable-v21/icon.xml", v21_)
.AddSimple("android:string/one")
.Build();
}
inline FileReference* ValueForConfig(ResourceTable* table, const ConfigDescription& config) {
return GetValueForConfig<FileReference>(table, kResourceName, config);
};
void SetUp() override {
}
protected:
static constexpr const char* kResourceName = "android:drawable/icon";
ConfigDescription default_ = ParseConfigOrDie("").CopyWithoutSdkVersion();
ConfigDescription mdpi_ = ParseConfigOrDie("mdpi").CopyWithoutSdkVersion();
ConfigDescription hdpi_ = ParseConfigOrDie("hdpi").CopyWithoutSdkVersion();
ConfigDescription xhdpi_ = ParseConfigOrDie("xhdpi").CopyWithoutSdkVersion();
ConfigDescription xxhdpi_ = ParseConfigOrDie("xxhdpi").CopyWithoutSdkVersion();
ConfigDescription xxxhdpi_ = ParseConfigOrDie("xxxhdpi").CopyWithoutSdkVersion();
ConfigDescription v19_ = ParseConfigOrDie("v19");
ConfigDescription v21_ = ParseConfigOrDie("v21");
};
TEST_F(MultiApkGeneratorTest, VersionFilterNewerVersion) {
std::unique_ptr<ResourceTable> table = BuildTable();
LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(19).Build();
FilterChain chain;
OutputArtifact artifact = test::ArtifactBuilder().AddDensity(xhdpi_).SetAndroidSdk(23).Build();
MultiApkGeneratorWrapper generator{&apk, ctx.get()};
std::unique_ptr<ResourceTable> split =
generator.FilterTable(ctx.get(), artifact, *apk.GetResourceTable(), &chain);
ResourceTable* new_table = split.get();
EXPECT_THAT(ValueForConfig(new_table, mdpi_), IsNull());
EXPECT_THAT(ValueForConfig(new_table, hdpi_), IsNull());
EXPECT_THAT(ValueForConfig(new_table, xxhdpi_), IsNull());
EXPECT_THAT(ValueForConfig(new_table, xxxhdpi_), IsNull());
EXPECT_THAT(ValueForConfig(new_table, v19_), IsNull());
// xhdpi directly matches one of the required dimensions.
EXPECT_THAT(ValueForConfig(new_table, xhdpi_), NotNull());
// drawable-v21 was converted to drawable.
EXPECT_THAT(ValueForConfig(new_table, default_), NotNull());
EXPECT_THAT(GetValue<Id>(new_table, "android:string/one"), NotNull());
}
TEST_F(MultiApkGeneratorTest, VersionFilterOlderVersion) {
std::unique_ptr<ResourceTable> table = BuildTable();
LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
FilterChain chain;
OutputArtifact artifact = test::ArtifactBuilder().AddDensity(xhdpi_).SetAndroidSdk(4).Build();
MultiApkGeneratorWrapper generator{&apk, ctx.get()};;
std::unique_ptr<ResourceTable> split =
generator.FilterTable(ctx.get(), artifact, *apk.GetResourceTable(), &chain);
ResourceTable* new_table = split.get();
EXPECT_THAT(ValueForConfig(new_table, mdpi_), IsNull());
EXPECT_THAT(ValueForConfig(new_table, hdpi_), IsNull());
EXPECT_THAT(ValueForConfig(new_table, xxhdpi_), IsNull());
EXPECT_THAT(ValueForConfig(new_table, xxxhdpi_), IsNull());
EXPECT_THAT(ValueForConfig(new_table, xhdpi_), NotNull());
EXPECT_THAT(ValueForConfig(new_table, v19_), NotNull());
EXPECT_THAT(ValueForConfig(new_table, v21_), NotNull());
EXPECT_THAT(GetValue<Id>(new_table, "android:string/one"), NotNull());
}
TEST_F(MultiApkGeneratorTest, VersionFilterNoVersion) {
std::unique_ptr<ResourceTable> table = BuildTable();
LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
FilterChain chain;
OutputArtifact artifact = test::ArtifactBuilder().AddDensity(xhdpi_).Build();
MultiApkGeneratorWrapper generator{&apk, ctx.get()};
std::unique_ptr<ResourceTable> split =
generator.FilterTable(ctx.get(), artifact, *apk.GetResourceTable(), &chain);
ResourceTable* new_table = split.get();
EXPECT_THAT(ValueForConfig(new_table, mdpi_), IsNull());
EXPECT_THAT(ValueForConfig(new_table, hdpi_), IsNull());
EXPECT_THAT(ValueForConfig(new_table, xxhdpi_), IsNull());
EXPECT_THAT(ValueForConfig(new_table, xxxhdpi_), IsNull());
EXPECT_THAT(ValueForConfig(new_table, xhdpi_), NotNull());
EXPECT_THAT(ValueForConfig(new_table, v19_), NotNull());
EXPECT_THAT(ValueForConfig(new_table, v21_), NotNull());
EXPECT_THAT(GetValue<Id>(new_table, "android:string/one"), NotNull());
}
} // namespace
} // namespace aapt