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