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 21using ::testing::Eq; 22using ::testing::SizeIs; 23using ::testing::StrEq; 24 25namespace aapt { 26 27TEST(ResourceValuesTest, PluralEquals) { 28 StringPool pool; 29 30 Plural a; 31 a.values[Plural::One] = util::make_unique<String>(pool.MakeRef("one")); 32 a.values[Plural::Other] = util::make_unique<String>(pool.MakeRef("other")); 33 34 Plural b; 35 b.values[Plural::One] = util::make_unique<String>(pool.MakeRef("une")); 36 b.values[Plural::Other] = util::make_unique<String>(pool.MakeRef("autre")); 37 38 Plural c; 39 c.values[Plural::One] = util::make_unique<String>(pool.MakeRef("one")); 40 c.values[Plural::Other] = util::make_unique<String>(pool.MakeRef("other")); 41 42 EXPECT_FALSE(a.Equals(&b)); 43 EXPECT_TRUE(a.Equals(&c)); 44} 45 46TEST(ResourceValuesTest, PluralClone) { 47 StringPool pool; 48 49 Plural a; 50 a.values[Plural::One] = util::make_unique<String>(pool.MakeRef("one")); 51 a.values[Plural::Other] = util::make_unique<String>(pool.MakeRef("other")); 52 53 std::unique_ptr<Plural> b(a.Clone(&pool)); 54 EXPECT_TRUE(a.Equals(b.get())); 55} 56 57TEST(ResourceValuesTest, ArrayEquals) { 58 StringPool pool; 59 60 Array a; 61 a.elements.push_back(util::make_unique<String>(pool.MakeRef("one"))); 62 a.elements.push_back(util::make_unique<String>(pool.MakeRef("two"))); 63 64 Array b; 65 b.elements.push_back(util::make_unique<String>(pool.MakeRef("une"))); 66 b.elements.push_back(util::make_unique<String>(pool.MakeRef("deux"))); 67 68 Array c; 69 c.elements.push_back(util::make_unique<String>(pool.MakeRef("uno"))); 70 71 Array d; 72 d.elements.push_back(util::make_unique<String>(pool.MakeRef("one"))); 73 d.elements.push_back(util::make_unique<String>(pool.MakeRef("two"))); 74 75 EXPECT_FALSE(a.Equals(&b)); 76 EXPECT_FALSE(a.Equals(&c)); 77 EXPECT_FALSE(b.Equals(&c)); 78 EXPECT_TRUE(a.Equals(&d)); 79} 80 81TEST(ResourceValuesTest, ArrayClone) { 82 StringPool pool; 83 84 Array a; 85 a.elements.push_back(util::make_unique<String>(pool.MakeRef("one"))); 86 a.elements.push_back(util::make_unique<String>(pool.MakeRef("two"))); 87 88 std::unique_ptr<Array> b(a.Clone(&pool)); 89 EXPECT_TRUE(a.Equals(b.get())); 90} 91 92TEST(ResourceValuesTest, StyleEquals) { 93 StringPool pool; 94 95 std::unique_ptr<Style> a = test::StyleBuilder() 96 .SetParent("android:style/Parent") 97 .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1")) 98 .AddItem("android:attr/bar", ResourceUtils::TryParseInt("2")) 99 .Build(); 100 101 std::unique_ptr<Style> b = test::StyleBuilder() 102 .SetParent("android:style/Parent") 103 .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1")) 104 .AddItem("android:attr/bar", ResourceUtils::TryParseInt("3")) 105 .Build(); 106 107 std::unique_ptr<Style> c = test::StyleBuilder() 108 .SetParent("android:style/NoParent") 109 .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1")) 110 .AddItem("android:attr/bar", ResourceUtils::TryParseInt("2")) 111 .Build(); 112 113 std::unique_ptr<Style> d = test::StyleBuilder() 114 .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1")) 115 .AddItem("android:attr/bar", ResourceUtils::TryParseInt("2")) 116 .Build(); 117 118 std::unique_ptr<Style> e = test::StyleBuilder() 119 .SetParent("android:style/Parent") 120 .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1")) 121 .AddItem("android:attr/bat", ResourceUtils::TryParseInt("2")) 122 .Build(); 123 124 std::unique_ptr<Style> f = test::StyleBuilder() 125 .SetParent("android:style/Parent") 126 .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1")) 127 .Build(); 128 129 std::unique_ptr<Style> g = test::StyleBuilder() 130 .SetParent("android:style/Parent") 131 .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1")) 132 .AddItem("android:attr/bar", ResourceUtils::TryParseInt("2")) 133 .Build(); 134 135 EXPECT_FALSE(a->Equals(b.get())); 136 EXPECT_FALSE(a->Equals(c.get())); 137 EXPECT_FALSE(a->Equals(d.get())); 138 EXPECT_FALSE(a->Equals(e.get())); 139 EXPECT_FALSE(a->Equals(f.get())); 140 141 EXPECT_TRUE(a->Equals(g.get())); 142} 143 144TEST(ResourceValuesTest, StyleClone) { 145 std::unique_ptr<Style> a = test::StyleBuilder() 146 .SetParent("android:style/Parent") 147 .AddItem("android:attr/foo", ResourceUtils::TryParseInt("1")) 148 .AddItem("android:attr/bar", ResourceUtils::TryParseInt("2")) 149 .Build(); 150 151 std::unique_ptr<Style> b(a->Clone(nullptr)); 152 EXPECT_TRUE(a->Equals(b.get())); 153} 154 155TEST(ResourcesValuesTest, StringClones) { 156 StringPool pool_a; 157 StringPool pool_b; 158 159 String str_a(pool_a.MakeRef("hello", StringPool::Context(test::ParseConfigOrDie("en")))); 160 161 ASSERT_THAT(pool_a, SizeIs(1u)); 162 EXPECT_THAT(pool_a.strings()[0]->context.config, Eq(test::ParseConfigOrDie("en"))); 163 EXPECT_THAT(pool_a.strings()[0]->value, StrEq("hello")); 164 165 std::unique_ptr<String> str_b(str_a.Clone(&pool_b)); 166 ASSERT_THAT(pool_b, SizeIs(1u)); 167 EXPECT_THAT(pool_b.strings()[0]->context.config, Eq(test::ParseConfigOrDie("en"))); 168 EXPECT_THAT(pool_b.strings()[0]->value, StrEq("hello")); 169} 170 171TEST(ResourceValuesTest, StyleMerges) { 172 StringPool pool_a; 173 StringPool pool_b; 174 175 std::unique_ptr<Style> a = 176 test::StyleBuilder() 177 .SetParent("android:style/Parent") 178 .AddItem("android:attr/a", util::make_unique<String>(pool_a.MakeRef("FooA"))) 179 .AddItem("android:attr/b", util::make_unique<String>(pool_a.MakeRef("FooB"))) 180 .Build(); 181 182 std::unique_ptr<Style> b = 183 test::StyleBuilder() 184 .SetParent("android:style/OverlayParent") 185 .AddItem("android:attr/c", util::make_unique<String>(pool_b.MakeRef("OverlayFooC"))) 186 .AddItem("android:attr/a", util::make_unique<String>(pool_b.MakeRef("OverlayFooA"))) 187 .Build(); 188 189 a->MergeWith(b.get(), &pool_a); 190 191 StringPool pool; 192 std::unique_ptr<Style> expected = 193 test::StyleBuilder() 194 .SetParent("android:style/OverlayParent") 195 .AddItem("android:attr/a", util::make_unique<String>(pool.MakeRef("OverlayFooA"))) 196 .AddItem("android:attr/b", util::make_unique<String>(pool.MakeRef("FooB"))) 197 .AddItem("android:attr/c", util::make_unique<String>(pool.MakeRef("OverlayFooC"))) 198 .Build(); 199 200 EXPECT_TRUE(a->Equals(expected.get())); 201} 202 203// TYPE_NULL is encoded as TYPE_REFERENCE with a value of 0. This is represented in AAPT2 204// by a default constructed Reference value. 205TEST(ResourcesValuesTest, EmptyReferenceFlattens) { 206 android::Res_value value = {}; 207 ASSERT_TRUE(Reference().Flatten(&value)); 208 209 EXPECT_EQ(android::Res_value::TYPE_REFERENCE, value.dataType); 210 EXPECT_EQ(0x0u, value.data); 211} 212 213TEST(ResourcesValuesTest, AttributeMatches) { 214 constexpr const uint32_t TYPE_DIMENSION = android::ResTable_map::TYPE_DIMENSION; 215 constexpr const uint32_t TYPE_ENUM = android::ResTable_map::TYPE_ENUM; 216 constexpr const uint32_t TYPE_FLAGS = android::ResTable_map::TYPE_FLAGS; 217 constexpr const uint32_t TYPE_INTEGER = android::ResTable_map::TYPE_INTEGER; 218 constexpr const uint8_t TYPE_INT_DEC = android::Res_value::TYPE_INT_DEC; 219 220 Attribute attr1(false /*weak*/, TYPE_DIMENSION); 221 EXPECT_FALSE(attr1.Matches(*ResourceUtils::TryParseColor("#7fff00"))); 222 EXPECT_TRUE(attr1.Matches(*ResourceUtils::TryParseFloat("23dp"))); 223 EXPECT_TRUE(attr1.Matches(*ResourceUtils::TryParseReference("@android:string/foo"))); 224 225 Attribute attr2(false /*weak*/, TYPE_INTEGER | TYPE_ENUM); 226 attr2.min_int = 0; 227 attr2.symbols.push_back(Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 228 static_cast<uint32_t>(-1)}); 229 EXPECT_FALSE(attr2.Matches(*ResourceUtils::TryParseColor("#7fff00"))); 230 EXPECT_TRUE(attr2.Matches(BinaryPrimitive(TYPE_INT_DEC, static_cast<uint32_t>(-1)))); 231 EXPECT_TRUE(attr2.Matches(BinaryPrimitive(TYPE_INT_DEC, 1u))); 232 EXPECT_FALSE(attr2.Matches(BinaryPrimitive(TYPE_INT_DEC, static_cast<uint32_t>(-2)))); 233 234 Attribute attr3(false /*weak*/, TYPE_INTEGER | TYPE_FLAGS); 235 attr3.max_int = 100; 236 attr3.symbols.push_back( 237 Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u}); 238 attr3.symbols.push_back( 239 Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x02u}); 240 attr3.symbols.push_back( 241 Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/baz")), 0x04u}); 242 attr3.symbols.push_back( 243 Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bat")), 0x80u}); 244 EXPECT_FALSE(attr3.Matches(*ResourceUtils::TryParseColor("#7fff00"))); 245 EXPECT_TRUE(attr3.Matches(BinaryPrimitive(TYPE_INT_DEC, 0x01u | 0x02u))); 246 EXPECT_TRUE(attr3.Matches(BinaryPrimitive(TYPE_INT_DEC, 0x01u | 0x02u | 0x80u))); 247 248 // Not a flag, but a value less than max_int. 249 EXPECT_TRUE(attr3.Matches(BinaryPrimitive(TYPE_INT_DEC, 0x08u))); 250 251 // Not a flag and greater than max_int. 252 EXPECT_FALSE(attr3.Matches(BinaryPrimitive(TYPE_INT_DEC, 127u))); 253 254 Attribute attr4(false /*weak*/, TYPE_ENUM); 255 attr4.symbols.push_back( 256 Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u}); 257 EXPECT_TRUE(attr4.Matches(BinaryPrimitive(TYPE_INT_DEC, 0x01u))); 258 EXPECT_FALSE(attr4.Matches(BinaryPrimitive(TYPE_INT_DEC, 0x02u))); 259} 260 261} // namespace aapt 262