1 /*
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 "configuration/ConfigurationParser.h"
18
19 #include <string>
20
21 #include "android-base/stringprintf.h"
22 #include "androidfw/ResourceTypes.h"
23
24 #include "SdkConstants.h"
25 #include "configuration/ConfigurationParser.internal.h"
26 #include "test/Test.h"
27 #include "xml/XmlDom.h"
28
29 using ::android::ConfigDescription;
30
31 namespace aapt {
32
33 namespace configuration {
PrintTo(const AndroidSdk & sdk,std::ostream * os)34 void PrintTo(const AndroidSdk& sdk, std::ostream* os) {
35 *os << "SDK: min=" << sdk.min_sdk_version
36 << ", target=" << sdk.target_sdk_version.value_or_default(-1)
37 << ", max=" << sdk.max_sdk_version.value_or_default(-1);
38 }
39
operator ==(const ConfiguredArtifact & lhs,const ConfiguredArtifact & rhs)40 bool operator==(const ConfiguredArtifact& lhs, const ConfiguredArtifact& rhs) {
41 return lhs.name == rhs.name && lhs.abi_group == rhs.abi_group &&
42 lhs.screen_density_group == rhs.screen_density_group &&
43 lhs.locale_group == rhs.locale_group && lhs.android_sdk == rhs.android_sdk &&
44 lhs.device_feature_group == rhs.device_feature_group &&
45 lhs.gl_texture_group == rhs.gl_texture_group;
46 }
47
operator <<(std::ostream & out,const Maybe<std::string> & value)48 std::ostream& operator<<(std::ostream& out, const Maybe<std::string>& value) {
49 PrintTo(value, &out);
50 return out;
51 }
52
PrintTo(const ConfiguredArtifact & artifact,std::ostream * os)53 void PrintTo(const ConfiguredArtifact& artifact, std::ostream* os) {
54 *os << "\n{"
55 << "\n name: " << artifact.name << "\n sdk: " << artifact.android_sdk
56 << "\n abi: " << artifact.abi_group << "\n density: " << artifact.screen_density_group
57 << "\n locale: " << artifact.locale_group
58 << "\n features: " << artifact.device_feature_group
59 << "\n textures: " << artifact.gl_texture_group << "\n}\n";
60 }
61
62 namespace handler {
63
64 namespace {
65
66 using ::aapt::configuration::Abi;
67 using ::aapt::configuration::AndroidManifest;
68 using ::aapt::configuration::AndroidSdk;
69 using ::aapt::configuration::ConfiguredArtifact;
70 using ::aapt::configuration::DeviceFeature;
71 using ::aapt::configuration::ExtractConfiguration;
72 using ::aapt::configuration::GlTexture;
73 using ::aapt::configuration::Locale;
74 using ::aapt::configuration::PostProcessingConfiguration;
75 using ::aapt::xml::Element;
76 using ::aapt::xml::NodeCast;
77 using ::android::ResTable_config;
78 using ::android::base::StringPrintf;
79 using ::testing::ElementsAre;
80 using ::testing::Eq;
81 using ::testing::SizeIs;
82 using ::testing::StrEq;
83
84 constexpr const char* kValidConfig = R"(<?xml version="1.0" encoding="utf-8" ?>
85 <post-process xmlns="http://schemas.android.com/tools/aapt">
86 <abi-groups>
87 <abi-group label="other" version-code-order="2">
88 <abi>x86</abi>
89 <abi>mips</abi>
90 </abi-group>
91 <abi-group label="arm" version-code-order="1">
92 <abi>armeabi-v7a</abi>
93 <abi>arm64-v8a</abi>
94 </abi-group>
95 </abi-groups>
96 <screen-density-groups>
97 <screen-density-group label="large" version-code-order="2">
98 <screen-density>xhdpi</screen-density>
99 <screen-density>xxhdpi</screen-density>
100 <screen-density>xxxhdpi</screen-density>
101 </screen-density-group>
102 <screen-density-group label="alldpi" version-code-order="1">
103 <screen-density>ldpi</screen-density>
104 <screen-density>mdpi</screen-density>
105 <screen-density>hdpi</screen-density>
106 <screen-density>xhdpi</screen-density>
107 <screen-density>xxhdpi</screen-density>
108 <screen-density>xxxhdpi</screen-density>
109 </screen-density-group>
110 </screen-density-groups>
111 <locale-groups>
112 <locale-group label="europe" version-code-order="1">
113 <locale>en</locale>
114 <locale>es</locale>
115 <locale>fr</locale>
116 <locale>de</locale>
117 </locale-group>
118 <locale-group label="north-america" version-code-order="2">
119 <locale>en</locale>
120 <locale>es-rMX</locale>
121 <locale>fr-rCA</locale>
122 </locale-group>
123 <locale-group label="all" version-code-order="-1">
124 <locale />
125 </locale-group>
126 </locale-groups>
127 <android-sdks>
128 <android-sdk
129 label="v19"
130 minSdkVersion="19"
131 targetSdkVersion="24"
132 maxSdkVersion="25">
133 <manifest>
134 <!--- manifest additions here XSLT? TODO -->
135 </manifest>
136 </android-sdk>
137 </android-sdks>
138 <gl-texture-groups>
139 <gl-texture-group label="dxt1" version-code-order="2">
140 <gl-texture name="GL_EXT_texture_compression_dxt1">
141 <texture-path>assets/dxt1/*</texture-path>
142 </gl-texture>
143 </gl-texture-group>
144 </gl-texture-groups>
145 <device-feature-groups>
146 <device-feature-group label="low-latency" version-code-order="2">
147 <supports-feature>android.hardware.audio.low_latency</supports-feature>
148 </device-feature-group>
149 </device-feature-groups>
150 <artifacts>
151 <artifact-format>
152 ${base}.${abi}.${screen-density}.${locale}.${sdk}.${gl}.${feature}.release
153 </artifact-format>
154 <artifact
155 name="art1"
156 abi-group="arm"
157 screen-density-group="large"
158 locale-group="europe"
159 android-sdk="v19"
160 gl-texture-group="dxt1"
161 device-feature-group="low-latency"/>
162 <artifact
163 name="art2"
164 abi-group="other"
165 screen-density-group="alldpi"
166 locale-group="north-america"
167 android-sdk="v19"
168 gl-texture-group="dxt1"
169 device-feature-group="low-latency"/>
170 </artifacts>
171 </post-process>
172 )";
173
174 class ConfigurationParserTest : public ConfigurationParser, public ::testing::Test {
175 public:
ConfigurationParserTest()176 ConfigurationParserTest() : ConfigurationParser("", "config.xml") {
177 }
178
179 protected:
180 StdErrDiagnostics diag_;
181 };
182
183 TEST_F(ConfigurationParserTest, ForPath_NoFile) {
184 auto result = ConfigurationParser::ForPath("./does_not_exist.xml");
185 EXPECT_FALSE(result);
186 }
187
188 TEST_F(ConfigurationParserTest, ExtractConfiguration) {
189 Maybe<PostProcessingConfiguration> maybe_config =
190 ExtractConfiguration(kValidConfig, "dummy.xml", &diag_);
191
192 PostProcessingConfiguration config = maybe_config.value();
193
194 auto& arm = config.abi_groups["arm"];
195 auto& other = config.abi_groups["other"];
196 EXPECT_EQ(arm.order, 1);
197 EXPECT_EQ(other.order, 2);
198
199 auto& large = config.screen_density_groups["large"];
200 auto& alldpi = config.screen_density_groups["alldpi"];
201 EXPECT_EQ(large.order, 2);
202 EXPECT_EQ(alldpi.order, 1);
203
204 auto& north_america = config.locale_groups["north-america"];
205 auto& europe = config.locale_groups["europe"];
206 auto& all = config.locale_groups["all"];
207 // Checked in reverse to make sure access order does not matter.
208 EXPECT_EQ(north_america.order, 2);
209 EXPECT_EQ(europe.order, 1);
210 EXPECT_EQ(all.order, -1);
211 EXPECT_EQ(3ul, config.locale_groups.size());
212 }
213
214 TEST_F(ConfigurationParserTest, ValidateFile) {
215 auto parser = ConfigurationParser::ForContents(kValidConfig, "conf.xml").WithDiagnostics(&diag_);
216 auto result = parser.Parse("test.apk");
217 ASSERT_TRUE(result);
218 const std::vector<OutputArtifact>& value = result.value();
219 EXPECT_THAT(value, SizeIs(2ul));
220
221 const OutputArtifact& a1 = value[0];
222 EXPECT_EQ(a1.name, "art1.apk");
223 EXPECT_EQ(a1.version, 1);
224 EXPECT_THAT(a1.abis, ElementsAre(Abi::kArmV7a, Abi::kArm64V8a));
225 EXPECT_THAT(a1.screen_densities,
226 ElementsAre(test::ParseConfigOrDie("xhdpi").CopyWithoutSdkVersion(),
227 test::ParseConfigOrDie("xxhdpi").CopyWithoutSdkVersion(),
228 test::ParseConfigOrDie("xxxhdpi").CopyWithoutSdkVersion()));
229 EXPECT_THAT(a1.locales, ElementsAre(test::ParseConfigOrDie("en"), test::ParseConfigOrDie("es"),
230 test::ParseConfigOrDie("fr"), test::ParseConfigOrDie("de")));
231 ASSERT_TRUE(a1.android_sdk);
232 ASSERT_TRUE(a1.android_sdk.value().min_sdk_version);
233 EXPECT_EQ(a1.android_sdk.value().min_sdk_version, 19L);
234 EXPECT_THAT(a1.textures, SizeIs(1ul));
235 EXPECT_THAT(a1.features, SizeIs(1ul));
236
237 const OutputArtifact& a2 = value[1];
238 EXPECT_EQ(a2.name, "art2.apk");
239 EXPECT_EQ(a2.version, 2);
240 EXPECT_THAT(a2.abis, ElementsAre(Abi::kX86, Abi::kMips));
241 EXPECT_THAT(a2.screen_densities,
242 ElementsAre(test::ParseConfigOrDie("ldpi").CopyWithoutSdkVersion(),
243 test::ParseConfigOrDie("mdpi").CopyWithoutSdkVersion(),
244 test::ParseConfigOrDie("hdpi").CopyWithoutSdkVersion(),
245 test::ParseConfigOrDie("xhdpi").CopyWithoutSdkVersion(),
246 test::ParseConfigOrDie("xxhdpi").CopyWithoutSdkVersion(),
247 test::ParseConfigOrDie("xxxhdpi").CopyWithoutSdkVersion()));
248 EXPECT_THAT(a2.locales,
249 ElementsAre(test::ParseConfigOrDie("en"), test::ParseConfigOrDie("es-rMX"),
250 test::ParseConfigOrDie("fr-rCA")));
251 ASSERT_TRUE(a2.android_sdk);
252 ASSERT_TRUE(a2.android_sdk.value().min_sdk_version);
253 EXPECT_EQ(a2.android_sdk.value().min_sdk_version, 19L);
254 EXPECT_THAT(a2.textures, SizeIs(1ul));
255 EXPECT_THAT(a2.features, SizeIs(1ul));
256 }
257
258 TEST_F(ConfigurationParserTest, ConfiguredArtifactOrdering) {
259 // Create a base builder with the configuration groups but no artifacts to allow it to be copied.
260 test::PostProcessingConfigurationBuilder base_builder = test::PostProcessingConfigurationBuilder()
261 .AddAbiGroup("arm")
262 .AddAbiGroup("arm64")
263 .AddAndroidSdk("v23", 23)
264 .AddAndroidSdk("v19", 19);
265
266 {
267 // Test version ordering.
268 ConfiguredArtifact v23;
269 v23.android_sdk = {"v23"};
270 ConfiguredArtifact v19;
271 v19.android_sdk = {"v19"};
272
273 test::PostProcessingConfigurationBuilder builder = base_builder;
274 PostProcessingConfiguration config = builder.AddArtifact(v23).AddArtifact(v19).Build();
275
276 config.SortArtifacts();
277 ASSERT_THAT(config.artifacts, SizeIs(2));
278 EXPECT_THAT(config.artifacts[0], Eq(v19));
279 EXPECT_THAT(config.artifacts[1], Eq(v23));
280 }
281
282 {
283 // Test ABI ordering.
284 ConfiguredArtifact arm;
285 arm.android_sdk = {"v19"};
286 arm.abi_group = {"arm"};
287 ConfiguredArtifact arm64;
288 arm64.android_sdk = {"v19"};
289 arm64.abi_group = {"arm64"};
290
291 test::PostProcessingConfigurationBuilder builder = base_builder;
292 PostProcessingConfiguration config = builder.AddArtifact(arm64).AddArtifact(arm).Build();
293
294 config.SortArtifacts();
295 ASSERT_THAT(config.artifacts, SizeIs(2));
296 EXPECT_THAT(config.artifacts[0], Eq(arm));
297 EXPECT_THAT(config.artifacts[1], Eq(arm64));
298 }
299
300 {
301 // Test Android SDK has precedence over ABI.
302 ConfiguredArtifact arm;
303 arm.android_sdk = {"v23"};
304 arm.abi_group = {"arm"};
305 ConfiguredArtifact arm64;
306 arm64.android_sdk = {"v19"};
307 arm64.abi_group = {"arm64"};
308
309 test::PostProcessingConfigurationBuilder builder = base_builder;
310 PostProcessingConfiguration config = builder.AddArtifact(arm64).AddArtifact(arm).Build();
311
312 config.SortArtifacts();
313 ASSERT_THAT(config.artifacts, SizeIs(2));
314 EXPECT_THAT(config.artifacts[0], Eq(arm64));
315 EXPECT_THAT(config.artifacts[1], Eq(arm));
316 }
317
318 {
319 // Test version is better than ABI.
320 ConfiguredArtifact arm;
321 arm.abi_group = {"arm"};
322 ConfiguredArtifact v19;
323 v19.android_sdk = {"v19"};
324
325 test::PostProcessingConfigurationBuilder builder = base_builder;
326 PostProcessingConfiguration config = builder.AddArtifact(v19).AddArtifact(arm).Build();
327
328 config.SortArtifacts();
329 ASSERT_THAT(config.artifacts, SizeIs(2));
330 EXPECT_THAT(config.artifacts[0], Eq(arm));
331 EXPECT_THAT(config.artifacts[1], Eq(v19));
332 }
333
334 {
335 // Test version is sorted higher than no version.
336 ConfiguredArtifact arm;
337 arm.abi_group = {"arm"};
338 ConfiguredArtifact v19;
339 v19.abi_group = {"arm"};
340 v19.android_sdk = {"v19"};
341
342 test::PostProcessingConfigurationBuilder builder = base_builder;
343 PostProcessingConfiguration config = builder.AddArtifact(v19).AddArtifact(arm).Build();
344
345 config.SortArtifacts();
346 ASSERT_THAT(config.artifacts, SizeIs(2));
347 EXPECT_THAT(config.artifacts[0], Eq(arm));
348 EXPECT_THAT(config.artifacts[1], Eq(v19));
349 }
350 }
351
352 TEST_F(ConfigurationParserTest, InvalidNamespace) {
353 constexpr const char* invalid_ns = R"(<?xml version="1.0" encoding="utf-8" ?>
354 <post-process xmlns="http://schemas.android.com/tools/another-unknown-tool" />)";
355
356 auto result = ConfigurationParser::ForContents(invalid_ns, "config.xml").Parse("test.apk");
357 ASSERT_FALSE(result);
358 }
359
360 TEST_F(ConfigurationParserTest, ArtifactAction) {
361 PostProcessingConfiguration config;
362 const auto doc = test::BuildXmlDom(R"xml(
363 <artifact
364 abi-group="arm"
365 screen-density-group="large"
366 locale-group="europe"
367 android-sdk="v19"
368 gl-texture-group="dxt1"
369 device-feature-group="low-latency"/>)xml");
370
371 ASSERT_TRUE(ArtifactTagHandler(&config, NodeCast<Element>(doc->root.get()), &diag_));
372
373 EXPECT_THAT(config.artifacts, SizeIs(1ul));
374
375 auto& artifact = config.artifacts.back();
376 EXPECT_FALSE(artifact.name); // TODO: make this fail.
377 EXPECT_EQ("arm", artifact.abi_group.value());
378 EXPECT_EQ("large", artifact.screen_density_group.value());
379 EXPECT_EQ("europe", artifact.locale_group.value());
380 EXPECT_EQ("v19", artifact.android_sdk.value());
381 EXPECT_EQ("dxt1", artifact.gl_texture_group.value());
382 EXPECT_EQ("low-latency", artifact.device_feature_group.value());
383 }
384
385 TEST_F(ConfigurationParserTest, ArtifactFormatAction) {
386 const auto doc = test::BuildXmlDom(R"xml(
387 <artifact-format>
388 ${base}.${abi}.${screen-density}.${locale}.${sdk}.${gl}.${feature}.release
389 </artifact-format>)xml");
390
391 PostProcessingConfiguration config;
392 bool ok = ArtifactFormatTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
393 ASSERT_TRUE(ok);
394 ASSERT_TRUE(config.artifact_format);
395 EXPECT_EQ(
396 "${base}.${abi}.${screen-density}.${locale}.${sdk}.${gl}.${feature}.release",
397 static_cast<std::string>(config.artifact_format.value())
398 );
399 }
400
401 TEST_F(ConfigurationParserTest, AbiGroupAction) {
402 static constexpr const char* xml = R"xml(
403 <abi-group label="arm" version-code-order="2">
404 <!-- First comment. -->
405 <abi>
406 armeabi-v7a
407 </abi>
408 <!-- Another comment. -->
409 <abi>arm64-v8a</abi>
410 </abi-group>)xml";
411
412 auto doc = test::BuildXmlDom(xml);
413
414 PostProcessingConfiguration config;
415 bool ok = AbiGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
416 ASSERT_TRUE(ok);
417
418 EXPECT_THAT(config.abi_groups, SizeIs(1ul));
419 ASSERT_EQ(1u, config.abi_groups.count("arm"));
420
421 auto& out = config.abi_groups["arm"].entry;
422 ASSERT_THAT(out, ElementsAre(Abi::kArmV7a, Abi::kArm64V8a));
423 }
424
425 TEST_F(ConfigurationParserTest, AbiGroupAction_EmptyGroup) {
426 static constexpr const char* xml =
427 R"xml(<abi-group label="arm64-v8a" version-code-order="3"/>)xml";
428
429 auto doc = test::BuildXmlDom(xml);
430
431 PostProcessingConfiguration config;
432 bool ok = AbiGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
433 ASSERT_TRUE(ok);
434
435 EXPECT_THAT(config.abi_groups, SizeIs(1ul));
436 ASSERT_EQ(1u, config.abi_groups.count("arm64-v8a"));
437
438 auto& out = config.abi_groups["arm64-v8a"];
439 ASSERT_THAT(out.entry, ElementsAre(Abi::kArm64V8a));
440 EXPECT_EQ(3, out.order);
441 }
442
443 TEST_F(ConfigurationParserTest, AbiGroupAction_EmptyGroup_NoOrder) {
444 static constexpr const char* xml = R"xml(<abi-group label="arm64-v8a"/>)xml";
445
446 auto doc = test::BuildXmlDom(xml);
447
448 PostProcessingConfiguration config;
449 bool ok = AbiGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
450 ASSERT_FALSE(ok);
451 }
452
453 TEST_F(ConfigurationParserTest, AbiGroupAction_InvalidEmptyGroup) {
454 static constexpr const char* xml = R"xml(<abi-group label="arm" order="2"/>)xml";
455
456 auto doc = test::BuildXmlDom(xml);
457
458 PostProcessingConfiguration config;
459 bool ok = AbiGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
460 ASSERT_FALSE(ok);
461 }
462
463 TEST_F(ConfigurationParserTest, ScreenDensityGroupAction) {
464 static constexpr const char* xml = R"xml(
465 <screen-density-group label="large" version-code-order="2">
466 <screen-density>xhdpi</screen-density>
467 <screen-density>
468 xxhdpi
469 </screen-density>
470 <screen-density>xxxhdpi</screen-density>
471 </screen-density-group>)xml";
472
473 auto doc = test::BuildXmlDom(xml);
474
475 PostProcessingConfiguration config;
476 bool ok = ScreenDensityGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
477 ASSERT_TRUE(ok);
478
479 EXPECT_THAT(config.screen_density_groups, SizeIs(1ul));
480 ASSERT_EQ(1u, config.screen_density_groups.count("large"));
481
482 ConfigDescription xhdpi;
483 xhdpi.density = ResTable_config::DENSITY_XHIGH;
484 ConfigDescription xxhdpi;
485 xxhdpi.density = ResTable_config::DENSITY_XXHIGH;
486 ConfigDescription xxxhdpi;
487 xxxhdpi.density = ResTable_config::DENSITY_XXXHIGH;
488
489 auto& out = config.screen_density_groups["large"].entry;
490 ASSERT_THAT(out, ElementsAre(xhdpi, xxhdpi, xxxhdpi));
491 }
492
493 TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_EmtpyGroup) {
494 static constexpr const char* xml =
495 R"xml(<screen-density-group label="xhdpi" version-code-order="4"/>)xml";
496
497 auto doc = test::BuildXmlDom(xml);
498
499 PostProcessingConfiguration config;
500 bool ok = ScreenDensityGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
501 ASSERT_TRUE(ok);
502
503 EXPECT_THAT(config.screen_density_groups, SizeIs(1ul));
504 ASSERT_EQ(1u, config.screen_density_groups.count("xhdpi"));
505
506 ConfigDescription xhdpi;
507 xhdpi.density = ResTable_config::DENSITY_XHIGH;
508
509 auto& out = config.screen_density_groups["xhdpi"];
510 EXPECT_THAT(out.entry, ElementsAre(xhdpi));
511 EXPECT_EQ(4, out.order);
512 }
513
514 TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_EmtpyGroup_NoVersion) {
515 static constexpr const char* xml = R"xml(<screen-density-group label="xhdpi"/>)xml";
516
517 auto doc = test::BuildXmlDom(xml);
518
519 PostProcessingConfiguration config;
520 bool ok = ScreenDensityGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
521 ASSERT_FALSE(ok);
522 }
523
524 TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_InvalidEmtpyGroup) {
525 static constexpr const char* xml = R"xml(<screen-density-group label="really-big-screen"/>)xml";
526
527 auto doc = test::BuildXmlDom(xml);
528
529 PostProcessingConfiguration config;
530 bool ok = ScreenDensityGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
531 ASSERT_FALSE(ok);
532 }
533
534 TEST_F(ConfigurationParserTest, LocaleGroupAction) {
535 static constexpr const char* xml = R"xml(
536 <locale-group label="europe" version-code-order="2">
537 <locale>en</locale>
538 <locale>es</locale>
539 <locale>fr</locale>
540 <locale>de</locale>
541 </locale-group>)xml";
542
543 auto doc = test::BuildXmlDom(xml);
544
545 PostProcessingConfiguration config;
546 bool ok = LocaleGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
547 ASSERT_TRUE(ok);
548
549 ASSERT_EQ(1ul, config.locale_groups.size());
550 ASSERT_EQ(1u, config.locale_groups.count("europe"));
551
552 const auto& out = config.locale_groups["europe"].entry;
553
554 ConfigDescription en = test::ParseConfigOrDie("en");
555 ConfigDescription es = test::ParseConfigOrDie("es");
556 ConfigDescription fr = test::ParseConfigOrDie("fr");
557 ConfigDescription de = test::ParseConfigOrDie("de");
558
559 ASSERT_THAT(out, ElementsAre(en, es, fr, de));
560 }
561
562 TEST_F(ConfigurationParserTest, LocaleGroupAction_EmtpyGroup) {
563 static constexpr const char* xml = R"xml(<locale-group label="en" version-code-order="6"/>)xml";
564
565 auto doc = test::BuildXmlDom(xml);
566
567 PostProcessingConfiguration config;
568 bool ok = LocaleGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
569 ASSERT_TRUE(ok);
570
571 ASSERT_EQ(1ul, config.locale_groups.size());
572 ASSERT_EQ(1u, config.locale_groups.count("en"));
573
574 const auto& out = config.locale_groups["en"];
575
576 ConfigDescription en = test::ParseConfigOrDie("en");
577
578 EXPECT_THAT(out.entry, ElementsAre(en));
579 EXPECT_EQ(6, out.order);
580 }
581
582 TEST_F(ConfigurationParserTest, LocaleGroupAction_EmtpyGroup_NoOrder) {
583 static constexpr const char* xml = R"xml(<locale-group label="en"/>)xml";
584
585 auto doc = test::BuildXmlDom(xml);
586
587 PostProcessingConfiguration config;
588 bool ok = LocaleGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
589 ASSERT_FALSE(ok);
590 }
591
592 TEST_F(ConfigurationParserTest, LocaleGroupAction_InvalidEmtpyGroup) {
593 static constexpr const char* xml = R"xml(<locale-group label="arm64"/>)xml";
594
595 auto doc = test::BuildXmlDom(xml);
596
597 PostProcessingConfiguration config;
598 bool ok = LocaleGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
599 ASSERT_FALSE(ok);
600 }
601
602 TEST_F(ConfigurationParserTest, AndroidSdkGroupAction) {
603 static constexpr const char* xml = R"xml(
604 <android-sdk label="v19"
605 minSdkVersion="19"
606 targetSdkVersion="24"
607 maxSdkVersion="25">
608 <manifest>
609 <!--- manifest additions here XSLT? TODO -->
610 </manifest>
611 </android-sdk>)xml";
612
613 auto doc = test::BuildXmlDom(xml);
614
615 PostProcessingConfiguration config;
616 bool ok = AndroidSdkTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
617 ASSERT_TRUE(ok);
618
619 ASSERT_EQ(1ul, config.android_sdks.size());
620 ASSERT_EQ(1u, config.android_sdks.count("v19"));
621
622 auto& out = config.android_sdks["v19"];
623
624 AndroidSdk sdk;
625 sdk.min_sdk_version = 19;
626 sdk.target_sdk_version = 24;
627 sdk.max_sdk_version = 25;
628 sdk.manifest = AndroidManifest();
629
630 ASSERT_EQ(sdk, out);
631 }
632
633 TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_SingleVersion) {
634 {
635 const char* xml = "<android-sdk label='v19' minSdkVersion='19'></android-sdk>";
636 auto doc = test::BuildXmlDom(xml);
637
638 PostProcessingConfiguration config;
639 bool ok = AndroidSdkTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
640 ASSERT_TRUE(ok);
641
642 ASSERT_EQ(1ul, config.android_sdks.size());
643 ASSERT_EQ(1u, config.android_sdks.count("v19"));
644
645 auto& out = config.android_sdks["v19"];
646 EXPECT_EQ(19, out.min_sdk_version);
647 EXPECT_FALSE(out.max_sdk_version);
648 EXPECT_FALSE(out.target_sdk_version);
649 }
650
651 {
652 const char* xml =
653 "<android-sdk label='v19' minSdkVersion='19' maxSdkVersion='19'></android-sdk>";
654 auto doc = test::BuildXmlDom(xml);
655
656 PostProcessingConfiguration config;
657 bool ok = AndroidSdkTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
658 ASSERT_TRUE(ok);
659
660 ASSERT_EQ(1ul, config.android_sdks.size());
661 ASSERT_EQ(1u, config.android_sdks.count("v19"));
662
663 auto& out = config.android_sdks["v19"];
664 EXPECT_EQ(19, out.max_sdk_version.value());
665 EXPECT_EQ(19, out.min_sdk_version);
666 EXPECT_FALSE(out.target_sdk_version);
667 }
668
669 {
670 const char* xml =
671 "<android-sdk label='v19' minSdkVersion='19' targetSdkVersion='19'></android-sdk>";
672 auto doc = test::BuildXmlDom(xml);
673
674 PostProcessingConfiguration config;
675 bool ok = AndroidSdkTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
676 ASSERT_TRUE(ok);
677
678 ASSERT_EQ(1ul, config.android_sdks.size());
679 ASSERT_EQ(1u, config.android_sdks.count("v19"));
680
681 auto& out = config.android_sdks["v19"];
682 EXPECT_EQ(19, out.target_sdk_version.value());
683 EXPECT_EQ(19, out.min_sdk_version);
684 EXPECT_FALSE(out.max_sdk_version);
685 }
686 }
687
688 TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_InvalidVersion) {
689 static constexpr const char* xml = R"xml(
690 <android-sdk
691 label="v19"
692 minSdkVersion="v19"
693 targetSdkVersion="v24"
694 maxSdkVersion="v25">
695 <manifest>
696 <!--- manifest additions here XSLT? TODO -->
697 </manifest>
698 </android-sdk>)xml";
699
700 auto doc = test::BuildXmlDom(xml);
701
702 PostProcessingConfiguration config;
703 bool ok = AndroidSdkTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
704 ASSERT_FALSE(ok);
705 }
706
707 TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_NonNumeric) {
708 auto doc = test::BuildXmlDom(R"xml(
709 <android-sdk
710 label="Q"
711 minSdkVersion="25"
712 targetSdkVersion="Q"
713 maxSdkVersion="Q">
714 </android-sdk>)xml");
715
716 PostProcessingConfiguration config;
717 ASSERT_TRUE(AndroidSdkTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_));
718 ASSERT_EQ(1ul, config.android_sdks.size());
719 ASSERT_EQ(1u, config.android_sdks.count("Q"));
720
721 AndroidSdk sdk;
722 sdk.min_sdk_version = 25;
723 sdk.target_sdk_version = 10000;
724 sdk.max_sdk_version = 10000;
725 ASSERT_EQ(sdk, config.android_sdks["Q"]);
726 }
727
728 TEST_F(ConfigurationParserTest, GlTextureGroupAction) {
729 static constexpr const char* xml = R"xml(
730 <gl-texture-group label="dxt1" version-code-order="2">
731 <gl-texture name="GL_EXT_texture_compression_dxt1">
732 <texture-path>assets/dxt1/main/*</texture-path>
733 <texture-path>
734 assets/dxt1/test/*
735 </texture-path>
736 </gl-texture>
737 </gl-texture-group>)xml";
738
739 auto doc = test::BuildXmlDom(xml);
740
741 PostProcessingConfiguration config;
742 bool ok = GlTextureGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
743 ASSERT_TRUE(ok);
744
745 EXPECT_THAT(config.gl_texture_groups, SizeIs(1ul));
746 ASSERT_EQ(1u, config.gl_texture_groups.count("dxt1"));
747
748 auto& out = config.gl_texture_groups["dxt1"].entry;
749
750 GlTexture texture{
751 std::string("GL_EXT_texture_compression_dxt1"),
752 {"assets/dxt1/main/*", "assets/dxt1/test/*"}
753 };
754
755 ASSERT_EQ(1ul, out.size());
756 ASSERT_EQ(texture, out[0]);
757 }
758
759 TEST_F(ConfigurationParserTest, DeviceFeatureGroupAction) {
760 static constexpr const char* xml = R"xml(
761 <device-feature-group label="low-latency" version-code-order="2">
762 <supports-feature>android.hardware.audio.low_latency</supports-feature>
763 <supports-feature>
764 android.hardware.audio.pro
765 </supports-feature>
766 </device-feature-group>)xml";
767
768 auto doc = test::BuildXmlDom(xml);
769
770 PostProcessingConfiguration config;
771 bool ok = DeviceFeatureGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
772 ASSERT_TRUE(ok);
773
774 EXPECT_THAT(config.device_feature_groups, SizeIs(1ul));
775 ASSERT_EQ(1u, config.device_feature_groups.count("low-latency"));
776
777 auto& out = config.device_feature_groups["low-latency"].entry;
778
779 DeviceFeature low_latency = "android.hardware.audio.low_latency";
780 DeviceFeature pro = "android.hardware.audio.pro";
781 ASSERT_THAT(out, ElementsAre(low_latency, pro));
782 }
783
784 TEST_F(ConfigurationParserTest, Group_Valid) {
785 Group<int32_t> group;
786 group["item1"].order = 1;
787 group["item2"].order = 2;
788 group["item3"].order = 3;
789 group["item4"].order = 4;
790 group["item5"].order = 5;
791 group["item6"].order = 6;
792
793 EXPECT_TRUE(IsGroupValid(group, "test", &diag_));
794 }
795
796 TEST_F(ConfigurationParserTest, Group_OverlappingOrder) {
797 Group<int32_t> group;
798 group["item1"].order = 1;
799 group["item2"].order = 2;
800 group["item3"].order = 3;
801 group["item4"].order = 2;
802 group["item5"].order = 5;
803 group["item6"].order = 1;
804
805 EXPECT_FALSE(IsGroupValid(group, "test", &diag_));
806 }
807
808 // Artifact name parser test cases.
809
810 TEST(ArtifactTest, Simple) {
811 StdErrDiagnostics diag;
812 ConfiguredArtifact x86;
813 x86.abi_group = {"x86"};
814
815 auto x86_result = x86.ToArtifactName("something.${abi}.apk", "", &diag);
816 ASSERT_TRUE(x86_result);
817 EXPECT_EQ(x86_result.value(), "something.x86.apk");
818
819 ConfiguredArtifact arm;
820 arm.abi_group = {"armeabi-v7a"};
821
822 {
823 auto arm_result = arm.ToArtifactName("app.${abi}.apk", "", &diag);
824 ASSERT_TRUE(arm_result);
825 EXPECT_EQ(arm_result.value(), "app.armeabi-v7a.apk");
826 }
827
828 {
829 auto arm_result = arm.ToArtifactName("app.${abi}.apk", "different_name.apk", &diag);
830 ASSERT_TRUE(arm_result);
831 EXPECT_EQ(arm_result.value(), "app.armeabi-v7a.apk");
832 }
833
834 {
835 auto arm_result = arm.ToArtifactName("${basename}.${abi}.apk", "app.apk", &diag);
836 ASSERT_TRUE(arm_result);
837 EXPECT_EQ(arm_result.value(), "app.armeabi-v7a.apk");
838 }
839
840 {
841 auto arm_result = arm.ToArtifactName("app.${abi}.${ext}", "app.apk", &diag);
842 ASSERT_TRUE(arm_result);
843 EXPECT_EQ(arm_result.value(), "app.armeabi-v7a.apk");
844 }
845 }
846
847 TEST(ArtifactTest, Complex) {
848 StdErrDiagnostics diag;
849 ConfiguredArtifact artifact;
850 artifact.abi_group = {"mips64"};
851 artifact.screen_density_group = {"ldpi"};
852 artifact.device_feature_group = {"df1"};
853 artifact.gl_texture_group = {"glx1"};
854 artifact.locale_group = {"en-AU"};
855 artifact.android_sdk = {"v26"};
856
857 {
858 auto result = artifact.ToArtifactName(
859 "app.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.apk", "", &diag);
860 ASSERT_TRUE(result);
861 EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk");
862 }
863
864 {
865 auto result = artifact.ToArtifactName(
866 "app.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.apk", "app.apk", &diag);
867 ASSERT_TRUE(result);
868 EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk");
869 }
870
871 {
872 auto result = artifact.ToArtifactName(
873 "${basename}.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.apk", "app.apk", &diag);
874 ASSERT_TRUE(result);
875 EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk");
876 }
877
878 {
879 auto result = artifact.ToArtifactName(
880 "app.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.${ext}", "app.apk", &diag);
881 ASSERT_TRUE(result);
882 EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk");
883 }
884
885 {
886 auto result = artifact.ToArtifactName(
887 "${basename}.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}", "app.apk", &diag);
888 ASSERT_TRUE(result);
889 EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk");
890 }
891 }
892
893 TEST(ArtifactTest, Missing) {
894 StdErrDiagnostics diag;
895 ConfiguredArtifact x86;
896 x86.abi_group = {"x86"};
897
898 EXPECT_FALSE(x86.ToArtifactName("something.${density}.apk", "", &diag));
899 EXPECT_FALSE(x86.ToArtifactName("something.apk", "", &diag));
900 EXPECT_FALSE(x86.ToArtifactName("something.${density}.apk", "something.apk", &diag));
901 EXPECT_FALSE(x86.ToArtifactName("something.apk", "something.apk", &diag));
902 }
903
904 TEST(ArtifactTest, Empty) {
905 StdErrDiagnostics diag;
906 ConfiguredArtifact artifact;
907
908 EXPECT_FALSE(artifact.ToArtifactName("something.${density}.apk", "", &diag));
909 EXPECT_TRUE(artifact.ToArtifactName("something.apk", "", &diag));
910 EXPECT_FALSE(artifact.ToArtifactName("something.${density}.apk", "something.apk", &diag));
911 EXPECT_TRUE(artifact.ToArtifactName("something.apk", "something.apk", &diag));
912 }
913
914 TEST(ArtifactTest, Repeated) {
915 StdErrDiagnostics diag;
916 ConfiguredArtifact artifact;
917 artifact.screen_density_group = {"mdpi"};
918
919 ASSERT_TRUE(artifact.ToArtifactName("something.${density}.apk", "", &diag));
920 EXPECT_FALSE(artifact.ToArtifactName("something.${density}.${density}.apk", "", &diag));
921 ASSERT_TRUE(artifact.ToArtifactName("something.${density}.apk", "something.apk", &diag));
922 }
923
924 TEST(ArtifactTest, Nesting) {
925 StdErrDiagnostics diag;
926 ConfiguredArtifact x86;
927 x86.abi_group = {"x86"};
928
929 EXPECT_FALSE(x86.ToArtifactName("something.${abi${density}}.apk", "", &diag));
930
931 const Maybe<std::string>& name = x86.ToArtifactName("something.${abi${abi}}.apk", "", &diag);
932 ASSERT_TRUE(name);
933 EXPECT_EQ(name.value(), "something.${abix86}.apk");
934 }
935
936 TEST(ArtifactTest, Recursive) {
937 StdErrDiagnostics diag;
938 ConfiguredArtifact artifact;
939 artifact.device_feature_group = {"${gl}"};
940 artifact.gl_texture_group = {"glx1"};
941
942 EXPECT_FALSE(artifact.ToArtifactName("app.${feature}.${gl}.apk", "", &diag));
943
944 artifact.device_feature_group = {"df1"};
945 artifact.gl_texture_group = {"${feature}"};
946 {
947 const auto& result = artifact.ToArtifactName("app.${feature}.${gl}.apk", "", &diag);
948 ASSERT_TRUE(result);
949 EXPECT_EQ(result.value(), "app.df1.${feature}.apk");
950 }
951
952 // This is an invalid case, but should be the only possible case due to the ordering of
953 // replacement.
954 artifact.device_feature_group = {"${gl}"};
955 artifact.gl_texture_group = {"glx1"};
956 {
957 const auto& result = artifact.ToArtifactName("app.${feature}.apk", "", &diag);
958 ASSERT_TRUE(result);
959 EXPECT_EQ(result.value(), "app.glx1.apk");
960 }
961 }
962
963 } // namespace
964 } // namespace handler
965 } // namespace configuration
966 } // namespace aapt
967