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 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 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 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 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 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 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 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 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. 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 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 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 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 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 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