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