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 namespace aapt {
     30 
     31 namespace configuration {
     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 
     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 
     46 std::ostream& operator<<(std::ostream& out, const Maybe<std::string>& value) {
     47   PrintTo(value, &out);
     48   return out;
     49 }
     50 
     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:
    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