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