1 /*
2  * Copyright (C) 2017 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 "ResourceValues.h"
18 
19 #include "test/Test.h"
20 
21 using ::testing::Eq;
22 using ::testing::SizeIs;
23 using ::testing::StrEq;
24 
25 namespace aapt {
26 
27 namespace {
28 
29 // Attribute types.
30 constexpr const uint32_t TYPE_DIMENSION = android::ResTable_map::TYPE_DIMENSION;
31 constexpr const uint32_t TYPE_ENUM = android::ResTable_map::TYPE_ENUM;
32 constexpr const uint32_t TYPE_FLAGS = android::ResTable_map::TYPE_FLAGS;
33 constexpr const uint32_t TYPE_INTEGER = android::ResTable_map::TYPE_INTEGER;
34 constexpr const uint32_t TYPE_REFERENCE = android::Res_value::TYPE_REFERENCE;
35 constexpr const uint32_t TYPE_STRING = android::ResTable_map::TYPE_STRING;
36 
37 }  // namespace
38 
TEST(ResourceValuesTest,PluralEquals)39 TEST(ResourceValuesTest, PluralEquals) {
40   StringPool pool;
41 
42   Plural a;
43   a.values[Plural::One] = util::make_unique<String>(pool.MakeRef("one"));
44   a.values[Plural::Other] = util::make_unique<String>(pool.MakeRef("other"));
45 
46   Plural b;
47   b.values[Plural::One] = util::make_unique<String>(pool.MakeRef("une"));
48   b.values[Plural::Other] = util::make_unique<String>(pool.MakeRef("autre"));
49 
50   Plural c;
51   c.values[Plural::One] = util::make_unique<String>(pool.MakeRef("one"));
52   c.values[Plural::Other] = util::make_unique<String>(pool.MakeRef("other"));
53 
54   EXPECT_FALSE(a.Equals(&b));
55   EXPECT_TRUE(a.Equals(&c));
56 }
57 
TEST(ResourceValuesTest,PluralClone)58 TEST(ResourceValuesTest, PluralClone) {
59   StringPool pool;
60 
61   Plural a;
62   a.values[Plural::One] = util::make_unique<String>(pool.MakeRef("one"));
63   a.values[Plural::Other] = util::make_unique<String>(pool.MakeRef("other"));
64 
65   std::unique_ptr<Plural> b(a.Clone(&pool));
66   EXPECT_TRUE(a.Equals(b.get()));
67 }
68 
TEST(ResourceValuesTest,ArrayEquals)69 TEST(ResourceValuesTest, ArrayEquals) {
70   StringPool pool;
71 
72   Array a;
73   a.elements.push_back(util::make_unique<String>(pool.MakeRef("one")));
74   a.elements.push_back(util::make_unique<String>(pool.MakeRef("two")));
75 
76   Array b;
77   b.elements.push_back(util::make_unique<String>(pool.MakeRef("une")));
78   b.elements.push_back(util::make_unique<String>(pool.MakeRef("deux")));
79 
80   Array c;
81   c.elements.push_back(util::make_unique<String>(pool.MakeRef("uno")));
82 
83   Array d;
84   d.elements.push_back(util::make_unique<String>(pool.MakeRef("one")));
85   d.elements.push_back(util::make_unique<String>(pool.MakeRef("two")));
86 
87   EXPECT_FALSE(a.Equals(&b));
88   EXPECT_FALSE(a.Equals(&c));
89   EXPECT_FALSE(b.Equals(&c));
90   EXPECT_TRUE(a.Equals(&d));
91 }
92 
TEST(ResourceValuesTest,ArrayClone)93 TEST(ResourceValuesTest, ArrayClone) {
94   StringPool pool;
95 
96   Array a;
97   a.elements.push_back(util::make_unique<String>(pool.MakeRef("one")));
98   a.elements.push_back(util::make_unique<String>(pool.MakeRef("two")));
99 
100   std::unique_ptr<Array> b(a.Clone(&pool));
101   EXPECT_TRUE(a.Equals(b.get()));
102 }
103 
TEST(ResourceValuesTest,StyleEquals)104 TEST(ResourceValuesTest, StyleEquals) {
105   StringPool pool;
106 
107   std::unique_ptr<Style> a = test::StyleBuilder()
108       .SetParent("android:style/Parent")
109       .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1"))
110       .AddItem("android:attr/bar", ResourceUtils::TryParseInt("2"))
111       .Build();
112 
113   std::unique_ptr<Style> b = test::StyleBuilder()
114       .SetParent("android:style/Parent")
115       .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1"))
116       .AddItem("android:attr/bar", ResourceUtils::TryParseInt("3"))
117       .Build();
118 
119   std::unique_ptr<Style> c = test::StyleBuilder()
120       .SetParent("android:style/NoParent")
121       .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1"))
122       .AddItem("android:attr/bar", ResourceUtils::TryParseInt("2"))
123       .Build();
124 
125   std::unique_ptr<Style> d = test::StyleBuilder()
126       .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1"))
127       .AddItem("android:attr/bar", ResourceUtils::TryParseInt("2"))
128       .Build();
129 
130   std::unique_ptr<Style> e = test::StyleBuilder()
131       .SetParent("android:style/Parent")
132       .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1"))
133       .AddItem("android:attr/bat", ResourceUtils::TryParseInt("2"))
134       .Build();
135 
136   std::unique_ptr<Style> f = test::StyleBuilder()
137       .SetParent("android:style/Parent")
138       .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1"))
139       .Build();
140 
141   std::unique_ptr<Style> g = test::StyleBuilder()
142       .SetParent("android:style/Parent")
143       .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1"))
144       .AddItem("android:attr/bar", ResourceUtils::TryParseInt("2"))
145       .Build();
146 
147   EXPECT_FALSE(a->Equals(b.get()));
148   EXPECT_FALSE(a->Equals(c.get()));
149   EXPECT_FALSE(a->Equals(d.get()));
150   EXPECT_FALSE(a->Equals(e.get()));
151   EXPECT_FALSE(a->Equals(f.get()));
152 
153   EXPECT_TRUE(a->Equals(g.get()));
154 }
155 
TEST(ResourceValuesTest,StyleClone)156 TEST(ResourceValuesTest, StyleClone) {
157   std::unique_ptr<Style> a = test::StyleBuilder()
158       .SetParent("android:style/Parent")
159       .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1"))
160       .AddItem("android:attr/bar", ResourceUtils::TryParseInt("2"))
161       .Build();
162 
163   std::unique_ptr<Style> b(a->Clone(nullptr));
164   EXPECT_TRUE(a->Equals(b.get()));
165 }
166 
TEST(ResourcesValuesTest,StringClones)167 TEST(ResourcesValuesTest, StringClones) {
168   StringPool pool_a;
169   StringPool pool_b;
170 
171   String str_a(pool_a.MakeRef("hello", StringPool::Context(test::ParseConfigOrDie("en"))));
172 
173   ASSERT_THAT(pool_a, SizeIs(1u));
174   EXPECT_THAT(pool_a.strings()[0]->context.config, Eq(test::ParseConfigOrDie("en")));
175   EXPECT_THAT(pool_a.strings()[0]->value, StrEq("hello"));
176 
177   std::unique_ptr<String> str_b(str_a.Clone(&pool_b));
178   ASSERT_THAT(pool_b, SizeIs(1u));
179   EXPECT_THAT(pool_b.strings()[0]->context.config, Eq(test::ParseConfigOrDie("en")));
180   EXPECT_THAT(pool_b.strings()[0]->value, StrEq("hello"));
181 }
182 
TEST(ResourceValuesTest,StyleMerges)183 TEST(ResourceValuesTest, StyleMerges) {
184   StringPool pool_a;
185   StringPool pool_b;
186 
187   std::unique_ptr<Style> a =
188       test::StyleBuilder()
189           .SetParent("android:style/Parent")
190           .AddItem("android:attr/a", util::make_unique<String>(pool_a.MakeRef("FooA")))
191           .AddItem("android:attr/b", util::make_unique<String>(pool_a.MakeRef("FooB")))
192           .Build();
193 
194   std::unique_ptr<Style> b =
195       test::StyleBuilder()
196           .SetParent("android:style/OverlayParent")
197           .AddItem("android:attr/c", util::make_unique<String>(pool_b.MakeRef("OverlayFooC")))
198           .AddItem("android:attr/a", util::make_unique<String>(pool_b.MakeRef("OverlayFooA")))
199           .Build();
200 
201   a->MergeWith(b.get(), &pool_a);
202 
203   StringPool pool;
204   std::unique_ptr<Style> expected =
205       test::StyleBuilder()
206           .SetParent("android:style/OverlayParent")
207           .AddItem("android:attr/a", util::make_unique<String>(pool.MakeRef("OverlayFooA")))
208           .AddItem("android:attr/b", util::make_unique<String>(pool.MakeRef("FooB")))
209           .AddItem("android:attr/c", util::make_unique<String>(pool.MakeRef("OverlayFooC")))
210           .Build();
211 
212   EXPECT_TRUE(a->Equals(expected.get()));
213 }
214 
215 // TYPE_NULL is encoded as TYPE_REFERENCE with a value of 0. This is represented in AAPT2
216 // by a default constructed Reference value.
TEST(ResourcesValuesTest,EmptyReferenceFlattens)217 TEST(ResourcesValuesTest, EmptyReferenceFlattens) {
218   android::Res_value value = {};
219   ASSERT_TRUE(Reference().Flatten(&value));
220 
221   EXPECT_THAT(value.dataType, Eq(android::Res_value::TYPE_REFERENCE));
222   EXPECT_THAT(value.data, Eq(0u));
223 }
224 
TEST(ResourcesValuesTest,AttributeMatches)225 TEST(ResourcesValuesTest, AttributeMatches) {
226   constexpr const uint8_t TYPE_INT_DEC = android::Res_value::TYPE_INT_DEC;
227 
228   Attribute attr1(TYPE_DIMENSION);
229   EXPECT_FALSE(attr1.Matches(*ResourceUtils::TryParseColor("#7fff00")));
230   EXPECT_TRUE(attr1.Matches(*ResourceUtils::TryParseFloat("23dp")));
231   EXPECT_TRUE(attr1.Matches(*ResourceUtils::TryParseReference("@android:string/foo")));
232 
233   Attribute attr2(TYPE_INTEGER | TYPE_ENUM);
234   attr2.min_int = 0;
235   attr2.symbols.push_back(Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")),
236                                             static_cast<uint32_t>(-1)});
237   EXPECT_FALSE(attr2.Matches(*ResourceUtils::TryParseColor("#7fff00")));
238   EXPECT_TRUE(attr2.Matches(BinaryPrimitive(TYPE_INT_DEC, static_cast<uint32_t>(-1))));
239   EXPECT_TRUE(attr2.Matches(BinaryPrimitive(TYPE_INT_DEC, 1u)));
240   EXPECT_FALSE(attr2.Matches(BinaryPrimitive(TYPE_INT_DEC, static_cast<uint32_t>(-2))));
241 
242   Attribute attr3(TYPE_INTEGER | TYPE_FLAGS);
243   attr3.max_int = 100;
244   attr3.symbols.push_back(
245       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
246   attr3.symbols.push_back(
247       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x02u});
248   attr3.symbols.push_back(
249       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/baz")), 0x04u});
250   attr3.symbols.push_back(
251       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bat")), 0x80u});
252   EXPECT_FALSE(attr3.Matches(*ResourceUtils::TryParseColor("#7fff00")));
253   EXPECT_TRUE(attr3.Matches(BinaryPrimitive(TYPE_INT_DEC, 0x01u | 0x02u)));
254   EXPECT_TRUE(attr3.Matches(BinaryPrimitive(TYPE_INT_DEC, 0x01u | 0x02u | 0x80u)));
255 
256   // Not a flag, but a value less than max_int.
257   EXPECT_TRUE(attr3.Matches(BinaryPrimitive(TYPE_INT_DEC, 0x08u)));
258 
259   // Not a flag and greater than max_int.
260   EXPECT_FALSE(attr3.Matches(BinaryPrimitive(TYPE_INT_DEC, 127u)));
261 
262   Attribute attr4(TYPE_ENUM);
263   attr4.symbols.push_back(
264       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
265   EXPECT_TRUE(attr4.Matches(BinaryPrimitive(TYPE_INT_DEC, 0x01u)));
266   EXPECT_FALSE(attr4.Matches(BinaryPrimitive(TYPE_INT_DEC, 0x02u)));
267 }
268 
TEST(ResourcesValuesTest,AttributeIsCompatible)269 TEST(ResourcesValuesTest, AttributeIsCompatible) {
270   Attribute attr_one(TYPE_STRING | TYPE_REFERENCE);
271   Attribute attr_two(TYPE_STRING);
272   Attribute attr_three(TYPE_ENUM);
273   Attribute attr_four(TYPE_REFERENCE);
274 
275   EXPECT_TRUE(attr_one.IsCompatibleWith(attr_one));
276   EXPECT_TRUE(attr_one.IsCompatibleWith(attr_two));
277   EXPECT_FALSE(attr_one.IsCompatibleWith(attr_three));
278   EXPECT_FALSE(attr_one.IsCompatibleWith(attr_four));
279 
280   EXPECT_TRUE(attr_two.IsCompatibleWith(attr_one));
281   EXPECT_TRUE(attr_two.IsCompatibleWith(attr_two));
282   EXPECT_FALSE(attr_two.IsCompatibleWith(attr_three));
283   EXPECT_FALSE(attr_two.IsCompatibleWith(attr_four));
284 
285   EXPECT_FALSE(attr_three.IsCompatibleWith(attr_one));
286   EXPECT_FALSE(attr_three.IsCompatibleWith(attr_two));
287   EXPECT_TRUE(attr_three.IsCompatibleWith(attr_three));
288   EXPECT_FALSE(attr_three.IsCompatibleWith(attr_four));
289 
290   EXPECT_FALSE(attr_four.IsCompatibleWith(attr_one));
291   EXPECT_FALSE(attr_four.IsCompatibleWith(attr_two));
292   EXPECT_FALSE(attr_four.IsCompatibleWith(attr_three));
293   EXPECT_TRUE(attr_four.IsCompatibleWith(attr_four));
294 }
295 
TEST(ResourcesValuesTest,AttributeEnumIsCompatible)296 TEST(ResourcesValuesTest, AttributeEnumIsCompatible) {
297   Attribute attr_one(TYPE_ENUM);
298   attr_one.symbols.push_back(
299       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
300   attr_one.symbols.push_back(
301       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x07u});
302 
303   Attribute attr_two(TYPE_ENUM);
304   attr_two.symbols.push_back(
305       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
306   attr_two.symbols.push_back(
307       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x07u});
308   EXPECT_TRUE(attr_one.IsCompatibleWith(attr_two));
309 }
310 
TEST(ResourcesValuesTest,DifferentAttributeEnumDifferentNameIsNotCompatible)311 TEST(ResourcesValuesTest, DifferentAttributeEnumDifferentNameIsNotCompatible) {
312   Attribute attr_one(TYPE_ENUM);
313   attr_one.symbols.push_back(
314       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
315   attr_one.symbols.push_back(
316       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x07u});
317 
318   Attribute attr_two(TYPE_ENUM);
319   attr_two.symbols.push_back(
320       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
321   attr_one.symbols.push_back(
322       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/baz")), 0x07u});
323   EXPECT_FALSE(attr_one.IsCompatibleWith(attr_two));
324 }
325 
TEST(ResourcesValuesTest,DifferentAttributeEnumDifferentValueIsNotCompatible)326 TEST(ResourcesValuesTest, DifferentAttributeEnumDifferentValueIsNotCompatible) {
327   Attribute attr_one(TYPE_ENUM);
328   attr_one.symbols.push_back(
329       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
330   attr_one.symbols.push_back(
331       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x07u});
332 
333   Attribute attr_two(TYPE_ENUM);
334   attr_two.symbols.push_back(
335       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
336   attr_two.symbols.push_back(
337       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x09u});
338   EXPECT_FALSE(attr_one.IsCompatibleWith(attr_two));
339 }
340 
341 } // namespace aapt
342