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