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 "filter/ConfigFilter.h"
18 #include "io/FileSystem.h"
19 #include "link/TableMerger.h"
20 #include "test/Builders.h"
21 #include "test/Context.h"
22
23 #include <gtest/gtest.h>
24
25 namespace aapt {
26
27 struct TableMergerTest : public ::testing::Test {
28 std::unique_ptr<IAaptContext> mContext;
29
SetUpaapt::TableMergerTest30 void SetUp() override {
31 mContext = test::ContextBuilder()
32 // We are compiling this package.
33 .setCompilationPackage(u"com.app.a")
34
35 // Merge all packages that have this package ID.
36 .setPackageId(0x7f)
37
38 // Mangle all packages that do not have this package name.
39 .setNameManglerPolicy(NameManglerPolicy{ u"com.app.a", { u"com.app.b" } })
40
41 .build();
42 }
43 };
44
TEST_F(TableMergerTest,SimpleMerge)45 TEST_F(TableMergerTest, SimpleMerge) {
46 std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
47 .setPackageId(u"com.app.a", 0x7f)
48 .addReference(u"@com.app.a:id/foo", u"@com.app.a:id/bar")
49 .addReference(u"@com.app.a:id/bar", u"@com.app.b:id/foo")
50 .addValue(u"@com.app.a:styleable/view", test::StyleableBuilder()
51 .addItem(u"@com.app.b:id/foo")
52 .build())
53 .build();
54
55 std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
56 .setPackageId(u"com.app.b", 0x7f)
57 .addSimple(u"@com.app.b:id/foo")
58 .build();
59
60 ResourceTable finalTable;
61 TableMerger merger(mContext.get(), &finalTable, TableMergerOptions{});
62 io::FileCollection collection;
63
64 ASSERT_TRUE(merger.merge({}, tableA.get()));
65 ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get(), &collection));
66
67 EXPECT_TRUE(merger.getMergedPackages().count(u"com.app.b") != 0);
68
69 // Entries from com.app.a should not be mangled.
70 AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie(u"@com.app.a:id/foo")));
71 AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie(u"@com.app.a:id/bar")));
72 AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie(u"@com.app.a:styleable/view")));
73
74 // The unmangled name should not be present.
75 AAPT_EXPECT_FALSE(finalTable.findResource(test::parseNameOrDie(u"@com.app.b:id/foo")));
76
77 // Look for the mangled name.
78 AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie(u"@com.app.a:id/com.app.b$foo")));
79 }
80
TEST_F(TableMergerTest,MergeFile)81 TEST_F(TableMergerTest, MergeFile) {
82 ResourceTable finalTable;
83 TableMergerOptions options;
84 options.autoAddOverlay = false;
85 TableMerger merger(mContext.get(), &finalTable, options);
86
87 ResourceFile fileDesc;
88 fileDesc.config = test::parseConfigOrDie("hdpi-v4");
89 fileDesc.name = test::parseNameOrDie(u"@layout/main");
90 fileDesc.source = Source("res/layout-hdpi/main.xml");
91 test::TestFile testFile("path/to/res/layout-hdpi/main.xml.flat");
92
93 ASSERT_TRUE(merger.mergeFile(fileDesc, &testFile));
94
95 FileReference* file = test::getValueForConfig<FileReference>(&finalTable,
96 u"@com.app.a:layout/main",
97 test::parseConfigOrDie("hdpi-v4"));
98 ASSERT_NE(nullptr, file);
99 EXPECT_EQ(std::u16string(u"res/layout-hdpi-v4/main.xml"), *file->path);
100 }
101
TEST_F(TableMergerTest,MergeFileOverlay)102 TEST_F(TableMergerTest, MergeFileOverlay) {
103 ResourceTable finalTable;
104 TableMergerOptions tableMergerOptions;
105 tableMergerOptions.autoAddOverlay = false;
106 TableMerger merger(mContext.get(), &finalTable, tableMergerOptions);
107
108 ResourceFile fileDesc;
109 fileDesc.name = test::parseNameOrDie(u"@xml/foo");
110 test::TestFile fileA("path/to/fileA.xml.flat");
111 test::TestFile fileB("path/to/fileB.xml.flat");
112
113 ASSERT_TRUE(merger.mergeFile(fileDesc, &fileA));
114 ASSERT_TRUE(merger.mergeFileOverlay(fileDesc, &fileB));
115 }
116
TEST_F(TableMergerTest,MergeFileReferences)117 TEST_F(TableMergerTest, MergeFileReferences) {
118 std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
119 .setPackageId(u"com.app.a", 0x7f)
120 .addFileReference(u"@com.app.a:xml/file", u"res/xml/file.xml")
121 .build();
122 std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
123 .setPackageId(u"com.app.b", 0x7f)
124 .addFileReference(u"@com.app.b:xml/file", u"res/xml/file.xml")
125 .build();
126
127 ResourceTable finalTable;
128 TableMerger merger(mContext.get(), &finalTable, TableMergerOptions{});
129 io::FileCollection collection;
130 collection.insertFile("res/xml/file.xml");
131
132 ASSERT_TRUE(merger.merge({}, tableA.get()));
133 ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get(), &collection));
134
135 FileReference* f = test::getValue<FileReference>(&finalTable, u"@com.app.a:xml/file");
136 ASSERT_NE(f, nullptr);
137 EXPECT_EQ(std::u16string(u"res/xml/file.xml"), *f->path);
138
139 f = test::getValue<FileReference>(&finalTable, u"@com.app.a:xml/com.app.b$file");
140 ASSERT_NE(f, nullptr);
141 EXPECT_EQ(std::u16string(u"res/xml/com.app.b$file.xml"), *f->path);
142 }
143
TEST_F(TableMergerTest,OverrideResourceWithOverlay)144 TEST_F(TableMergerTest, OverrideResourceWithOverlay) {
145 std::unique_ptr<ResourceTable> base = test::ResourceTableBuilder()
146 .setPackageId(u"", 0x00)
147 .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
148 .build();
149 std::unique_ptr<ResourceTable> overlay = test::ResourceTableBuilder()
150 .setPackageId(u"", 0x00)
151 .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"false"))
152 .build();
153
154 ResourceTable finalTable;
155 TableMergerOptions tableMergerOptions;
156 tableMergerOptions.autoAddOverlay = false;
157 TableMerger merger(mContext.get(), &finalTable, tableMergerOptions);
158
159 ASSERT_TRUE(merger.merge({}, base.get()));
160 ASSERT_TRUE(merger.mergeOverlay({}, overlay.get()));
161
162 BinaryPrimitive* foo = test::getValue<BinaryPrimitive>(&finalTable, u"@com.app.a:bool/foo");
163 ASSERT_NE(nullptr, foo);
164 EXPECT_EQ(0x0u, foo->value.data);
165 }
166
TEST_F(TableMergerTest,MergeAddResourceFromOverlay)167 TEST_F(TableMergerTest, MergeAddResourceFromOverlay) {
168 std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
169 .setPackageId(u"", 0x7f)
170 .setSymbolState(u"@bool/foo", {}, SymbolState::kUndefined)
171 .build();
172 std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
173 .setPackageId(u"", 0x7f)
174 .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
175 .build();
176
177 ResourceTable finalTable;
178 TableMerger merger(mContext.get(), &finalTable, TableMergerOptions{});
179
180 ASSERT_TRUE(merger.merge({}, tableA.get()));
181 ASSERT_TRUE(merger.mergeOverlay({}, tableB.get()));
182 }
183
TEST_F(TableMergerTest,MergeAddResourceFromOverlayWithAutoAddOverlay)184 TEST_F(TableMergerTest, MergeAddResourceFromOverlayWithAutoAddOverlay) {
185 std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
186 .setPackageId(u"", 0x7f)
187 .build();
188 std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
189 .setPackageId(u"", 0x7f)
190 .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
191 .build();
192
193 ResourceTable finalTable;
194 TableMergerOptions options;
195 options.autoAddOverlay = true;
196 TableMerger merger(mContext.get(), &finalTable, options);
197
198 ASSERT_TRUE(merger.merge({}, tableA.get()));
199 ASSERT_TRUE(merger.mergeOverlay({}, tableB.get()));
200 }
201
TEST_F(TableMergerTest,FailToMergeNewResourceWithoutAutoAddOverlay)202 TEST_F(TableMergerTest, FailToMergeNewResourceWithoutAutoAddOverlay) {
203 std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
204 .setPackageId(u"", 0x7f)
205 .build();
206 std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
207 .setPackageId(u"", 0x7f)
208 .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
209 .build();
210
211 ResourceTable finalTable;
212 TableMergerOptions options;
213 options.autoAddOverlay = false;
214 TableMerger merger(mContext.get(), &finalTable, options);
215
216 ASSERT_TRUE(merger.merge({}, tableA.get()));
217 ASSERT_FALSE(merger.mergeOverlay({}, tableB.get()));
218 }
219
220 } // namespace aapt
221