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