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 "ResourceUtils.h"
18 
19 #include "SdkConstants.h"
20 #include "Resource.h"
21 #include "test/Test.h"
22 
23 using ::aapt::test::ValueEq;
24 using ::android::Res_value;
25 using ::android::ResTable_map;
26 using ::testing::Eq;
27 using ::testing::NotNull;
28 using ::testing::Pointee;
29 
30 namespace aapt {
31 
TEST(ResourceUtilsTest,ParseBool)32 TEST(ResourceUtilsTest, ParseBool) {
33   EXPECT_THAT(ResourceUtils::ParseBool("true"), Eq(Maybe<bool>(true)));
34   EXPECT_THAT(ResourceUtils::ParseBool("TRUE"), Eq(Maybe<bool>(true)));
35   EXPECT_THAT(ResourceUtils::ParseBool("True"), Eq(Maybe<bool>(true)));
36 
37   EXPECT_THAT(ResourceUtils::ParseBool("false"), Eq(Maybe<bool>(false)));
38   EXPECT_THAT(ResourceUtils::ParseBool("FALSE"), Eq(Maybe<bool>(false)));
39   EXPECT_THAT(ResourceUtils::ParseBool("False"), Eq(Maybe<bool>(false)));
40 
41   EXPECT_THAT(ResourceUtils::ParseBool(" False\n "), Eq(Maybe<bool>(false)));
42 }
43 
TEST(ResourceUtilsTest,ParseResourceName)44 TEST(ResourceUtilsTest, ParseResourceName) {
45   ResourceNameRef actual;
46   bool actual_priv = false;
47   EXPECT_TRUE(ResourceUtils::ParseResourceName("android:color/foo", &actual, &actual_priv));
48   EXPECT_THAT(actual, Eq(ResourceNameRef("android", ResourceType::kColor, "foo")));
49   EXPECT_FALSE(actual_priv);
50 
51   EXPECT_TRUE(ResourceUtils::ParseResourceName("color/foo", &actual, &actual_priv));
52   EXPECT_THAT(actual, Eq(ResourceNameRef({}, ResourceType::kColor, "foo")));
53   EXPECT_FALSE(actual_priv);
54 
55   EXPECT_TRUE(ResourceUtils::ParseResourceName("*android:color/foo", &actual, &actual_priv));
56   EXPECT_THAT(actual, Eq(ResourceNameRef("android", ResourceType::kColor, "foo")));
57   EXPECT_TRUE(actual_priv);
58 
59   EXPECT_FALSE(ResourceUtils::ParseResourceName(android::StringPiece(), &actual, &actual_priv));
60 }
61 
TEST(ResourceUtilsTest,ParseReferenceWithNoPackage)62 TEST(ResourceUtilsTest, ParseReferenceWithNoPackage) {
63   ResourceNameRef actual;
64   bool create = false;
65   bool private_ref = false;
66   EXPECT_TRUE(ResourceUtils::ParseReference("@color/foo", &actual, &create, &private_ref));
67   EXPECT_THAT(actual, Eq(ResourceNameRef({}, ResourceType::kColor, "foo")));
68   EXPECT_FALSE(create);
69   EXPECT_FALSE(private_ref);
70 }
71 
TEST(ResourceUtilsTest,ParseReferenceWithPackage)72 TEST(ResourceUtilsTest, ParseReferenceWithPackage) {
73   ResourceNameRef actual;
74   bool create = false;
75   bool private_ref = false;
76   EXPECT_TRUE(ResourceUtils::ParseReference("@android:color/foo", &actual, &create, &private_ref));
77   EXPECT_THAT(actual, Eq(ResourceNameRef("android", ResourceType::kColor, "foo")));
78   EXPECT_FALSE(create);
79   EXPECT_FALSE(private_ref);
80 }
81 
TEST(ResourceUtilsTest,ParseReferenceWithSurroundingWhitespace)82 TEST(ResourceUtilsTest, ParseReferenceWithSurroundingWhitespace) {
83   ResourceNameRef actual;
84   bool create = false;
85   bool private_ref = false;
86   EXPECT_TRUE(ResourceUtils::ParseReference("\t @android:color/foo\n \n\t", &actual, &create, &private_ref));
87   EXPECT_THAT(actual, Eq(ResourceNameRef("android", ResourceType::kColor, "foo")));
88   EXPECT_FALSE(create);
89   EXPECT_FALSE(private_ref);
90 }
91 
TEST(ResourceUtilsTest,ParseAutoCreateIdReference)92 TEST(ResourceUtilsTest, ParseAutoCreateIdReference) {
93   ResourceNameRef actual;
94   bool create = false;
95   bool private_ref = false;
96   EXPECT_TRUE(ResourceUtils::ParseReference("@+android:id/foo", &actual, &create, &private_ref));
97   EXPECT_THAT(actual, Eq(ResourceNameRef("android", ResourceType::kId, "foo")));
98   EXPECT_TRUE(create);
99   EXPECT_FALSE(private_ref);
100 }
101 
TEST(ResourceUtilsTest,ParsePrivateReference)102 TEST(ResourceUtilsTest, ParsePrivateReference) {
103   ResourceNameRef actual;
104   bool create = false;
105   bool private_ref = false;
106   EXPECT_TRUE(ResourceUtils::ParseReference("@*android:id/foo", &actual, &create, &private_ref));
107   EXPECT_THAT(actual, Eq(ResourceNameRef("android", ResourceType::kId, "foo")));
108   EXPECT_FALSE(create);
109   EXPECT_TRUE(private_ref);
110 }
111 
TEST(ResourceUtilsTest,FailToParseAutoCreateNonIdReference)112 TEST(ResourceUtilsTest, FailToParseAutoCreateNonIdReference) {
113   bool create = false;
114   bool private_ref = false;
115   ResourceNameRef actual;
116   EXPECT_FALSE(ResourceUtils::ParseReference("@+android:color/foo", &actual, &create, &private_ref));
117 }
118 
TEST(ResourceUtilsTest,ParseAttributeReferences)119 TEST(ResourceUtilsTest, ParseAttributeReferences) {
120   EXPECT_TRUE(ResourceUtils::IsAttributeReference("?android"));
121   EXPECT_TRUE(ResourceUtils::IsAttributeReference("?android:foo"));
122   EXPECT_TRUE(ResourceUtils::IsAttributeReference("?attr/foo"));
123   EXPECT_TRUE(ResourceUtils::IsAttributeReference("?android:attr/foo"));
124 }
125 
TEST(ResourceUtilsTest,FailParseIncompleteReference)126 TEST(ResourceUtilsTest, FailParseIncompleteReference) {
127   EXPECT_FALSE(ResourceUtils::IsAttributeReference("?style/foo"));
128   EXPECT_FALSE(ResourceUtils::IsAttributeReference("?android:style/foo"));
129   EXPECT_FALSE(ResourceUtils::IsAttributeReference("?android:"));
130   EXPECT_FALSE(ResourceUtils::IsAttributeReference("?android:attr/"));
131   EXPECT_FALSE(ResourceUtils::IsAttributeReference("?:attr/"));
132   EXPECT_FALSE(ResourceUtils::IsAttributeReference("?:attr/foo"));
133   EXPECT_FALSE(ResourceUtils::IsAttributeReference("?:/"));
134   EXPECT_FALSE(ResourceUtils::IsAttributeReference("?:/foo"));
135   EXPECT_FALSE(ResourceUtils::IsAttributeReference("?attr/"));
136   EXPECT_FALSE(ResourceUtils::IsAttributeReference("?/foo"));
137 }
138 
TEST(ResourceUtilsTest,ParseStyleParentReference)139 TEST(ResourceUtilsTest, ParseStyleParentReference) {
140   const ResourceName kAndroidStyleFooName("android", ResourceType::kStyle, "foo");
141   const ResourceName kStyleFooName({}, ResourceType::kStyle, "foo");
142 
143   std::string err_str;
144   Maybe<Reference> ref = ResourceUtils::ParseStyleParentReference("@android:style/foo", &err_str);
145   ASSERT_TRUE(ref);
146   EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName)));
147 
148   ref = ResourceUtils::ParseStyleParentReference("@style/foo", &err_str);
149   ASSERT_TRUE(ref);
150   EXPECT_THAT(ref.value().name, Eq(make_value(kStyleFooName)));
151 
152   ref = ResourceUtils::ParseStyleParentReference("?android:style/foo", &err_str);
153   ASSERT_TRUE(ref);
154   EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName)));
155 
156   ref = ResourceUtils::ParseStyleParentReference("?style/foo", &err_str);
157   ASSERT_TRUE(ref);
158   EXPECT_THAT(ref.value().name, Eq(make_value(kStyleFooName)));
159 
160   ref = ResourceUtils::ParseStyleParentReference("android:style/foo", &err_str);
161   ASSERT_TRUE(ref);
162   EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName)));
163 
164   ref = ResourceUtils::ParseStyleParentReference("android:foo", &err_str);
165   ASSERT_TRUE(ref);
166   EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName)));
167 
168   ref = ResourceUtils::ParseStyleParentReference("@android:foo", &err_str);
169   ASSERT_TRUE(ref);
170   EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName)));
171 
172   ref = ResourceUtils::ParseStyleParentReference("foo", &err_str);
173   ASSERT_TRUE(ref);
174   EXPECT_THAT(ref.value().name, Eq(make_value(kStyleFooName)));
175 
176   ref = ResourceUtils::ParseStyleParentReference("*android:style/foo", &err_str);
177   ASSERT_TRUE(ref);
178   EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName)));
179   EXPECT_TRUE(ref.value().private_reference);
180 }
181 
TEST(ResourceUtilsTest,ParseEmptyFlag)182 TEST(ResourceUtilsTest, ParseEmptyFlag) {
183   std::unique_ptr<Attribute> attr = test::AttributeBuilder()
184                                         .SetTypeMask(ResTable_map::TYPE_FLAGS)
185                                         .AddItem("one", 0x01)
186                                         .AddItem("two", 0x02)
187                                         .Build();
188 
189   std::unique_ptr<BinaryPrimitive> result = ResourceUtils::TryParseFlagSymbol(attr.get(), "");
190   ASSERT_THAT(result, NotNull());
191   EXPECT_THAT(result->value.data, Eq(0u));
192 }
193 
TEST(ResourceUtilsTest,NullIsEmptyReference)194 TEST(ResourceUtilsTest, NullIsEmptyReference) {
195   ASSERT_THAT(ResourceUtils::MakeNull(), Pointee(ValueEq(Reference())));
196   ASSERT_THAT(ResourceUtils::TryParseNullOrEmpty("@null"), Pointee(ValueEq(Reference())));
197 }
198 
TEST(ResourceUtilsTest,EmptyIsBinaryPrimitive)199 TEST(ResourceUtilsTest, EmptyIsBinaryPrimitive) {
200   ASSERT_THAT(ResourceUtils::MakeEmpty(), Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_NULL, Res_value::DATA_NULL_EMPTY))));
201   ASSERT_THAT(ResourceUtils::TryParseNullOrEmpty("@empty"), Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_NULL, Res_value::DATA_NULL_EMPTY))));
202 }
203 
TEST(ResourceUtilsTest,ItemsWithWhitespaceAreParsedCorrectly)204 TEST(ResourceUtilsTest, ItemsWithWhitespaceAreParsedCorrectly) {
205   EXPECT_THAT(ResourceUtils::TryParseItemForAttribute(" 12\n   ", ResTable_map::TYPE_INTEGER),
206               Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_INT_DEC, 12u))));
207   EXPECT_THAT(ResourceUtils::TryParseItemForAttribute(" true\n   ", ResTable_map::TYPE_BOOLEAN),
208               Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_INT_BOOLEAN, 0xffffffffu))));
209 
210   const float expected_float = 12.0f;
211   const uint32_t expected_float_flattened = *(uint32_t*)&expected_float;
212   EXPECT_THAT(ResourceUtils::TryParseItemForAttribute(" 12.0\n   ", ResTable_map::TYPE_FLOAT),
213               Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, expected_float_flattened))));
214 }
215 
TEST(ResourceUtilsTest,ParseSdkVersionWithCodename)216 TEST(ResourceUtilsTest, ParseSdkVersionWithCodename) {
217   EXPECT_THAT(ResourceUtils::ParseSdkVersion("Q"), Eq(Maybe<int>(10000)));
218   EXPECT_THAT(
219       ResourceUtils::ParseSdkVersion("Q.fingerprint"),
220       Eq(Maybe<int>(10000)));
221 
222   EXPECT_THAT(ResourceUtils::ParseSdkVersion("R"), Eq(Maybe<int>(10000)));
223   EXPECT_THAT(
224       ResourceUtils::ParseSdkVersion("R.fingerprint"),
225       Eq(Maybe<int>(10000)));
226 }
227 
TEST(ResourceUtilsTest,StringBuilderWhitespaceRemoval)228 TEST(ResourceUtilsTest, StringBuilderWhitespaceRemoval) {
229   EXPECT_THAT(ResourceUtils::StringBuilder()
230                   .AppendText("    hey guys ")
231                   .AppendText(" this is so cool ")
232                   .to_string(),
233               Eq(" hey guys this is so cool "));
234   EXPECT_THAT(ResourceUtils::StringBuilder()
235                   .AppendText(" \" wow,  so many \t ")
236                   .AppendText("spaces. \"what? ")
237                   .to_string(),
238               Eq("  wow,  so many \t spaces. what? "));
239   EXPECT_THAT(ResourceUtils::StringBuilder()
240                   .AppendText("  where \t ")
241                   .AppendText(" \nis the pie?")
242                   .to_string(),
243               Eq(" where is the pie?"));
244 }
245 
TEST(ResourceUtilsTest,StringBuilderEscaping)246 TEST(ResourceUtilsTest, StringBuilderEscaping) {
247   EXPECT_THAT(ResourceUtils::StringBuilder()
248                   .AppendText("hey guys\\n ")
249                   .AppendText(" this \\t is so\\\\ cool")
250                   .to_string(),
251               Eq("hey guys\n this \t is so\\ cool"));
252   EXPECT_THAT(ResourceUtils::StringBuilder().AppendText("\\@\\?\\#\\\\\\'").to_string(),
253               Eq("@?#\\\'"));
254 }
255 
TEST(ResourceUtilsTest,StringBuilderMisplacedQuote)256 TEST(ResourceUtilsTest, StringBuilderMisplacedQuote) {
257   ResourceUtils::StringBuilder builder;
258   EXPECT_FALSE(builder.AppendText("they're coming!"));
259 }
260 
TEST(ResourceUtilsTest,StringBuilderUnicodeCodes)261 TEST(ResourceUtilsTest, StringBuilderUnicodeCodes) {
262   EXPECT_THAT(ResourceUtils::StringBuilder().AppendText("\\u00AF\\u0AF0 woah").to_string(),
263               Eq("\u00AF\u0AF0 woah"));
264   EXPECT_FALSE(ResourceUtils::StringBuilder().AppendText("\\u00 yo"));
265 }
266 
TEST(ResourceUtilsTest,StringBuilderPreserveSpaces)267 TEST(ResourceUtilsTest, StringBuilderPreserveSpaces) {
268   EXPECT_THAT(ResourceUtils::StringBuilder(true /*preserve_spaces*/).AppendText("\"").to_string(),
269               Eq("\""));
270 }
271 
272 }  // namespace aapt
273