blob: 45c8c98780b8a03a6414c66854d015f996786a92 [file] [log] [blame]
Adam Lesinski1ab598f2015-08-14 14:26:04 -07001/*
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
Adam Lesinski6a008172016-02-02 17:02:58 -080017#include "filter/ConfigFilter.h"
Adam Lesinskia6fe3452015-12-09 15:20:52 -080018#include "io/FileSystem.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070019#include "link/TableMerger.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070020#include "test/Builders.h"
21#include "test/Context.h"
22
23#include <gtest/gtest.h>
24
25namespace aapt {
26
27struct TableMergerTest : public ::testing::Test {
28 std::unique_ptr<IAaptContext> mContext;
29
30 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
45TEST_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;
Adam Lesinskia6fe3452015-12-09 15:20:52 -080061 TableMerger merger(mContext.get(), &finalTable, TableMergerOptions{});
62 io::FileCollection collection;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070063
Adam Lesinskia6fe3452015-12-09 15:20:52 -080064 ASSERT_TRUE(merger.merge({}, tableA.get()));
65 ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get(), &collection));
Adam Lesinski1ab598f2015-08-14 14:26:04 -070066
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
Adam Lesinskia6fe3452015-12-09 15:20:52 -080081TEST_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 ResourceName name = test::parseNameOrDie(u"@com.app.a:layout/main");
102 ResourceKeyRef key = { name, test::parseConfigOrDie("hdpi-v4") };
103
104 auto iter = merger.getFilesToMerge().find(key);
105 ASSERT_NE(merger.getFilesToMerge().end(), iter);
106
107 const FileToMerge& actualFileToMerge = iter->second;
108 EXPECT_EQ(&testFile, actualFileToMerge.file);
109 EXPECT_EQ(std::string("res/layout-hdpi-v4/main.xml"), actualFileToMerge.dstPath);
110}
111
112TEST_F(TableMergerTest, MergeFileOverlay) {
113 ResourceTable finalTable;
114 TableMergerOptions tableMergerOptions;
115 tableMergerOptions.autoAddOverlay = false;
116 TableMerger merger(mContext.get(), &finalTable, tableMergerOptions);
117
118 ResourceFile fileDesc;
119 fileDesc.name = test::parseNameOrDie(u"@xml/foo");
120 test::TestFile fileA("path/to/fileA.xml.flat");
121 test::TestFile fileB("path/to/fileB.xml.flat");
122
123 ASSERT_TRUE(merger.mergeFile(fileDesc, &fileA));
124 ASSERT_TRUE(merger.mergeFileOverlay(fileDesc, &fileB));
125
126 ResourceName name = test::parseNameOrDie(u"@com.app.a:xml/foo");
127 ResourceKeyRef key = { name, ConfigDescription{} };
128 auto iter = merger.getFilesToMerge().find(key);
129 ASSERT_NE(merger.getFilesToMerge().end(), iter);
130
131 const FileToMerge& actualFileToMerge = iter->second;
132 EXPECT_EQ(&fileB, actualFileToMerge.file);
133}
134
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700135TEST_F(TableMergerTest, MergeFileReferences) {
136 std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
137 .setPackageId(u"com.app.a", 0x7f)
138 .addFileReference(u"@com.app.a:xml/file", u"res/xml/file.xml")
139 .build();
140 std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
141 .setPackageId(u"com.app.b", 0x7f)
142 .addFileReference(u"@com.app.b:xml/file", u"res/xml/file.xml")
143 .build();
144
145 ResourceTable finalTable;
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800146 TableMerger merger(mContext.get(), &finalTable, TableMergerOptions{});
147 io::FileCollection collection;
148 collection.insertFile("res/xml/file.xml");
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700149
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800150 ASSERT_TRUE(merger.merge({}, tableA.get()));
151 ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get(), &collection));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700152
153 FileReference* f = test::getValue<FileReference>(&finalTable, u"@com.app.a:xml/file");
154 ASSERT_NE(f, nullptr);
155 EXPECT_EQ(std::u16string(u"res/xml/file.xml"), *f->path);
156
157 f = test::getValue<FileReference>(&finalTable, u"@com.app.a:xml/com.app.b$file");
158 ASSERT_NE(f, nullptr);
159 EXPECT_EQ(std::u16string(u"res/xml/com.app.b$file.xml"), *f->path);
160
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800161 ResourceName name = test::parseNameOrDie(u"@com.app.a:xml/com.app.b$file");
162 ResourceKeyRef key = { name, ConfigDescription{} };
163 auto iter = merger.getFilesToMerge().find(key);
164 ASSERT_NE(merger.getFilesToMerge().end(), iter);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700165
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800166 const FileToMerge& actualFileToMerge = iter->second;
167 EXPECT_EQ(Source("res/xml/file.xml"), actualFileToMerge.file->getSource());
168 EXPECT_EQ(std::string("res/xml/com.app.b$file.xml"), actualFileToMerge.dstPath);
169}
170
171TEST_F(TableMergerTest, OverrideResourceWithOverlay) {
172 std::unique_ptr<ResourceTable> base = test::ResourceTableBuilder()
173 .setPackageId(u"", 0x00)
174 .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
175 .build();
176 std::unique_ptr<ResourceTable> overlay = test::ResourceTableBuilder()
177 .setPackageId(u"", 0x00)
178 .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"false"))
179 .build();
180
181 ResourceTable finalTable;
182 TableMergerOptions tableMergerOptions;
183 tableMergerOptions.autoAddOverlay = false;
184 TableMerger merger(mContext.get(), &finalTable, tableMergerOptions);
185
186 ASSERT_TRUE(merger.merge({}, base.get()));
187 ASSERT_TRUE(merger.mergeOverlay({}, overlay.get()));
188
189 BinaryPrimitive* foo = test::getValue<BinaryPrimitive>(&finalTable, u"@com.app.a:bool/foo");
190 ASSERT_NE(nullptr, foo);
191 EXPECT_EQ(0x0u, foo->value.data);
192}
193
194TEST_F(TableMergerTest, MergeAddResourceFromOverlay) {
195 std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
196 .setPackageId(u"", 0x7f)
197 .setSymbolState(u"@bool/foo", {}, SymbolState::kUndefined)
198 .build();
199 std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
200 .setPackageId(u"", 0x7f)
201 .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
202 .build();
203
204 ResourceTable finalTable;
205 TableMerger merger(mContext.get(), &finalTable, TableMergerOptions{});
206
207 ASSERT_TRUE(merger.merge({}, tableA.get()));
208 ASSERT_TRUE(merger.mergeOverlay({}, tableB.get()));
209}
210
211TEST_F(TableMergerTest, MergeAddResourceFromOverlayWithAutoAddOverlay) {
212 std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
213 .setPackageId(u"", 0x7f)
214 .build();
215 std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
216 .setPackageId(u"", 0x7f)
217 .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
218 .build();
219
220 ResourceTable finalTable;
221 TableMergerOptions options;
222 options.autoAddOverlay = true;
223 TableMerger merger(mContext.get(), &finalTable, options);
224
225 ASSERT_TRUE(merger.merge({}, tableA.get()));
226 ASSERT_TRUE(merger.mergeOverlay({}, tableB.get()));
227}
228
229TEST_F(TableMergerTest, FailToMergeNewResourceWithoutAutoAddOverlay) {
230 std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
231 .setPackageId(u"", 0x7f)
232 .build();
233 std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
234 .setPackageId(u"", 0x7f)
235 .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
236 .build();
237
238 ResourceTable finalTable;
239 TableMergerOptions options;
240 options.autoAddOverlay = false;
241 TableMerger merger(mContext.get(), &finalTable, options);
242
243 ASSERT_TRUE(merger.merge({}, tableA.get()));
244 ASSERT_FALSE(merger.mergeOverlay({}, tableB.get()));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700245}
246
Adam Lesinski6a008172016-02-02 17:02:58 -0800247TEST_F(TableMergerTest, MergeAndStripResourcesNotMatchingFilter) {
248 ResourceTable finalTable;
249 TableMergerOptions options;
250 options.autoAddOverlay = false;
251
252 AxisConfigFilter filter;
253 filter.addConfig(test::parseConfigOrDie("en"));
254 options.filter = &filter;
255
256 test::TestFile fileA("res/layout-en/main.xml"), fileB("res/layout-fr-rFR/main.xml");
257 const ResourceName name = test::parseNameOrDie(u"@com.app.a:layout/main");
258 const ConfigDescription configEn = test::parseConfigOrDie("en");
259 const ConfigDescription configFr = test::parseConfigOrDie("fr-rFR");
260
261 TableMerger merger(mContext.get(), &finalTable, options);
262 ASSERT_TRUE(merger.mergeFile(ResourceFile{ name, configEn }, &fileA));
263 ASSERT_TRUE(merger.mergeFile(ResourceFile{ name, configFr }, &fileB));
264
265 EXPECT_NE(nullptr, test::getValueForConfig<FileReference>(&finalTable,
266 u"@com.app.a:layout/main",
267 configEn));
268 EXPECT_EQ(nullptr, test::getValueForConfig<FileReference>(&finalTable,
269 u"@com.app.a:layout/main",
270 configFr));
271
272 EXPECT_NE(merger.getFilesToMerge().end(),
273 merger.getFilesToMerge().find(ResourceKeyRef(name, configEn)));
274
275 EXPECT_EQ(merger.getFilesToMerge().end(),
276 merger.getFilesToMerge().find(ResourceKeyRef(name, configFr)));
277}
278
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700279} // namespace aapt