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