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
29namespace aapt {
30
31namespace configuration {
32void 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
38bool 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
46std::ostream& operator<<(std::ostream& out, const Maybe<std::string>& value) {
47  PrintTo(value, &out);
48  return out;
49}
50
51void 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
60namespace handler {
61
62namespace {
63
64using ::aapt::configuration::Abi;
65using ::aapt::configuration::AndroidManifest;
66using ::aapt::configuration::AndroidSdk;
67using ::aapt::configuration::ConfiguredArtifact;
68using ::aapt::configuration::DeviceFeature;
69using ::aapt::configuration::ExtractConfiguration;
70using ::aapt::configuration::GlTexture;
71using ::aapt::configuration::Locale;
72using ::aapt::configuration::PostProcessingConfiguration;
73using ::aapt::xml::Element;
74using ::aapt::xml::NodeCast;
75using ::android::ResTable_config;
76using ::android::base::StringPrintf;
77using ::testing::ElementsAre;
78using ::testing::Eq;
79using ::testing::SizeIs;
80using ::testing::StrEq;
81
82constexpr 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
172class ConfigurationParserTest : public ConfigurationParser, public ::testing::Test {
173 public:
174  ConfigurationParserTest() : ConfigurationParser("", "config.xml") {
175  }
176
177 protected:
178  StdErrDiagnostics diag_;
179};
180
181TEST_F(ConfigurationParserTest, ForPath_NoFile) {
182  auto result = ConfigurationParser::ForPath("./does_not_exist.xml");
183  EXPECT_FALSE(result);
184}
185
186TEST_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
212TEST_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
256TEST_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
350TEST_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
358TEST_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
383TEST_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
399TEST_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
423TEST_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
441TEST_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
451TEST_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
461TEST_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
491TEST_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
512TEST_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
522TEST_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
532TEST_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
560TEST_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
580TEST_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
590TEST_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
600TEST_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
631TEST_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
686TEST_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
705TEST_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
737TEST_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
768TEST_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
793TEST_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
805TEST_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
819TEST(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
856TEST(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
902TEST(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
913TEST(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
923TEST(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
933TEST(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
945TEST(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