Home | History | Annotate | Download | only in link
      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