blob: 23f573cd52a55c3104932ebe72aa81a4ee8322b7 [file] [log] [blame]
Shane Farmer0a5b2012017-06-22 12:24:12 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "optimize/MultiApkGenerator.h"
18
19#include <string>
20
21#include "gmock/gmock.h"
22#include "gtest/gtest.h"
23
24#include "LoadedApk.h"
25#include "ResourceTable.h"
26#include "configuration/ConfigurationParser.h"
27#include "filter/Filter.h"
28#include "flatten/Archive.h"
29#include "flatten/TableFlattener.h"
30#include "process/IResourceTableConsumer.h"
31#include "test/Context.h"
32#include "test/Test.h"
33
34namespace aapt {
35namespace {
36
37using ::aapt::configuration::Abi;
Shane Farmerefe45392017-08-21 14:39:28 -070038using ::aapt::configuration::AndroidSdk;
Shane Farmer0a5b2012017-06-22 12:24:12 -070039using ::aapt::configuration::Artifact;
40using ::aapt::configuration::PostProcessingConfiguration;
Shane Farmerefe45392017-08-21 14:39:28 -070041using ::aapt::test::GetValue;
42using ::aapt::test::GetValueForConfig;
43using ::aapt::test::ParseConfigOrDie;
Shane Farmer0a5b2012017-06-22 12:24:12 -070044using ::testing::Eq;
Shane Farmerefe45392017-08-21 14:39:28 -070045using ::testing::IsNull;
46using ::testing::Not;
47using ::testing::NotNull;
48using ::testing::PrintToString;
Shane Farmer0a5b2012017-06-22 12:24:12 -070049using ::testing::Return;
Shane Farmerefe45392017-08-21 14:39:28 -070050using ::testing::Test;
Shane Farmer0a5b2012017-06-22 12:24:12 -070051using ::testing::_;
52
Shane Farmerefe45392017-08-21 14:39:28 -070053/** Subclass the LoadedApk class so that we can mock the WriteToArchive method. */
Shane Farmer0a5b2012017-06-22 12:24:12 -070054class MockApk : public LoadedApk {
55 public:
56 MockApk(std::unique_ptr<ResourceTable> table) : LoadedApk({"test.apk"}, {}, std::move(table)){};
57 MOCK_METHOD5(WriteToArchive, bool(IAaptContext*, ResourceTable*, const TableFlattenerOptions&,
58 FilterChain*, IArchiveWriter*));
59};
60
Shane Farmerefe45392017-08-21 14:39:28 -070061/**
62 * Subclass the MultiApkGenerator class so that we can access the protected FilterTable method to
63 * directly test table filter.
64 */
65class MultiApkGeneratorWrapper : public MultiApkGenerator {
66 public:
67 MultiApkGeneratorWrapper(LoadedApk* apk, IAaptContext* context)
68 : MultiApkGenerator(apk, context) {
69 }
70
71 std::unique_ptr<ResourceTable> FilterTable(
72 const configuration::Artifact& artifact,
73 const configuration::PostProcessingConfiguration& config, const ResourceTable& old_table,
74 FilterChain* pChain) override {
75 return MultiApkGenerator::FilterTable(artifact, config, old_table, pChain);
76 }
77};
78
79/** MultiApkGenerator test fixture. */
80class MultiApkGeneratorTest : public ::testing::Test {
81 public:
82 std::unique_ptr<ResourceTable> BuildTable() {
83 return test::ResourceTableBuilder()
84 .AddFileReference(kResourceName, "res/drawable-mdpi/icon.png", mdpi_)
85 .AddFileReference(kResourceName, "res/drawable-hdpi/icon.png", hdpi_)
86 .AddFileReference(kResourceName, "res/drawable-xhdpi/icon.png", xhdpi_)
87 .AddFileReference(kResourceName, "res/drawable-xxhdpi/icon.png", xxhdpi_)
88 .AddFileReference(kResourceName, "res/drawable-v19/icon.xml", v19_)
89 .AddFileReference(kResourceName, "res/drawable-v21/icon.xml", v21_)
90 .AddSimple("android:string/one")
91 .Build();
92 }
93
94 inline FileReference* ValueForConfig(ResourceTable* table, const ConfigDescription& config) {
95 return GetValueForConfig<FileReference>(table, kResourceName, config);
96 };
97
98 void SetUp() override {
99 }
100
101 protected:
102 static constexpr const char* kResourceName = "android:drawable/icon";
103
104 ConfigDescription default_ = ParseConfigOrDie("").CopyWithoutSdkVersion();
105 ConfigDescription mdpi_ = ParseConfigOrDie("mdpi").CopyWithoutSdkVersion();
106 ConfigDescription hdpi_ = ParseConfigOrDie("hdpi").CopyWithoutSdkVersion();
107 ConfigDescription xhdpi_ = ParseConfigOrDie("xhdpi").CopyWithoutSdkVersion();
108 ConfigDescription xxhdpi_ = ParseConfigOrDie("xxhdpi").CopyWithoutSdkVersion();
109 ConfigDescription xxxhdpi_ = ParseConfigOrDie("xxxhdpi").CopyWithoutSdkVersion();
110 ConfigDescription v19_ = ParseConfigOrDie("v19");
111 ConfigDescription v21_ = ParseConfigOrDie("v21");
112};
113
114TEST_F(MultiApkGeneratorTest, FromBaseApk) {
115 std::unique_ptr<ResourceTable> table = BuildTable();
Shane Farmer0a5b2012017-06-22 12:24:12 -0700116
117 MockApk apk{std::move(table)};
118
119 EXPECT_CALL(apk, WriteToArchive(_, _, _, _, _)).Times(0);
120
121 test::Context ctx;
122 PostProcessingConfiguration empty_config;
123 TableFlattenerOptions table_flattener_options;
124
125 MultiApkGenerator generator{&apk, &ctx};
Shane Farmerefe45392017-08-21 14:39:28 -0700126 EXPECT_TRUE(generator.FromBaseApk({"out", empty_config, table_flattener_options}));
Shane Farmer0a5b2012017-06-22 12:24:12 -0700127
128 Artifact x64 = test::ArtifactBuilder()
129 .SetName("${basename}.x64.apk")
130 .SetAbiGroup("x64")
131 .SetLocaleGroup("en")
132 .SetDensityGroup("xhdpi")
133 .Build();
134
135 Artifact intel = test::ArtifactBuilder()
136 .SetName("${basename}.intel.apk")
137 .SetAbiGroup("intel")
138 .SetLocaleGroup("europe")
139 .SetDensityGroup("large")
140 .Build();
141
142 auto config = test::PostProcessingConfigurationBuilder()
143 .SetLocaleGroup("en", {"en"})
144 .SetLocaleGroup("europe", {"en", "fr", "de", "es"})
145 .SetAbiGroup("x64", {Abi::kX86_64})
146 .SetAbiGroup("intel", {Abi::kX86_64, Abi::kX86})
147 .SetDensityGroup("xhdpi", {"xhdpi"})
148 .SetDensityGroup("large", {"xhdpi", "xxhdpi", "xxxhdpi"})
149 .AddArtifact(x64)
150 .AddArtifact(intel)
151 .Build();
152
153 // Called once for each artifact.
154 EXPECT_CALL(apk, WriteToArchive(Eq(&ctx), _, _, _, _)).Times(2).WillRepeatedly(Return(true));
Shane Farmerefe45392017-08-21 14:39:28 -0700155 EXPECT_TRUE(generator.FromBaseApk({"out", config, table_flattener_options}));
156}
157
158TEST_F(MultiApkGeneratorTest, VersionFilterNewerVersion) {
159 std::unique_ptr<ResourceTable> table = BuildTable();
160
161 MockApk apk{std::move(table)};
162 std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(19).Build();
163 PostProcessingConfiguration empty_config;
164 TableFlattenerOptions table_flattener_options;
165 FilterChain chain;
166
167 Artifact x64 = test::ArtifactBuilder()
168 .SetName("${basename}.${sdk}.apk")
169 .SetDensityGroup("xhdpi")
170 .SetAndroidSdk("v23")
171 .Build();
172
173 auto config = test::PostProcessingConfigurationBuilder()
174 .SetLocaleGroup("en", {"en"})
175 .SetAbiGroup("x64", {Abi::kX86_64})
176 .SetDensityGroup("xhdpi", {"xhdpi"})
177 .SetAndroidSdk("v23", AndroidSdk::ForMinSdk("v23"))
178 .AddArtifact(x64)
179 .Build();
180
181 MultiApkGeneratorWrapper generator{&apk, ctx.get()};
182 std::unique_ptr<ResourceTable> split =
183 generator.FilterTable(x64, config, *apk.GetResourceTable(), &chain);
184
185 ResourceTable* new_table = split.get();
186 EXPECT_THAT(ValueForConfig(new_table, mdpi_), IsNull());
187 EXPECT_THAT(ValueForConfig(new_table, hdpi_), IsNull());
188 EXPECT_THAT(ValueForConfig(new_table, xxhdpi_), IsNull());
189 EXPECT_THAT(ValueForConfig(new_table, xxxhdpi_), IsNull());
190 EXPECT_THAT(ValueForConfig(new_table, v19_), IsNull());
191
192 // xhdpi directly matches one of the required dimensions.
193 EXPECT_THAT(ValueForConfig(new_table, xhdpi_), NotNull());
194 // drawable-v21 was converted to drawable.
195 EXPECT_THAT(ValueForConfig(new_table, default_), NotNull());
196 EXPECT_THAT(GetValue<Id>(new_table, "android:string/one"), NotNull());
197}
198
199TEST_F(MultiApkGeneratorTest, VersionFilterOlderVersion) {
200 std::unique_ptr<ResourceTable> table = BuildTable();
201
202 MockApk apk{std::move(table)};
203 std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
204 PostProcessingConfiguration empty_config;
205 TableFlattenerOptions table_flattener_options;
206 FilterChain chain;
207
208 Artifact x64 = test::ArtifactBuilder()
209 .SetName("${basename}.${sdk}.apk")
210 .SetDensityGroup("xhdpi")
211 .SetAndroidSdk("v4")
212 .Build();
213
214 auto config = test::PostProcessingConfigurationBuilder()
215 .SetLocaleGroup("en", {"en"})
216 .SetAbiGroup("x64", {Abi::kX86_64})
217 .SetDensityGroup("xhdpi", {"xhdpi"})
218 .SetAndroidSdk("v4", AndroidSdk::ForMinSdk("v4"))
219 .AddArtifact(x64)
220 .Build();
221
222 MultiApkGeneratorWrapper generator{&apk, ctx.get()};;
223 std::unique_ptr<ResourceTable> split =
224 generator.FilterTable(x64, config, *apk.GetResourceTable(), &chain);
225
226 ResourceTable* new_table = split.get();
227 EXPECT_THAT(ValueForConfig(new_table, mdpi_), IsNull());
228 EXPECT_THAT(ValueForConfig(new_table, hdpi_), IsNull());
229 EXPECT_THAT(ValueForConfig(new_table, xxhdpi_), IsNull());
230 EXPECT_THAT(ValueForConfig(new_table, xxxhdpi_), IsNull());
231
232 EXPECT_THAT(ValueForConfig(new_table, xhdpi_), NotNull());
233 EXPECT_THAT(ValueForConfig(new_table, v19_), NotNull());
234 EXPECT_THAT(ValueForConfig(new_table, v21_), NotNull());
235 EXPECT_THAT(GetValue<Id>(new_table, "android:string/one"), NotNull());
236}
237
238TEST_F(MultiApkGeneratorTest, VersionFilterNoVersion) {
239 std::unique_ptr<ResourceTable> table = BuildTable();
240
241 MockApk apk{std::move(table)};
242 std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
243 PostProcessingConfiguration empty_config;
244 TableFlattenerOptions table_flattener_options;
245 FilterChain chain;
246
247 Artifact x64 =
248 test::ArtifactBuilder().SetName("${basename}.${sdk}.apk").SetDensityGroup("xhdpi").Build();
249
250 auto config = test::PostProcessingConfigurationBuilder()
251 .SetLocaleGroup("en", {"en"})
252 .SetAbiGroup("x64", {Abi::kX86_64})
253 .SetDensityGroup("xhdpi", {"xhdpi"})
254 .AddArtifact(x64)
255 .Build();
256
257 MultiApkGeneratorWrapper generator{&apk, ctx.get()};
258 std::unique_ptr<ResourceTable> split =
259 generator.FilterTable(x64, config, *apk.GetResourceTable(), &chain);
260
261 ResourceTable* new_table = split.get();
262 EXPECT_THAT(ValueForConfig(new_table, mdpi_), IsNull());
263 EXPECT_THAT(ValueForConfig(new_table, hdpi_), IsNull());
264 EXPECT_THAT(ValueForConfig(new_table, xxhdpi_), IsNull());
265 EXPECT_THAT(ValueForConfig(new_table, xxxhdpi_), IsNull());
266
267 EXPECT_THAT(ValueForConfig(new_table, xhdpi_), NotNull());
268 EXPECT_THAT(ValueForConfig(new_table, v19_), NotNull());
269 EXPECT_THAT(ValueForConfig(new_table, v21_), NotNull());
270 EXPECT_THAT(GetValue<Id>(new_table, "android:string/one"), NotNull());
Shane Farmer0a5b2012017-06-22 12:24:12 -0700271}
272
273} // namespace
274} // namespace aapt