1 /* 2 * Copyright (C) 2015 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 "link/TableMerger.h" 18 19 #include "filter/ConfigFilter.h" 20 #include "io/FileSystem.h" 21 #include "test/Test.h" 22 23 using ::aapt::test::ValueEq; 24 using ::testing::Contains; 25 using ::testing::Eq; 26 using ::testing::Field; 27 using ::testing::NotNull; 28 using ::testing::Pointee; 29 using ::testing::StrEq; 30 using ::testing::UnorderedElementsAreArray; 31 32 namespace aapt { 33 34 struct TableMergerTest : public ::testing::Test { 35 std::unique_ptr<IAaptContext> context_; 36 37 void SetUp() override { 38 context_ = 39 test::ContextBuilder() 40 // We are compiling this package. 41 .SetCompilationPackage("com.app.a") 42 43 // Merge all packages that have this package ID. 44 .SetPackageId(0x7f) 45 46 // Mangle all packages that do not have this package name. 47 .SetNameManglerPolicy(NameManglerPolicy{"com.app.a", {"com.app.b"}}) 48 49 .Build(); 50 } 51 }; 52 53 TEST_F(TableMergerTest, SimpleMerge) { 54 std::unique_ptr<ResourceTable> table_a = 55 test::ResourceTableBuilder() 56 .SetPackageId("com.app.a", 0x7f) 57 .AddReference("com.app.a:id/foo", "com.app.a:id/bar") 58 .AddReference("com.app.a:id/bar", "com.app.b:id/foo") 59 .AddValue( 60 "com.app.a:styleable/view", 61 test::StyleableBuilder().AddItem("com.app.b:id/foo").Build()) 62 .Build(); 63 64 std::unique_ptr<ResourceTable> table_b = test::ResourceTableBuilder() 65 .SetPackageId("com.app.b", 0x7f) 66 .AddSimple("com.app.b:id/foo") 67 .Build(); 68 69 ResourceTable final_table; 70 TableMerger merger(context_.get(), &final_table, TableMergerOptions{}); 71 72 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); 73 ASSERT_TRUE(merger.MergeAndMangle({}, "com.app.b", table_b.get())); 74 75 EXPECT_TRUE(merger.merged_packages().count("com.app.b") != 0); 76 77 // Entries from com.app.a should not be mangled. 78 EXPECT_TRUE(final_table.FindResource(test::ParseNameOrDie("com.app.a:id/foo"))); 79 EXPECT_TRUE(final_table.FindResource(test::ParseNameOrDie("com.app.a:id/bar"))); 80 EXPECT_TRUE(final_table.FindResource(test::ParseNameOrDie("com.app.a:styleable/view"))); 81 82 // The unmangled name should not be present. 83 EXPECT_FALSE(final_table.FindResource(test::ParseNameOrDie("com.app.b:id/foo"))); 84 85 // Look for the mangled name. 86 EXPECT_TRUE(final_table.FindResource(test::ParseNameOrDie("com.app.a:id/com.app.b$foo"))); 87 } 88 89 TEST_F(TableMergerTest, MergeFile) { 90 ResourceTable final_table; 91 TableMergerOptions options; 92 options.auto_add_overlay = false; 93 TableMerger merger(context_.get(), &final_table, options); 94 95 ResourceFile file_desc; 96 file_desc.config = test::ParseConfigOrDie("hdpi-v4"); 97 file_desc.name = test::ParseNameOrDie("layout/main"); 98 file_desc.source = Source("res/layout-hdpi/main.xml"); 99 test::TestFile test_file("path/to/res/layout-hdpi/main.xml.flat"); 100 101 ASSERT_TRUE(merger.MergeFile(file_desc, false /*overlay*/, &test_file)); 102 103 FileReference* file = test::GetValueForConfig<FileReference>( 104 &final_table, "com.app.a:layout/main", test::ParseConfigOrDie("hdpi-v4")); 105 ASSERT_THAT(file, NotNull()); 106 EXPECT_EQ(std::string("res/layout-hdpi-v4/main.xml"), *file->path); 107 } 108 109 TEST_F(TableMergerTest, MergeFileOverlay) { 110 ResourceTable final_table; 111 TableMergerOptions options; 112 options.auto_add_overlay = false; 113 TableMerger merger(context_.get(), &final_table, options); 114 115 ResourceFile file_desc; 116 file_desc.name = test::ParseNameOrDie("xml/foo"); 117 test::TestFile file_a("path/to/fileA.xml.flat"); 118 test::TestFile file_b("path/to/fileB.xml.flat"); 119 120 ASSERT_TRUE(merger.MergeFile(file_desc, false /*overlay*/, &file_a)); 121 ASSERT_TRUE(merger.MergeFile(file_desc, true /*overlay*/, &file_b)); 122 } 123 124 TEST_F(TableMergerTest, MergeFileReferences) { 125 test::TestFile file_a("res/xml/file.xml"); 126 test::TestFile file_b("res/xml/file.xml"); 127 128 std::unique_ptr<ResourceTable> table_a = 129 test::ResourceTableBuilder() 130 .SetPackageId("com.app.a", 0x7f) 131 .AddFileReference("com.app.a:xml/file", "res/xml/file.xml", &file_a) 132 .Build(); 133 std::unique_ptr<ResourceTable> table_b = 134 test::ResourceTableBuilder() 135 .SetPackageId("com.app.b", 0x7f) 136 .AddFileReference("com.app.b:xml/file", "res/xml/file.xml", &file_b) 137 .Build(); 138 139 ResourceTable final_table; 140 TableMerger merger(context_.get(), &final_table, TableMergerOptions{}); 141 142 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); 143 ASSERT_TRUE(merger.MergeAndMangle({}, "com.app.b", table_b.get())); 144 145 FileReference* f = test::GetValue<FileReference>(&final_table, "com.app.a:xml/file"); 146 ASSERT_THAT(f, NotNull()); 147 EXPECT_THAT(*f->path, StrEq("res/xml/file.xml")); 148 EXPECT_THAT(f->file, Eq(&file_a)); 149 150 f = test::GetValue<FileReference>(&final_table, "com.app.a:xml/com.app.b$file"); 151 ASSERT_THAT(f, NotNull()); 152 EXPECT_THAT(*f->path, StrEq("res/xml/com.app.b$file.xml")); 153 EXPECT_THAT(f->file, Eq(&file_b)); 154 } 155 156 TEST_F(TableMergerTest, OverrideResourceWithOverlay) { 157 std::unique_ptr<ResourceTable> base = 158 test::ResourceTableBuilder() 159 .SetPackageId("", 0x00) 160 .AddValue("bool/foo", ResourceUtils::TryParseBool("true")) 161 .Build(); 162 std::unique_ptr<ResourceTable> overlay = 163 test::ResourceTableBuilder() 164 .SetPackageId("", 0x00) 165 .AddValue("bool/foo", ResourceUtils::TryParseBool("false")) 166 .Build(); 167 168 ResourceTable final_table; 169 TableMergerOptions options; 170 options.auto_add_overlay = false; 171 TableMerger merger(context_.get(), &final_table, options); 172 173 ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/)); 174 ASSERT_TRUE(merger.Merge({}, overlay.get(), true /*overlay*/)); 175 176 BinaryPrimitive* foo = test::GetValue<BinaryPrimitive>(&final_table, "com.app.a:bool/foo"); 177 ASSERT_THAT(foo, 178 Pointee(Field(&BinaryPrimitive::value, Field(&android::Res_value::data, Eq(0u))))); 179 } 180 181 TEST_F(TableMergerTest, DoNotOverrideResourceComment) { 182 std::unique_ptr<Value> foo_original = ResourceUtils::TryParseBool("true"); 183 foo_original->SetComment(android::StringPiece("Original foo comment")); 184 std::unique_ptr<Value> bar_original = ResourceUtils::TryParseBool("true"); 185 186 std::unique_ptr<Value> foo_overlay = ResourceUtils::TryParseBool("false"); 187 foo_overlay->SetComment(android::StringPiece("Overlay foo comment")); 188 std::unique_ptr<Value> bar_overlay = ResourceUtils::TryParseBool("false"); 189 bar_overlay->SetComment(android::StringPiece("Overlay bar comment")); 190 std::unique_ptr<Value> baz_overlay = ResourceUtils::TryParseBool("false"); 191 baz_overlay->SetComment(android::StringPiece("Overlay baz comment")); 192 193 std::unique_ptr<ResourceTable> base = 194 test::ResourceTableBuilder() 195 .SetPackageId("", 0x00) 196 .AddValue("bool/foo", std::move(foo_original)) 197 .AddValue("bool/bar", std::move(bar_original)) 198 .Build(); 199 200 std::unique_ptr<ResourceTable> overlay = 201 test::ResourceTableBuilder() 202 .SetPackageId("", 0x00) 203 .AddValue("bool/foo", std::move(foo_overlay)) 204 .AddValue("bool/bar", std::move(bar_overlay)) 205 .AddValue("bool/baz", std::move(baz_overlay)) 206 .Build(); 207 208 ResourceTable final_table; 209 TableMergerOptions options; 210 options.auto_add_overlay = true; 211 TableMerger merger(context_.get(), &final_table, options); 212 213 ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/)); 214 ASSERT_TRUE(merger.Merge({}, overlay.get(), true /*overlay*/)); 215 216 BinaryPrimitive* foo = test::GetValue<BinaryPrimitive>(&final_table, "com.app.a:bool/foo"); 217 EXPECT_THAT(foo, Pointee(Property(&BinaryPrimitive::GetComment, StrEq("Original foo comment")))); 218 BinaryPrimitive* bar = test::GetValue<BinaryPrimitive>(&final_table, "com.app.a:bool/bar"); 219 EXPECT_THAT(bar, Pointee(Property(&BinaryPrimitive::GetComment, StrEq("")))); 220 BinaryPrimitive* baz = test::GetValue<BinaryPrimitive>(&final_table, "com.app.a:bool/baz"); 221 EXPECT_THAT(baz, Pointee(Property(&BinaryPrimitive::GetComment, StrEq("Overlay baz comment")))); 222 } 223 224 TEST_F(TableMergerTest, OverrideSameResourceIdsWithOverlay) { 225 std::unique_ptr<ResourceTable> base = 226 test::ResourceTableBuilder() 227 .SetPackageId("", 0x7f) 228 .SetSymbolState("bool/foo", ResourceId(0x7f, 0x01, 0x0001), Visibility::Level::kPublic) 229 .Build(); 230 std::unique_ptr<ResourceTable> overlay = 231 test::ResourceTableBuilder() 232 .SetPackageId("", 0x7f) 233 .SetSymbolState("bool/foo", ResourceId(0x7f, 0x01, 0x0001), Visibility::Level::kPublic) 234 .Build(); 235 236 ResourceTable final_table; 237 TableMergerOptions options; 238 options.auto_add_overlay = false; 239 TableMerger merger(context_.get(), &final_table, options); 240 241 ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/)); 242 ASSERT_TRUE(merger.Merge({}, overlay.get(), true /*overlay*/)); 243 } 244 245 TEST_F(TableMergerTest, FailToOverrideConflictingTypeIdsWithOverlay) { 246 std::unique_ptr<ResourceTable> base = 247 test::ResourceTableBuilder() 248 .SetPackageId("", 0x7f) 249 .SetSymbolState("bool/foo", ResourceId(0x7f, 0x01, 0x0001), Visibility::Level::kPublic) 250 .Build(); 251 std::unique_ptr<ResourceTable> overlay = 252 test::ResourceTableBuilder() 253 .SetPackageId("", 0x7f) 254 .SetSymbolState("bool/foo", ResourceId(0x7f, 0x02, 0x0001), Visibility::Level::kPublic) 255 .Build(); 256 257 ResourceTable final_table; 258 TableMergerOptions options; 259 options.auto_add_overlay = false; 260 TableMerger merger(context_.get(), &final_table, options); 261 262 ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/)); 263 ASSERT_FALSE(merger.Merge({}, overlay.get(), true /*overlay*/)); 264 } 265 266 TEST_F(TableMergerTest, FailToOverrideConflictingEntryIdsWithOverlay) { 267 std::unique_ptr<ResourceTable> base = 268 test::ResourceTableBuilder() 269 .SetPackageId("", 0x7f) 270 .SetSymbolState("bool/foo", ResourceId(0x7f, 0x01, 0x0001), Visibility::Level::kPublic) 271 .Build(); 272 std::unique_ptr<ResourceTable> overlay = 273 test::ResourceTableBuilder() 274 .SetPackageId("", 0x7f) 275 .SetSymbolState("bool/foo", ResourceId(0x7f, 0x01, 0x0002), Visibility::Level::kPublic) 276 .Build(); 277 278 ResourceTable final_table; 279 TableMergerOptions options; 280 options.auto_add_overlay = false; 281 TableMerger merger(context_.get(), &final_table, options); 282 283 ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/)); 284 ASSERT_FALSE(merger.Merge({}, overlay.get(), true /*overlay*/)); 285 } 286 287 TEST_F(TableMergerTest, FailConflictingVisibility) { 288 std::unique_ptr<ResourceTable> base = 289 test::ResourceTableBuilder() 290 .SetPackageId("", 0x7f) 291 .SetSymbolState("bool/foo", ResourceId(0x7f, 0x01, 0x0001), Visibility::Level::kPublic) 292 .Build(); 293 std::unique_ptr<ResourceTable> overlay = 294 test::ResourceTableBuilder() 295 .SetPackageId("", 0x7f) 296 .SetSymbolState("bool/foo", ResourceId(0x7f, 0x01, 0x0001), Visibility::Level::kPrivate) 297 .Build(); 298 299 // It should fail if the "--strict-visibility" flag is set. 300 ResourceTable final_table; 301 TableMergerOptions options; 302 options.auto_add_overlay = false; 303 options.strict_visibility = true; 304 TableMerger merger(context_.get(), &final_table, options); 305 306 ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/)); 307 ASSERT_FALSE(merger.Merge({}, overlay.get(), true /*overlay*/)); 308 309 // But it should still pass if the flag is not set. 310 ResourceTable final_table2; 311 options.strict_visibility = false; 312 TableMerger merger2(context_.get(), &final_table2, options); 313 314 ASSERT_TRUE(merger2.Merge({}, base.get(), false /*overlay*/)); 315 ASSERT_TRUE(merger2.Merge({}, overlay.get(), true /*overlay*/)); 316 } 317 318 TEST_F(TableMergerTest, MergeAddResourceFromOverlay) { 319 std::unique_ptr<ResourceTable> table_a = 320 test::ResourceTableBuilder().SetPackageId("", 0x7f).Build(); 321 std::unique_ptr<ResourceTable> table_b = 322 test::ResourceTableBuilder() 323 .SetPackageId("", 0x7f) 324 .SetSymbolState("bool/foo", {}, Visibility::Level::kUndefined, true /*allow new overlay*/) 325 .AddValue("bool/foo", ResourceUtils::TryParseBool("true")) 326 .Build(); 327 328 ResourceTable final_table; 329 TableMergerOptions options; 330 options.auto_add_overlay = false; 331 TableMerger merger(context_.get(), &final_table, options); 332 333 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); 334 ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/)); 335 } 336 337 TEST_F(TableMergerTest, MergeAddResourceFromOverlayWithAutoAddOverlay) { 338 std::unique_ptr<ResourceTable> table_a = 339 test::ResourceTableBuilder().SetPackageId("", 0x7f).Build(); 340 std::unique_ptr<ResourceTable> table_b = 341 test::ResourceTableBuilder() 342 .SetPackageId("", 0x7f) 343 .AddValue("bool/foo", ResourceUtils::TryParseBool("true")) 344 .Build(); 345 346 ResourceTable final_table; 347 TableMergerOptions options; 348 options.auto_add_overlay = true; 349 TableMerger merger(context_.get(), &final_table, options); 350 351 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); 352 ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/)); 353 } 354 355 TEST_F(TableMergerTest, OverrideAttributeSameFormatsWithOverlay) { 356 std::unique_ptr<ResourceTable> base = 357 test::ResourceTableBuilder() 358 .SetPackageId("", 0x7f) 359 .AddValue("attr/foo", test::AttributeBuilder() 360 .SetTypeMask(android::ResTable_map::TYPE_STRING) 361 .SetWeak(false) 362 .Build()) 363 .Build(); 364 365 std::unique_ptr<ResourceTable> overlay = 366 test::ResourceTableBuilder() 367 .SetPackageId("", 0x7f) 368 .AddValue("attr/foo", test::AttributeBuilder() 369 .SetTypeMask(android::ResTable_map::TYPE_STRING) 370 .SetWeak(false) 371 .Build()) 372 .Build(); 373 374 ResourceTable final_table; 375 TableMergerOptions options; 376 options.auto_add_overlay = false; 377 TableMerger merger(context_.get(), &final_table, options); 378 379 ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/)); 380 ASSERT_TRUE(merger.Merge({}, overlay.get(), true /*overlay*/)); 381 } 382 383 TEST_F(TableMergerTest, FailToOverrideConflictingAttributeFormatsWithOverlay) { 384 std::unique_ptr<ResourceTable> base = 385 test::ResourceTableBuilder() 386 .SetPackageId("", 0x7f) 387 .AddValue("attr/foo", test::AttributeBuilder() 388 .SetTypeMask(android::ResTable_map::TYPE_ANY) 389 .SetWeak(false) 390 .Build()) 391 .Build(); 392 393 std::unique_ptr<ResourceTable> overlay = 394 test::ResourceTableBuilder() 395 .SetPackageId("", 0x7f) 396 .AddValue("attr/foo", test::AttributeBuilder() 397 .SetTypeMask(android::ResTable_map::TYPE_STRING) 398 .SetWeak(false) 399 .Build()) 400 .Build(); 401 402 ResourceTable final_table; 403 TableMergerOptions options; 404 options.auto_add_overlay = false; 405 TableMerger merger(context_.get(), &final_table, options); 406 407 ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/)); 408 ASSERT_FALSE(merger.Merge({}, overlay.get(), true /*overlay*/)); 409 } 410 411 TEST_F(TableMergerTest, FailToMergeNewResourceWithoutAutoAddOverlay) { 412 std::unique_ptr<ResourceTable> table_a = 413 test::ResourceTableBuilder().SetPackageId("", 0x7f).Build(); 414 std::unique_ptr<ResourceTable> table_b = 415 test::ResourceTableBuilder() 416 .SetPackageId("", 0x7f) 417 .AddValue("bool/foo", ResourceUtils::TryParseBool("true")) 418 .Build(); 419 420 ResourceTable final_table; 421 TableMergerOptions options; 422 options.auto_add_overlay = false; 423 TableMerger merger(context_.get(), &final_table, options); 424 425 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); 426 ASSERT_FALSE(merger.Merge({}, table_b.get(), true /*overlay*/)); 427 } 428 429 TEST_F(TableMergerTest, OverlaidStyleablesAndStylesShouldBeMerged) { 430 std::unique_ptr<ResourceTable> table_a = 431 test::ResourceTableBuilder() 432 .SetPackageId("com.app.a", 0x7f) 433 .AddValue("com.app.a:styleable/Foo", 434 test::StyleableBuilder() 435 .AddItem("com.app.a:attr/bar") 436 .AddItem("com.app.a:attr/foo", ResourceId(0x01010000)) 437 .Build()) 438 .AddValue("com.app.a:style/Theme", 439 test::StyleBuilder() 440 .SetParent("com.app.a:style/Parent") 441 .AddItem("com.app.a:attr/bar", util::make_unique<Id>()) 442 .AddItem("com.app.a:attr/foo", ResourceUtils::MakeBool(false)) 443 .Build()) 444 .Build(); 445 446 std::unique_ptr<ResourceTable> table_b = 447 test::ResourceTableBuilder() 448 .SetPackageId("com.app.a", 0x7f) 449 .AddValue("com.app.a:styleable/Foo", test::StyleableBuilder() 450 .AddItem("com.app.a:attr/bat") 451 .AddItem("com.app.a:attr/foo") 452 .Build()) 453 .AddValue("com.app.a:style/Theme", 454 test::StyleBuilder() 455 .SetParent("com.app.a:style/OverlayParent") 456 .AddItem("com.app.a:attr/bat", util::make_unique<Id>()) 457 .AddItem("com.app.a:attr/foo", ResourceId(0x01010000), 458 ResourceUtils::MakeBool(true)) 459 .Build()) 460 .Build(); 461 462 ResourceTable final_table; 463 TableMergerOptions options; 464 options.auto_add_overlay = true; 465 TableMerger merger(context_.get(), &final_table, options); 466 467 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); 468 ASSERT_TRUE(merger.Merge({}, table_b.get(), true /*overlay*/)); 469 470 Styleable* styleable = test::GetValue<Styleable>(&final_table, "com.app.a:styleable/Foo"); 471 ASSERT_THAT(styleable, NotNull()); 472 473 std::vector<Reference> expected_refs = { 474 Reference(test::ParseNameOrDie("com.app.a:attr/bar")), 475 Reference(test::ParseNameOrDie("com.app.a:attr/bat")), 476 Reference(test::ParseNameOrDie("com.app.a:attr/foo"), ResourceId(0x01010000)), 477 }; 478 EXPECT_THAT(styleable->entries, UnorderedElementsAreArray(expected_refs)); 479 480 Style* style = test::GetValue<Style>(&final_table, "com.app.a:style/Theme"); 481 ASSERT_THAT(style, NotNull()); 482 483 std::vector<Reference> extracted_refs; 484 for (const auto& entry : style->entries) { 485 extracted_refs.push_back(entry.key); 486 } 487 EXPECT_THAT(extracted_refs, UnorderedElementsAreArray(expected_refs)); 488 489 const auto expected = ResourceUtils::MakeBool(true); 490 EXPECT_THAT(style->entries, Contains(Field(&Style::Entry::value, Pointee(ValueEq(*expected))))); 491 EXPECT_THAT(style->parent, 492 Eq(make_value(Reference(test::ParseNameOrDie("com.app.a:style/OverlayParent"))))); 493 } 494 495 TEST_F(TableMergerTest, SetOverlayable) { 496 auto overlayable = std::make_shared<Overlayable>("CustomizableResources", 497 "overlay://customization"); 498 OverlayableItem overlayable_item(overlayable); 499 overlayable_item.policies |= OverlayableItem::Policy::kProduct; 500 overlayable_item.policies |= OverlayableItem::Policy::kVendor; 501 502 std::unique_ptr<ResourceTable> table_a = 503 test::ResourceTableBuilder() 504 .SetPackageId("com.app.a", 0x7f) 505 .SetOverlayable("bool/foo", overlayable_item) 506 .Build(); 507 508 std::unique_ptr<ResourceTable> table_b = 509 test::ResourceTableBuilder() 510 .SetPackageId("com.app.a", 0x7f) 511 .AddSimple("bool/foo") 512 .Build(); 513 514 ResourceTable final_table; 515 TableMergerOptions options; 516 options.auto_add_overlay = true; 517 TableMerger merger(context_.get(), &final_table, options); 518 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); 519 ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/)); 520 521 const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo"); 522 Maybe<ResourceTable::SearchResult> search_result = final_table.FindResource(name); 523 ASSERT_TRUE(search_result); 524 ASSERT_TRUE(search_result.value().entry->overlayable_item); 525 OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value(); 526 EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources")); 527 EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization")); 528 EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct 529 | OverlayableItem::Policy::kVendor)); 530 } 531 532 TEST_F(TableMergerTest, SetOverlayableLater) { 533 auto overlayable = std::make_shared<Overlayable>("CustomizableResources", 534 "overlay://customization"); 535 std::unique_ptr<ResourceTable> table_a = 536 test::ResourceTableBuilder() 537 .SetPackageId("com.app.a", 0x7f) 538 .AddSimple("bool/foo") 539 .Build(); 540 541 OverlayableItem overlayable_item(overlayable); 542 overlayable_item.policies |= OverlayableItem::Policy::kPublic; 543 overlayable_item.policies |= OverlayableItem::Policy::kSystem; 544 std::unique_ptr<ResourceTable> table_b = 545 test::ResourceTableBuilder() 546 .SetPackageId("com.app.a", 0x7f) 547 .SetOverlayable("bool/foo", overlayable_item) 548 .Build(); 549 550 ResourceTable final_table; 551 TableMergerOptions options; 552 options.auto_add_overlay = true; 553 TableMerger merger(context_.get(), &final_table, options); 554 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); 555 ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/)); 556 557 const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo"); 558 Maybe<ResourceTable::SearchResult> search_result = final_table.FindResource(name); 559 ASSERT_TRUE(search_result); 560 ASSERT_TRUE(search_result.value().entry->overlayable_item); 561 OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value(); 562 EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources")); 563 EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization")); 564 EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic 565 | OverlayableItem::Policy::kSystem)); 566 } 567 568 TEST_F(TableMergerTest, SameResourceDifferentNameFail) { 569 auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources", 570 "overlay://customization"); 571 OverlayableItem overlayable_item_first(overlayable_first); 572 overlayable_item_first.policies |= OverlayableItem::Policy::kProduct; 573 std::unique_ptr<ResourceTable> table_a = 574 test::ResourceTableBuilder() 575 .SetPackageId("com.app.a", 0x7f) 576 .SetOverlayable("bool/foo", overlayable_item_first) 577 .Build(); 578 579 auto overlayable_second = std::make_shared<Overlayable>("ThemeResources", 580 "overlay://customization"); 581 OverlayableItem overlayable_item_second(overlayable_second); 582 overlayable_item_second.policies |= OverlayableItem::Policy::kProduct; 583 std::unique_ptr<ResourceTable> table_b = 584 test::ResourceTableBuilder() 585 .SetPackageId("com.app.a", 0x7f) 586 .SetOverlayable("bool/foo", overlayable_item_second) 587 .Build(); 588 589 ResourceTable final_table; 590 TableMergerOptions options; 591 options.auto_add_overlay = true; 592 TableMerger merger(context_.get(), &final_table, options); 593 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); 594 ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/)); 595 } 596 597 TEST_F(TableMergerTest, SameResourceDifferentActorFail) { 598 auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources", 599 "overlay://customization"); 600 OverlayableItem overlayable_item_first(overlayable_first); 601 overlayable_item_first.policies |= OverlayableItem::Policy::kProduct; 602 std::unique_ptr<ResourceTable> table_a = 603 test::ResourceTableBuilder() 604 .SetPackageId("com.app.a", 0x7f) 605 .SetOverlayable("bool/foo", overlayable_item_first) 606 .Build(); 607 608 auto overlayable_second = std::make_shared<Overlayable>("CustomizableResources", 609 "overlay://theme"); 610 OverlayableItem overlayable_item_second(overlayable_second); 611 overlayable_item_second.policies |= OverlayableItem::Policy::kProduct; 612 std::unique_ptr<ResourceTable> table_b = 613 test::ResourceTableBuilder() 614 .SetPackageId("com.app.a", 0x7f) 615 .SetOverlayable("bool/foo", overlayable_item_second) 616 .Build(); 617 618 ResourceTable final_table; 619 TableMergerOptions options; 620 options.auto_add_overlay = true; 621 TableMerger merger(context_.get(), &final_table, options); 622 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); 623 ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/)); 624 } 625 626 TEST_F(TableMergerTest, SameResourceDifferentPoliciesFail) { 627 auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources", 628 "overlay://customization"); 629 OverlayableItem overlayable_item_first(overlayable_first); 630 overlayable_item_first.policies |= OverlayableItem::Policy::kProduct; 631 std::unique_ptr<ResourceTable> table_a = 632 test::ResourceTableBuilder() 633 .SetPackageId("com.app.a", 0x7f) 634 .SetOverlayable("bool/foo", overlayable_item_first) 635 .Build(); 636 637 auto overlayable_second = std::make_shared<Overlayable>("CustomizableResources", 638 "overlay://customization"); 639 OverlayableItem overlayable_item_second(overlayable_second); 640 overlayable_item_second.policies |= OverlayableItem::Policy::kSignature; 641 std::unique_ptr<ResourceTable> table_b = 642 test::ResourceTableBuilder() 643 .SetPackageId("com.app.a", 0x7f) 644 .SetOverlayable("bool/foo", overlayable_item_second) 645 .Build(); 646 647 ResourceTable final_table; 648 TableMergerOptions options; 649 options.auto_add_overlay = true; 650 TableMerger merger(context_.get(), &final_table, options); 651 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); 652 ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/)); 653 } 654 655 TEST_F(TableMergerTest, SameResourceSameOverlayable) { 656 auto overlayable = std::make_shared<Overlayable>("CustomizableResources", 657 "overlay://customization"); 658 659 OverlayableItem overlayable_item_first(overlayable); 660 overlayable_item_first.policies |= OverlayableItem::Policy::kProduct; 661 std::unique_ptr<ResourceTable> table_a = 662 test::ResourceTableBuilder() 663 .SetPackageId("com.app.a", 0x7f) 664 .SetOverlayable("bool/foo", overlayable_item_first) 665 .Build(); 666 667 OverlayableItem overlayable_item_second(overlayable); 668 overlayable_item_second.policies |= OverlayableItem::Policy::kProduct; 669 std::unique_ptr<ResourceTable> table_b = 670 test::ResourceTableBuilder() 671 .SetPackageId("com.app.a", 0x7f) 672 .SetOverlayable("bool/foo", overlayable_item_second) 673 .Build(); 674 675 ResourceTable final_table; 676 TableMergerOptions options; 677 options.auto_add_overlay = true; 678 TableMerger merger(context_.get(), &final_table, options); 679 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); 680 ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/)); 681 } 682 683 } // namespace aapt 684