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/ReferenceLinker.h"
18
19 #include "test/Test.h"
20
21 using ::android::ResTable_map;
22 using ::testing::Eq;
23 using ::testing::IsNull;
24 using ::testing::NotNull;
25
26 namespace aapt {
27
TEST(ReferenceLinkerTest,LinkSimpleReferences)28 TEST(ReferenceLinkerTest, LinkSimpleReferences) {
29 std::unique_ptr<ResourceTable> table =
30 test::ResourceTableBuilder()
31 .AddReference("com.app.test:string/foo", ResourceId(0x7f020000),
32 "com.app.test:string/bar")
33
34 // Test use of local reference (w/o package name).
35 .AddReference("com.app.test:string/bar", ResourceId(0x7f020001),
36 "string/baz")
37
38 .AddReference("com.app.test:string/baz", ResourceId(0x7f020002),
39 "android:string/ok")
40 .Build();
41
42 std::unique_ptr<IAaptContext> context =
43 test::ContextBuilder()
44 .SetCompilationPackage("com.app.test")
45 .SetPackageId(0x7f)
46 .SetNameManglerPolicy(NameManglerPolicy{"com.app.test"})
47 .AddSymbolSource(
48 util::make_unique<ResourceTableSymbolSource>(table.get()))
49 .AddSymbolSource(
50 test::StaticSymbolSourceBuilder()
51 .AddPublicSymbol("android:string/ok", ResourceId(0x01040034))
52 .Build())
53 .Build();
54
55 ReferenceLinker linker;
56 ASSERT_TRUE(linker.Consume(context.get(), table.get()));
57
58 Reference* ref = test::GetValue<Reference>(table.get(), "com.app.test:string/foo");
59 ASSERT_THAT(ref, NotNull());
60 ASSERT_TRUE(ref->id);
61 EXPECT_EQ(ResourceId(0x7f020001), ref->id.value());
62
63 ref = test::GetValue<Reference>(table.get(), "com.app.test:string/bar");
64 ASSERT_THAT(ref, NotNull());
65 ASSERT_TRUE(ref->id);
66 EXPECT_EQ(ResourceId(0x7f020002), ref->id.value());
67
68 ref = test::GetValue<Reference>(table.get(), "com.app.test:string/baz");
69 ASSERT_THAT(ref, NotNull());
70 ASSERT_TRUE(ref->id);
71 EXPECT_EQ(ResourceId(0x01040034), ref->id.value());
72 }
73
TEST(ReferenceLinkerTest,LinkStyleAttributes)74 TEST(ReferenceLinkerTest, LinkStyleAttributes) {
75 std::unique_ptr<ResourceTable> table =
76 test::ResourceTableBuilder()
77 .AddValue("com.app.test:style/Theme",
78 test::StyleBuilder()
79 .SetParent("android:style/Theme.Material")
80 .AddItem("android:attr/foo",
81 ResourceUtils::TryParseColor("#ff00ff"))
82 .AddItem("android:attr/bar", {} /* placeholder */)
83 .Build())
84 .Build();
85
86 {
87 // We need to fill in the value for the attribute android:attr/bar after we
88 // build the table, because we need access to the string pool.
89 Style* style = test::GetValue<Style>(table.get(), "com.app.test:style/Theme");
90 ASSERT_THAT(style, NotNull());
91 style->entries.back().value =
92 util::make_unique<RawString>(table->string_pool.MakeRef("one|two"));
93 }
94
95 std::unique_ptr<IAaptContext> context =
96 test::ContextBuilder()
97 .SetCompilationPackage("com.app.test")
98 .SetPackageId(0x7f)
99 .SetNameManglerPolicy(NameManglerPolicy{"com.app.test"})
100 .AddSymbolSource(
101 test::StaticSymbolSourceBuilder()
102 .AddPublicSymbol("android:style/Theme.Material",
103 ResourceId(0x01060000))
104 .AddPublicSymbol("android:attr/foo", ResourceId(0x01010001),
105 test::AttributeBuilder()
106 .SetTypeMask(ResTable_map::TYPE_COLOR)
107 .Build())
108 .AddPublicSymbol("android:attr/bar", ResourceId(0x01010002),
109 test::AttributeBuilder()
110 .SetTypeMask(ResTable_map::TYPE_FLAGS)
111 .AddItem("one", 0x01)
112 .AddItem("two", 0x02)
113 .Build())
114 .Build())
115 .Build();
116
117 ReferenceLinker linker;
118 ASSERT_TRUE(linker.Consume(context.get(), table.get()));
119
120 Style* style = test::GetValue<Style>(table.get(), "com.app.test:style/Theme");
121 ASSERT_THAT(style, NotNull());
122 ASSERT_TRUE(style->parent);
123 ASSERT_TRUE(style->parent.value().id);
124 EXPECT_EQ(ResourceId(0x01060000), style->parent.value().id.value());
125
126 ASSERT_EQ(2u, style->entries.size());
127
128 ASSERT_TRUE(style->entries[0].key.id);
129 EXPECT_EQ(ResourceId(0x01010001), style->entries[0].key.id.value());
130 ASSERT_THAT(ValueCast<BinaryPrimitive>(style->entries[0].value.get()), NotNull());
131
132 ASSERT_TRUE(style->entries[1].key.id);
133 EXPECT_EQ(ResourceId(0x01010002), style->entries[1].key.id.value());
134 ASSERT_THAT(ValueCast<BinaryPrimitive>(style->entries[1].value.get()), NotNull());
135 }
136
TEST(ReferenceLinkerTest,LinkMangledReferencesAndAttributes)137 TEST(ReferenceLinkerTest, LinkMangledReferencesAndAttributes) {
138 std::unique_ptr<IAaptContext> context =
139 test::ContextBuilder()
140 .SetCompilationPackage("com.app.test")
141 .SetPackageId(0x7f)
142 .SetNameManglerPolicy(
143 NameManglerPolicy{"com.app.test", {"com.android.support"}})
144 .AddSymbolSource(
145 test::StaticSymbolSourceBuilder()
146 .AddPublicSymbol("com.app.test:attr/com.android.support$foo",
147 ResourceId(0x7f010000),
148 test::AttributeBuilder()
149 .SetTypeMask(ResTable_map::TYPE_COLOR)
150 .Build())
151 .Build())
152 .Build();
153
154 std::unique_ptr<ResourceTable> table =
155 test::ResourceTableBuilder()
156 .AddValue("com.app.test:style/Theme", ResourceId(0x7f020000),
157 test::StyleBuilder()
158 .AddItem("com.android.support:attr/foo",
159 ResourceUtils::TryParseColor("#ff0000"))
160 .Build())
161 .Build();
162
163 ReferenceLinker linker;
164 ASSERT_TRUE(linker.Consume(context.get(), table.get()));
165
166 Style* style = test::GetValue<Style>(table.get(), "com.app.test:style/Theme");
167 ASSERT_THAT(style, NotNull());
168 ASSERT_EQ(1u, style->entries.size());
169 ASSERT_TRUE(style->entries.front().key.id);
170 EXPECT_EQ(ResourceId(0x7f010000), style->entries.front().key.id.value());
171 }
172
TEST(ReferenceLinkerTest,FailToLinkPrivateSymbols)173 TEST(ReferenceLinkerTest, FailToLinkPrivateSymbols) {
174 std::unique_ptr<ResourceTable> table =
175 test::ResourceTableBuilder()
176 .AddReference("com.app.test:string/foo", ResourceId(0x7f020000),
177 "android:string/hidden")
178 .Build();
179
180 std::unique_ptr<IAaptContext> context =
181 test::ContextBuilder()
182 .SetCompilationPackage("com.app.test")
183 .SetPackageId(0x7f)
184 .SetNameManglerPolicy(NameManglerPolicy{"com.app.test"})
185 .AddSymbolSource(
186 util::make_unique<ResourceTableSymbolSource>(table.get()))
187 .AddSymbolSource(
188 test::StaticSymbolSourceBuilder()
189 .AddSymbol("android:string/hidden", ResourceId(0x01040034))
190 .Build())
191 .Build();
192
193 ReferenceLinker linker;
194 ASSERT_FALSE(linker.Consume(context.get(), table.get()));
195 }
196
TEST(ReferenceLinkerTest,FailToLinkPrivateMangledSymbols)197 TEST(ReferenceLinkerTest, FailToLinkPrivateMangledSymbols) {
198 std::unique_ptr<ResourceTable> table =
199 test::ResourceTableBuilder()
200 .AddReference("com.app.test:string/foo", ResourceId(0x7f020000),
201 "com.app.lib:string/hidden")
202 .Build();
203
204 std::unique_ptr<IAaptContext> context =
205 test::ContextBuilder()
206 .SetCompilationPackage("com.app.test")
207 .SetPackageId(0x7f)
208 .SetNameManglerPolicy(
209 NameManglerPolicy{"com.app.test", {"com.app.lib"}})
210 .AddSymbolSource(
211 util::make_unique<ResourceTableSymbolSource>(table.get()))
212 .AddSymbolSource(
213 test::StaticSymbolSourceBuilder()
214 .AddSymbol("com.app.test:string/com.app.lib$hidden",
215 ResourceId(0x7f040034))
216 .Build())
217
218 .Build();
219
220 ReferenceLinker linker;
221 ASSERT_FALSE(linker.Consume(context.get(), table.get()));
222 }
223
TEST(ReferenceLinkerTest,FailToLinkPrivateStyleAttributes)224 TEST(ReferenceLinkerTest, FailToLinkPrivateStyleAttributes) {
225 std::unique_ptr<ResourceTable> table =
226 test::ResourceTableBuilder()
227 .AddValue("com.app.test:style/Theme",
228 test::StyleBuilder()
229 .AddItem("android:attr/hidden",
230 ResourceUtils::TryParseColor("#ff00ff"))
231 .Build())
232 .Build();
233
234 std::unique_ptr<IAaptContext> context =
235 test::ContextBuilder()
236 .SetCompilationPackage("com.app.test")
237 .SetPackageId(0x7f)
238 .SetNameManglerPolicy(NameManglerPolicy{"com.app.test"})
239 .AddSymbolSource(
240 util::make_unique<ResourceTableSymbolSource>(table.get()))
241 .AddSymbolSource(
242 test::StaticSymbolSourceBuilder()
243 .AddSymbol("android:attr/hidden", ResourceId(0x01010001),
244 test::AttributeBuilder()
245 .SetTypeMask(android::ResTable_map::TYPE_COLOR)
246 .Build())
247 .Build())
248 .Build();
249
250 ReferenceLinker linker;
251 ASSERT_FALSE(linker.Consume(context.get(), table.get()));
252 }
253
TEST(ReferenceLinkerTest,AppsWithSamePackageButDifferentIdAreVisibleNonPublic)254 TEST(ReferenceLinkerTest, AppsWithSamePackageButDifferentIdAreVisibleNonPublic) {
255 NameMangler mangler(NameManglerPolicy{"com.app.test"});
256 SymbolTable table(&mangler);
257 table.AppendSource(test::StaticSymbolSourceBuilder()
258 .AddSymbol("com.app.test:string/foo", ResourceId(0x7f010000))
259 .Build());
260
261 std::string error;
262 const CallSite call_site{"com.app.test"};
263 std::unique_ptr<IAaptContext> context =
264 test::ContextBuilder()
265 .SetCompilationPackage("com.app.test")
266 .SetPackageId(0x7f)
267 .Build();
268 const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveSymbolCheckVisibility(
269 *test::BuildReference("com.app.test:string/foo"), call_site, context.get(), &table, &error);
270 ASSERT_THAT(symbol, NotNull());
271 EXPECT_TRUE(error.empty());
272 }
273
TEST(ReferenceLinkerTest,AppsWithDifferentPackageCanNotUseEachOthersAttribute)274 TEST(ReferenceLinkerTest, AppsWithDifferentPackageCanNotUseEachOthersAttribute) {
275 NameMangler mangler(NameManglerPolicy{"com.app.ext"});
276 SymbolTable table(&mangler);
277 table.AppendSource(test::StaticSymbolSourceBuilder()
278 .AddSymbol("com.app.test:attr/foo", ResourceId(0x7f010000),
279 test::AttributeBuilder().Build())
280 .AddPublicSymbol("com.app.test:attr/public_foo", ResourceId(0x7f010001),
281 test::AttributeBuilder().Build())
282 .Build());
283 std::unique_ptr<IAaptContext> context =
284 test::ContextBuilder()
285 .SetCompilationPackage("com.app.ext")
286 .SetPackageId(0x7f)
287 .Build();
288
289 std::string error;
290 const CallSite call_site{"com.app.ext"};
291
292 EXPECT_FALSE(ReferenceLinker::CompileXmlAttribute(
293 *test::BuildReference("com.app.test:attr/foo"), call_site, context.get(), &table, &error));
294 EXPECT_FALSE(error.empty());
295
296 error = "";
297 ASSERT_TRUE(ReferenceLinker::CompileXmlAttribute(
298 *test::BuildReference("com.app.test:attr/public_foo"), call_site, context.get(), &table,
299 &error));
300 EXPECT_TRUE(error.empty());
301 }
302
TEST(ReferenceLinkerTest,ReferenceWithNoPackageUsesCallSitePackage)303 TEST(ReferenceLinkerTest, ReferenceWithNoPackageUsesCallSitePackage) {
304 NameMangler mangler(NameManglerPolicy{"com.app.test"});
305 SymbolTable table(&mangler);
306 table.AppendSource(test::StaticSymbolSourceBuilder()
307 .AddSymbol("com.app.test:string/foo", ResourceId(0x7f010000))
308 .AddSymbol("com.app.lib:string/foo", ResourceId(0x7f010001))
309 .Build());
310 std::unique_ptr<IAaptContext> context =
311 test::ContextBuilder()
312 .SetCompilationPackage("com.app.test")
313 .SetPackageId(0x7f)
314 .Build();
315
316 const SymbolTable::Symbol* s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"),
317 CallSite{"com.app.test"},
318 context.get(), &table);
319 ASSERT_THAT(s, NotNull());
320 EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010000)));
321
322 s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"), CallSite{"com.app.lib"},
323 context.get(), &table);
324 ASSERT_THAT(s, NotNull());
325 EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010001)));
326
327 EXPECT_THAT(ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"),
328 CallSite{"com.app.bad"}, context.get(), &table),
329 IsNull());
330 }
331
TEST(ReferenceLinkerTest,ReferenceSymbolFromOtherSplit)332 TEST(ReferenceLinkerTest, ReferenceSymbolFromOtherSplit) {
333 NameMangler mangler(NameManglerPolicy{"com.app.test"});
334 SymbolTable table(&mangler);
335 table.AppendSource(test::StaticSymbolSourceBuilder()
336 .AddSymbol("com.app.test.feature:string/bar", ResourceId(0x80010000))
337 .Build());
338 std::set<std::string> split_name_dependencies;
339 split_name_dependencies.insert("feature");
340 std::unique_ptr<IAaptContext> context =
341 test::ContextBuilder()
342 .SetCompilationPackage("com.app.test")
343 .SetPackageId(0x81)
344 .SetSplitNameDependencies(split_name_dependencies)
345 .Build();
346
347 const SymbolTable::Symbol* s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/bar"),
348 CallSite{"com.app.test"},
349 context.get(), &table);
350 ASSERT_THAT(s, NotNull());
351 EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x80010000)));
352
353 s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"), CallSite{"com.app.lib"},
354 context.get(), &table);
355 EXPECT_THAT(s, IsNull());
356
357 context =
358 test::ContextBuilder()
359 .SetCompilationPackage("com.app.test")
360 .SetPackageId(0x81)
361 .Build();
362 s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/bar"),CallSite{"com.app.test"},
363 context.get(), &table);
364
365 EXPECT_THAT(s, IsNull());
366 }
367
TEST(ReferenceLinkerTest,MacroFailToFindDefinition)368 TEST(ReferenceLinkerTest, MacroFailToFindDefinition) {
369 std::unique_ptr<ResourceTable> table =
370 test::ResourceTableBuilder()
371 .AddReference("com.app.test:string/foo", ResourceId(0x7f020000), "com.app.test:macro/bar")
372 .Build();
373
374 std::unique_ptr<IAaptContext> context =
375 test::ContextBuilder()
376 .SetCompilationPackage("com.app.test")
377 .SetPackageId(0x7f)
378 .SetNameManglerPolicy(NameManglerPolicy{"com.app.test"})
379 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
380 .Build();
381
382 ReferenceLinker linker;
383 ASSERT_FALSE(linker.Consume(context.get(), table.get()));
384 }
385
386 } // namespace aapt
387