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#include "test/Test.h"
19
20using android::ResTable_map;
21
22namespace aapt {
23
24TEST(ReferenceLinkerTest, LinkSimpleReferences) {
25    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
26            .setPackageId(u"com.app.test", 0x7f)
27            .addReference(u"@com.app.test:string/foo", ResourceId(0x7f020000),
28                          u"@com.app.test:string/bar")
29
30            // Test use of local reference (w/o package name).
31            .addReference(u"@com.app.test:string/bar", ResourceId(0x7f020001), u"@string/baz")
32
33            .addReference(u"@com.app.test:string/baz", ResourceId(0x7f020002),
34                          u"@android:string/ok")
35            .build();
36
37    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
38            .setCompilationPackage(u"com.app.test")
39            .setPackageId(0x7f)
40            .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
41            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
42            .addSymbolSource(test::StaticSymbolSourceBuilder()
43                                     .addPublicSymbol(u"@android:string/ok", ResourceId(0x01040034))
44                                     .build())
45            .build();
46
47    ReferenceLinker linker;
48    ASSERT_TRUE(linker.consume(context.get(), table.get()));
49
50    Reference* ref = test::getValue<Reference>(table.get(), u"@com.app.test:string/foo");
51    ASSERT_NE(ref, nullptr);
52    AAPT_ASSERT_TRUE(ref->id);
53    EXPECT_EQ(ref->id.value(), ResourceId(0x7f020001));
54
55    ref = test::getValue<Reference>(table.get(), u"@com.app.test:string/bar");
56    ASSERT_NE(ref, nullptr);
57    AAPT_ASSERT_TRUE(ref->id);
58    EXPECT_EQ(ref->id.value(), ResourceId(0x7f020002));
59
60    ref = test::getValue<Reference>(table.get(), u"@com.app.test:string/baz");
61    ASSERT_NE(ref, nullptr);
62    AAPT_ASSERT_TRUE(ref->id);
63    EXPECT_EQ(ref->id.value(), ResourceId(0x01040034));
64}
65
66TEST(ReferenceLinkerTest, LinkStyleAttributes) {
67    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
68            .setPackageId(u"com.app.test", 0x7f)
69            .addValue(u"@com.app.test:style/Theme", test::StyleBuilder()
70                    .setParent(u"@android:style/Theme.Material")
71                    .addItem(u"@android:attr/foo", ResourceUtils::tryParseColor(u"#ff00ff"))
72                    .addItem(u"@android:attr/bar", {} /* placeholder */)
73                    .build())
74            .build();
75
76    {
77        // We need to fill in the value for the attribute android:attr/bar after we build the
78        // table, because we need access to the string pool.
79        Style* style = test::getValue<Style>(table.get(), u"@com.app.test:style/Theme");
80        ASSERT_NE(style, nullptr);
81        style->entries.back().value = util::make_unique<RawString>(
82                table->stringPool.makeRef(u"one|two"));
83    }
84
85    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
86            .setCompilationPackage(u"com.app.test")
87            .setPackageId(0x7f)
88            .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
89            .addSymbolSource(test::StaticSymbolSourceBuilder()
90                                     .addPublicSymbol(u"@android:style/Theme.Material",
91                                                      ResourceId(0x01060000))
92                                     .addPublicSymbol(u"@android:attr/foo", ResourceId(0x01010001),
93                                                      test::AttributeBuilder()
94                                                              .setTypeMask(ResTable_map::TYPE_COLOR)
95                                                              .build())
96                                     .addPublicSymbol(u"@android:attr/bar", ResourceId(0x01010002),
97                                                      test::AttributeBuilder()
98                                                              .setTypeMask(ResTable_map::TYPE_FLAGS)
99                                                              .addItem(u"one", 0x01)
100                                                              .addItem(u"two", 0x02)
101                                                              .build())
102                                     .build())
103            .build();
104
105    ReferenceLinker linker;
106    ASSERT_TRUE(linker.consume(context.get(), table.get()));
107
108    Style* style = test::getValue<Style>(table.get(), u"@com.app.test:style/Theme");
109    ASSERT_NE(style, nullptr);
110    AAPT_ASSERT_TRUE(style->parent);
111    AAPT_ASSERT_TRUE(style->parent.value().id);
112    EXPECT_EQ(style->parent.value().id.value(), ResourceId(0x01060000));
113
114    ASSERT_EQ(2u, style->entries.size());
115
116    AAPT_ASSERT_TRUE(style->entries[0].key.id);
117    EXPECT_EQ(style->entries[0].key.id.value(), ResourceId(0x01010001));
118    ASSERT_NE(valueCast<BinaryPrimitive>(style->entries[0].value.get()), nullptr);
119
120    AAPT_ASSERT_TRUE(style->entries[1].key.id);
121    EXPECT_EQ(style->entries[1].key.id.value(), ResourceId(0x01010002));
122    ASSERT_NE(valueCast<BinaryPrimitive>(style->entries[1].value.get()), nullptr);
123}
124
125TEST(ReferenceLinkerTest, LinkMangledReferencesAndAttributes) {
126    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
127            .setCompilationPackage(u"com.app.test")
128            .setPackageId(0x7f)
129            .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test", { u"com.android.support" } })
130            .addSymbolSource(test::StaticSymbolSourceBuilder()
131                                     .addPublicSymbol(u"@com.app.test:attr/com.android.support$foo",
132                                                      ResourceId(0x7f010000),
133                                                      test::AttributeBuilder()
134                                                              .setTypeMask(ResTable_map::TYPE_COLOR)
135                                                              .build())
136                                     .build())
137            .build();
138
139    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
140            .setPackageId(u"com.app.test", 0x7f)
141            .addValue(u"@com.app.test:style/Theme", ResourceId(0x7f020000),
142                      test::StyleBuilder().addItem(u"@com.android.support:attr/foo",
143                                                   ResourceUtils::tryParseColor(u"#ff0000"))
144                                          .build())
145            .build();
146
147    ReferenceLinker linker;
148    ASSERT_TRUE(linker.consume(context.get(), table.get()));
149
150    Style* style = test::getValue<Style>(table.get(), u"@com.app.test:style/Theme");
151    ASSERT_NE(style, nullptr);
152    ASSERT_EQ(1u, style->entries.size());
153    AAPT_ASSERT_TRUE(style->entries.front().key.id);
154    EXPECT_EQ(style->entries.front().key.id.value(), ResourceId(0x7f010000));
155}
156
157TEST(ReferenceLinkerTest, FailToLinkPrivateSymbols) {
158    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
159            .setPackageId(u"com.app.test", 0x7f)
160            .addReference(u"@com.app.test:string/foo", ResourceId(0x7f020000),
161                          u"@android:string/hidden")
162            .build();
163
164    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
165            .setCompilationPackage(u"com.app.test")
166            .setPackageId(0x7f)
167            .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
168            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
169            .addSymbolSource(test::StaticSymbolSourceBuilder()
170                                     .addSymbol(u"@android:string/hidden", ResourceId(0x01040034))
171                                     .build())
172            .build();
173
174    ReferenceLinker linker;
175    ASSERT_FALSE(linker.consume(context.get(), table.get()));
176}
177
178TEST(ReferenceLinkerTest, FailToLinkPrivateMangledSymbols) {
179    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
180            .setPackageId(u"com.app.test", 0x7f)
181            .addReference(u"@com.app.test:string/foo", ResourceId(0x7f020000),
182                          u"@com.app.lib:string/hidden")
183            .build();
184
185    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
186            .setCompilationPackage(u"com.app.test")
187            .setPackageId(0x7f)
188            .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test", { u"com.app.lib" } })
189            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
190            .addSymbolSource(test::StaticSymbolSourceBuilder()
191                                     .addSymbol(u"@com.app.test:string/com.app.lib$hidden",
192                                                ResourceId(0x7f040034))
193                                     .build())
194
195            .build();
196
197    ReferenceLinker linker;
198    ASSERT_FALSE(linker.consume(context.get(), table.get()));
199}
200
201TEST(ReferenceLinkerTest, FailToLinkPrivateStyleAttributes) {
202    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
203            .setPackageId(u"com.app.test", 0x7f)
204            .addValue(u"@com.app.test:style/Theme", test::StyleBuilder()
205                    .addItem(u"@android:attr/hidden", ResourceUtils::tryParseColor(u"#ff00ff"))
206                    .build())
207            .build();
208
209    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
210            .setCompilationPackage(u"com.app.test")
211            .setPackageId(0x7f)
212            .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
213            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
214            .addSymbolSource(test::StaticSymbolSourceBuilder()
215                                     .addSymbol(u"@android:attr/hidden", ResourceId(0x01010001),
216                                                test::AttributeBuilder()
217                                                        .setTypeMask(
218                                                                android::ResTable_map::TYPE_COLOR)
219                                                        .build())
220                                     .build())
221            .build();
222
223    ReferenceLinker linker;
224    ASSERT_FALSE(linker.consume(context.get(), table.get()));
225}
226
227} // namespace aapt
228