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 = 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,
413 Eq(make_value(Reference(test::ParseNameOrDie("com.app.a:style/OverlayParent")))));
414 }
415
TEST_F(TableMergerTest,OverrideStyleInsteadOfOverlaying)416 TEST_F(TableMergerTest, OverrideStyleInsteadOfOverlaying) {
417 std::unique_ptr<ResourceTable> table_a =
418 test::ResourceTableBuilder()
419 .AddValue(
420 "com.app.a:styleable/MyWidget",
421 test::StyleableBuilder().AddItem("com.app.a:attr/foo", ResourceId(0x1234)).Build())
422 .AddValue("com.app.a:style/Theme",
423 test::StyleBuilder()
424 .AddItem("com.app.a:attr/foo", ResourceUtils::MakeBool(false))
425 .Build())
426 .Build();
427 std::unique_ptr<ResourceTable> table_b =
428 test::ResourceTableBuilder()
429 .AddValue(
430 "com.app.a:styleable/MyWidget",
431 test::StyleableBuilder().AddItem("com.app.a:attr/bar", ResourceId(0x5678)).Build())
432 .AddValue(
433 "com.app.a:style/Theme",
434 test::StyleBuilder().AddItem("com.app.a:attr/bat", util::make_unique<Id>()).Build())
435 .Build();
436
437 ResourceTable final_table;
438 TableMergerOptions options;
439 options.auto_add_overlay = true;
440 options.override_styles_instead_of_overlaying = true;
441 TableMerger merger(context_.get(), &final_table, options);
442 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
443 ASSERT_TRUE(merger.Merge({}, table_b.get(), true /*overlay*/));
444
445 // Styleables are always overlaid
446 std::unique_ptr<Styleable> expected_styleable = test::StyleableBuilder()
447 // The merged Styleable has its entries ordered by name.
448 .AddItem("com.app.a:attr/bar", ResourceId(0x5678))
449 .AddItem("com.app.a:attr/foo", ResourceId(0x1234))
450 .Build();
451 const Styleable* actual_styleable =
452 test::GetValue<Styleable>(&final_table, "com.app.a:styleable/MyWidget");
453 ASSERT_NE(actual_styleable, nullptr);
454 EXPECT_TRUE(actual_styleable->Equals(expected_styleable.get()));
455 // Style should be overridden
456 const Style* actual_style = test::GetValue<Style>(&final_table, "com.app.a:style/Theme");
457 ASSERT_NE(actual_style, nullptr);
458 EXPECT_TRUE(actual_style->Equals(test::GetValue<Style>(table_b.get(), "com.app.a:style/Theme")));
459 }
460
TEST_F(TableMergerTest,SetOverlayable)461 TEST_F(TableMergerTest, SetOverlayable) {
462 auto overlayable = std::make_shared<Overlayable>("CustomizableResources",
463 "overlay://customization");
464 OverlayableItem overlayable_item(overlayable);
465 overlayable_item.policies |= PolicyFlags::PRODUCT_PARTITION;
466 overlayable_item.policies |= PolicyFlags::VENDOR_PARTITION;
467
468 std::unique_ptr<ResourceTable> table_a =
469 test::ResourceTableBuilder()
470 .SetOverlayable("bool/foo", overlayable_item)
471 .Build();
472
473 std::unique_ptr<ResourceTable> table_b =
474 test::ResourceTableBuilder()
475 .AddSimple("bool/foo")
476 .Build();
477
478 ResourceTable final_table;
479 TableMergerOptions options;
480 options.auto_add_overlay = true;
481 TableMerger merger(context_.get(), &final_table, options);
482 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
483 ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/));
484
485 const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo");
486 Maybe<ResourceTable::SearchResult> search_result = final_table.FindResource(name);
487 ASSERT_TRUE(search_result);
488 ASSERT_TRUE(search_result.value().entry->overlayable_item);
489 OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
490 EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources"));
491 EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization"));
492 EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::PRODUCT_PARTITION
493 | PolicyFlags::VENDOR_PARTITION));
494 }
495
TEST_F(TableMergerTest,SetOverlayableLater)496 TEST_F(TableMergerTest, SetOverlayableLater) {
497 auto overlayable = std::make_shared<Overlayable>("CustomizableResources",
498 "overlay://customization");
499 std::unique_ptr<ResourceTable> table_a =
500 test::ResourceTableBuilder()
501 .AddSimple("bool/foo")
502 .Build();
503
504 OverlayableItem overlayable_item(overlayable);
505 overlayable_item.policies |= PolicyFlags::PUBLIC;
506 overlayable_item.policies |= PolicyFlags::SYSTEM_PARTITION;
507 std::unique_ptr<ResourceTable> table_b =
508 test::ResourceTableBuilder()
509 .SetOverlayable("bool/foo", overlayable_item)
510 .Build();
511
512 ResourceTable final_table;
513 TableMergerOptions options;
514 options.auto_add_overlay = true;
515 TableMerger merger(context_.get(), &final_table, options);
516 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
517 ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/));
518
519 const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo");
520 Maybe<ResourceTable::SearchResult> search_result = final_table.FindResource(name);
521 ASSERT_TRUE(search_result);
522 ASSERT_TRUE(search_result.value().entry->overlayable_item);
523 OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
524 EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources"));
525 EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization"));
526 EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::PUBLIC
527 | PolicyFlags::SYSTEM_PARTITION));
528 }
529
TEST_F(TableMergerTest,SameResourceDifferentNameFail)530 TEST_F(TableMergerTest, SameResourceDifferentNameFail) {
531 auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources",
532 "overlay://customization");
533 OverlayableItem overlayable_item_first(overlayable_first);
534 overlayable_item_first.policies |= PolicyFlags::PRODUCT_PARTITION;
535 std::unique_ptr<ResourceTable> table_a =
536 test::ResourceTableBuilder()
537 .SetOverlayable("bool/foo", overlayable_item_first)
538 .Build();
539
540 auto overlayable_second = std::make_shared<Overlayable>("ThemeResources",
541 "overlay://customization");
542 OverlayableItem overlayable_item_second(overlayable_second);
543 overlayable_item_second.policies |= PolicyFlags::PRODUCT_PARTITION;
544 std::unique_ptr<ResourceTable> table_b =
545 test::ResourceTableBuilder()
546 .SetOverlayable("bool/foo", overlayable_item_second)
547 .Build();
548
549 ResourceTable final_table;
550 TableMergerOptions options;
551 options.auto_add_overlay = true;
552 TableMerger merger(context_.get(), &final_table, options);
553 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
554 ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/));
555 }
556
TEST_F(TableMergerTest,SameResourceDifferentActorFail)557 TEST_F(TableMergerTest, SameResourceDifferentActorFail) {
558 auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources",
559 "overlay://customization");
560 OverlayableItem overlayable_item_first(overlayable_first);
561 overlayable_item_first.policies |= PolicyFlags::PRODUCT_PARTITION;
562 std::unique_ptr<ResourceTable> table_a =
563 test::ResourceTableBuilder()
564 .SetOverlayable("bool/foo", overlayable_item_first)
565 .Build();
566
567 auto overlayable_second = std::make_shared<Overlayable>("CustomizableResources",
568 "overlay://theme");
569 OverlayableItem overlayable_item_second(overlayable_second);
570 overlayable_item_second.policies |= PolicyFlags::PRODUCT_PARTITION;
571 std::unique_ptr<ResourceTable> table_b =
572 test::ResourceTableBuilder()
573 .SetOverlayable("bool/foo", overlayable_item_second)
574 .Build();
575
576 ResourceTable final_table;
577 TableMergerOptions options;
578 options.auto_add_overlay = true;
579 TableMerger merger(context_.get(), &final_table, options);
580 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
581 ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/));
582 }
583
TEST_F(TableMergerTest,SameResourceDifferentPoliciesFail)584 TEST_F(TableMergerTest, SameResourceDifferentPoliciesFail) {
585 auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources",
586 "overlay://customization");
587 OverlayableItem overlayable_item_first(overlayable_first);
588 overlayable_item_first.policies |= PolicyFlags::PRODUCT_PARTITION;
589 std::unique_ptr<ResourceTable> table_a =
590 test::ResourceTableBuilder()
591 .SetOverlayable("bool/foo", overlayable_item_first)
592 .Build();
593
594 auto overlayable_second = std::make_shared<Overlayable>("CustomizableResources",
595 "overlay://customization");
596 OverlayableItem overlayable_item_second(overlayable_second);
597 overlayable_item_second.policies |= PolicyFlags::SIGNATURE;
598 std::unique_ptr<ResourceTable> table_b =
599 test::ResourceTableBuilder()
600 .SetOverlayable("bool/foo", overlayable_item_second)
601 .Build();
602
603 ResourceTable final_table;
604 TableMergerOptions options;
605 options.auto_add_overlay = true;
606 TableMerger merger(context_.get(), &final_table, options);
607 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
608 ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/));
609 }
610
TEST_F(TableMergerTest,SameResourceSameOverlayable)611 TEST_F(TableMergerTest, SameResourceSameOverlayable) {
612 auto overlayable = std::make_shared<Overlayable>("CustomizableResources",
613 "overlay://customization");
614
615 OverlayableItem overlayable_item_first(overlayable);
616 overlayable_item_first.policies |= PolicyFlags::PRODUCT_PARTITION;
617 std::unique_ptr<ResourceTable> table_a =
618 test::ResourceTableBuilder()
619 .SetOverlayable("bool/foo", overlayable_item_first)
620 .Build();
621
622 OverlayableItem overlayable_item_second(overlayable);
623 overlayable_item_second.policies |= PolicyFlags::PRODUCT_PARTITION;
624 std::unique_ptr<ResourceTable> table_b =
625 test::ResourceTableBuilder()
626 .SetOverlayable("bool/foo", overlayable_item_second)
627 .Build();
628
629 ResourceTable final_table;
630 TableMergerOptions options;
631 options.auto_add_overlay = true;
632 TableMerger merger(context_.get(), &final_table, options);
633 ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
634 ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/));
635 }
636
637 } // namespace aapt
638