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
21using android::ResTable_map;
22
23namespace aapt {
24
25TEST(ReferenceLinkerTest, LinkSimpleReferences) {
26  std::unique_ptr<ResourceTable> table =
27      test::ResourceTableBuilder()
28          .SetPackageId("com.app.test", 0x7f)
29          .AddReference("com.app.test:string/foo", ResourceId(0x7f020000),
30                        "com.app.test:string/bar")
31
32          // Test use of local reference (w/o package name).
33          .AddReference("com.app.test:string/bar", ResourceId(0x7f020001),
34                        "string/baz")
35
36          .AddReference("com.app.test:string/baz", ResourceId(0x7f020002),
37                        "android:string/ok")
38          .Build();
39
40  std::unique_ptr<IAaptContext> context =
41      test::ContextBuilder()
42          .SetCompilationPackage("com.app.test")
43          .SetPackageId(0x7f)
44          .SetNameManglerPolicy(NameManglerPolicy{"com.app.test"})
45          .AddSymbolSource(
46              util::make_unique<ResourceTableSymbolSource>(table.get()))
47          .AddSymbolSource(
48              test::StaticSymbolSourceBuilder()
49                  .AddPublicSymbol("android:string/ok", ResourceId(0x01040034))
50                  .Build())
51          .Build();
52
53  ReferenceLinker linker;
54  ASSERT_TRUE(linker.Consume(context.get(), table.get()));
55
56  Reference* ref = test::GetValue<Reference>(table.get(), "com.app.test:string/foo");
57  ASSERT_NE(nullptr, ref);
58  AAPT_ASSERT_TRUE(ref->id);
59  EXPECT_EQ(ResourceId(0x7f020001), ref->id.value());
60
61  ref = test::GetValue<Reference>(table.get(), "com.app.test:string/bar");
62  ASSERT_NE(nullptr, ref);
63  AAPT_ASSERT_TRUE(ref->id);
64  EXPECT_EQ(ResourceId(0x7f020002), ref->id.value());
65
66  ref = test::GetValue<Reference>(table.get(), "com.app.test:string/baz");
67  ASSERT_NE(nullptr, ref);
68  AAPT_ASSERT_TRUE(ref->id);
69  EXPECT_EQ(ResourceId(0x01040034), ref->id.value());
70}
71
72TEST(ReferenceLinkerTest, LinkStyleAttributes) {
73  std::unique_ptr<ResourceTable> table =
74      test::ResourceTableBuilder()
75          .SetPackageId("com.app.test", 0x7f)
76          .AddValue("com.app.test:style/Theme",
77                    test::StyleBuilder()
78                        .SetParent("android:style/Theme.Material")
79                        .AddItem("android:attr/foo",
80                                 ResourceUtils::TryParseColor("#ff00ff"))
81                        .AddItem("android:attr/bar", {} /* placeholder */)
82                        .Build())
83          .Build();
84
85  {
86    // We need to fill in the value for the attribute android:attr/bar after we
87    // build the
88    // table, because we need access to the string pool.
89    Style* style = test::GetValue<Style>(table.get(), "com.app.test:style/Theme");
90    ASSERT_NE(nullptr, style);
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_NE(nullptr, style);
122  AAPT_ASSERT_TRUE(style->parent);
123  AAPT_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  AAPT_ASSERT_TRUE(style->entries[0].key.id);
129  EXPECT_EQ(ResourceId(0x01010001), style->entries[0].key.id.value());
130  ASSERT_NE(nullptr, ValueCast<BinaryPrimitive>(style->entries[0].value.get()));
131
132  AAPT_ASSERT_TRUE(style->entries[1].key.id);
133  EXPECT_EQ(ResourceId(0x01010002), style->entries[1].key.id.value());
134  ASSERT_NE(nullptr, ValueCast<BinaryPrimitive>(style->entries[1].value.get()));
135}
136
137TEST(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          .SetPackageId("com.app.test", 0x7f)
157          .AddValue("com.app.test:style/Theme", ResourceId(0x7f020000),
158                    test::StyleBuilder()
159                        .AddItem("com.android.support:attr/foo",
160                                 ResourceUtils::TryParseColor("#ff0000"))
161                        .Build())
162          .Build();
163
164  ReferenceLinker linker;
165  ASSERT_TRUE(linker.Consume(context.get(), table.get()));
166
167  Style* style = test::GetValue<Style>(table.get(), "com.app.test:style/Theme");
168  ASSERT_NE(nullptr, style);
169  ASSERT_EQ(1u, style->entries.size());
170  AAPT_ASSERT_TRUE(style->entries.front().key.id);
171  EXPECT_EQ(ResourceId(0x7f010000), style->entries.front().key.id.value());
172}
173
174TEST(ReferenceLinkerTest, FailToLinkPrivateSymbols) {
175  std::unique_ptr<ResourceTable> table =
176      test::ResourceTableBuilder()
177          .SetPackageId("com.app.test", 0x7f)
178          .AddReference("com.app.test:string/foo", ResourceId(0x7f020000),
179                        "android:string/hidden")
180          .Build();
181
182  std::unique_ptr<IAaptContext> context =
183      test::ContextBuilder()
184          .SetCompilationPackage("com.app.test")
185          .SetPackageId(0x7f)
186          .SetNameManglerPolicy(NameManglerPolicy{"com.app.test"})
187          .AddSymbolSource(
188              util::make_unique<ResourceTableSymbolSource>(table.get()))
189          .AddSymbolSource(
190              test::StaticSymbolSourceBuilder()
191                  .AddSymbol("android:string/hidden", ResourceId(0x01040034))
192                  .Build())
193          .Build();
194
195  ReferenceLinker linker;
196  ASSERT_FALSE(linker.Consume(context.get(), table.get()));
197}
198
199TEST(ReferenceLinkerTest, FailToLinkPrivateMangledSymbols) {
200  std::unique_ptr<ResourceTable> table =
201      test::ResourceTableBuilder()
202          .SetPackageId("com.app.test", 0x7f)
203          .AddReference("com.app.test:string/foo", ResourceId(0x7f020000),
204                        "com.app.lib:string/hidden")
205          .Build();
206
207  std::unique_ptr<IAaptContext> context =
208      test::ContextBuilder()
209          .SetCompilationPackage("com.app.test")
210          .SetPackageId(0x7f)
211          .SetNameManglerPolicy(
212              NameManglerPolicy{"com.app.test", {"com.app.lib"}})
213          .AddSymbolSource(
214              util::make_unique<ResourceTableSymbolSource>(table.get()))
215          .AddSymbolSource(
216              test::StaticSymbolSourceBuilder()
217                  .AddSymbol("com.app.test:string/com.app.lib$hidden",
218                             ResourceId(0x7f040034))
219                  .Build())
220
221          .Build();
222
223  ReferenceLinker linker;
224  ASSERT_FALSE(linker.Consume(context.get(), table.get()));
225}
226
227TEST(ReferenceLinkerTest, FailToLinkPrivateStyleAttributes) {
228  std::unique_ptr<ResourceTable> table =
229      test::ResourceTableBuilder()
230          .SetPackageId("com.app.test", 0x7f)
231          .AddValue("com.app.test:style/Theme",
232                    test::StyleBuilder()
233                        .AddItem("android:attr/hidden",
234                                 ResourceUtils::TryParseColor("#ff00ff"))
235                        .Build())
236          .Build();
237
238  std::unique_ptr<IAaptContext> context =
239      test::ContextBuilder()
240          .SetCompilationPackage("com.app.test")
241          .SetPackageId(0x7f)
242          .SetNameManglerPolicy(NameManglerPolicy{"com.app.test"})
243          .AddSymbolSource(
244              util::make_unique<ResourceTableSymbolSource>(table.get()))
245          .AddSymbolSource(
246              test::StaticSymbolSourceBuilder()
247                  .AddSymbol("android:attr/hidden", ResourceId(0x01010001),
248                             test::AttributeBuilder()
249                                 .SetTypeMask(android::ResTable_map::TYPE_COLOR)
250                                 .Build())
251                  .Build())
252          .Build();
253
254  ReferenceLinker linker;
255  ASSERT_FALSE(linker.Consume(context.get(), table.get()));
256}
257
258TEST(ReferenceLinkerTest, AppsWithSamePackageButDifferentIdAreVisibleNonPublic) {
259  NameMangler mangler(NameManglerPolicy{"com.app.test"});
260  SymbolTable table(&mangler);
261  table.AppendSource(test::StaticSymbolSourceBuilder()
262                         .AddSymbol("com.app.test:string/foo", ResourceId(0x7f010000))
263                         .Build());
264
265  std::string error;
266  const CallSite call_site{ResourceNameRef("com.app.test", ResourceType::kString, "foo")};
267  const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveSymbolCheckVisibility(
268      *test::BuildReference("com.app.test:string/foo"), call_site, &table, &error);
269  ASSERT_NE(nullptr, symbol);
270  EXPECT_TRUE(error.empty());
271}
272
273TEST(ReferenceLinkerTest, AppsWithDifferentPackageCanNotUseEachOthersAttribute) {
274  NameMangler mangler(NameManglerPolicy{"com.app.ext"});
275  SymbolTable table(&mangler);
276  table.AppendSource(test::StaticSymbolSourceBuilder()
277                         .AddSymbol("com.app.test:attr/foo", ResourceId(0x7f010000),
278                                    test::AttributeBuilder().Build())
279                         .AddPublicSymbol("com.app.test:attr/public_foo", ResourceId(0x7f010001),
280                                          test::AttributeBuilder().Build())
281                         .Build());
282
283  std::string error;
284  const CallSite call_site{ResourceNameRef("com.app.ext", ResourceType::kLayout, "foo")};
285
286  AAPT_EXPECT_FALSE(ReferenceLinker::CompileXmlAttribute(
287      *test::BuildReference("com.app.test:attr/foo"), call_site, &table, &error));
288  EXPECT_FALSE(error.empty());
289
290  error = "";
291  AAPT_ASSERT_TRUE(ReferenceLinker::CompileXmlAttribute(
292      *test::BuildReference("com.app.test:attr/public_foo"), call_site, &table, &error));
293  EXPECT_TRUE(error.empty());
294}
295
296}  // namespace aapt
297