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
SetUpaapt::TableMergerTest37 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
TEST_F(TableMergerTest,SimpleMerge)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
TEST_F(TableMergerTest,MergeFile)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
TEST_F(TableMergerTest,MergeFileOverlay)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
TEST_F(TableMergerTest,MergeFileReferences)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
TEST_F(TableMergerTest,OverrideResourceWithOverlay)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
TEST_F(TableMergerTest,DoNotOverrideResourceComment)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
TEST_F(TableMergerTest,OverrideSameResourceIdsWithOverlay)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
TEST_F(TableMergerTest,FailToOverrideConflictingTypeIdsWithOverlay)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
TEST_F(TableMergerTest,FailToOverrideConflictingEntryIdsWithOverlay)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
TEST_F(TableMergerTest,FailConflictingVisibility)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
TEST_F(TableMergerTest,MergeAddResourceFromOverlay)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
TEST_F(TableMergerTest,MergeAddResourceFromOverlayWithAutoAddOverlay)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
TEST_F(TableMergerTest,OverrideAttributeSameFormatsWithOverlay)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
TEST_F(TableMergerTest,FailToOverrideConflictingAttributeFormatsWithOverlay)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
TEST_F(TableMergerTest,FailToMergeNewResourceWithoutAutoAddOverlay)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
TEST_F(TableMergerTest,OverlaidStyleablesAndStylesShouldBeMerged)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
TEST_F(TableMergerTest,SetOverlayable)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
TEST_F(TableMergerTest,SetOverlayableLater)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
TEST_F(TableMergerTest,SameResourceDifferentNameFail)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
TEST_F(TableMergerTest,SameResourceDifferentActorFail)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
TEST_F(TableMergerTest,SameResourceDifferentPoliciesFail)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
TEST_F(TableMergerTest,SameResourceSameOverlayable)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