1 /*
2 * Copyright (C) 2014 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 <androidfw/ResourceTypes.h>
18
19 #include <codecvt>
20 #include <locale>
21 #include <string>
22
23 #include <utils/String8.h>
24 #include <utils/String16.h>
25 #include "TestHelpers.h"
26 #include "data/basic/R.h"
27 #include "data/lib/R.h"
28
29 #include <gtest/gtest.h>
30
31 using namespace android;
32
33 namespace {
34
35 /**
36 * Include a binary resource table.
37 *
38 * Package: com.android.test.basic
39 */
40 #include "data/basic/basic_arsc.h"
41
42 #include "data/lib/lib_arsc.h"
43
TEST(ResTableTest,shouldLoadSuccessfully)44 TEST(ResTableTest, shouldLoadSuccessfully) {
45 ResTable table;
46 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
47 }
48
TEST(ResTableTest,simpleTypeIsRetrievedCorrectly)49 TEST(ResTableTest, simpleTypeIsRetrievedCorrectly) {
50 ResTable table;
51 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
52
53 EXPECT_TRUE(IsStringEqual(table, base::R::string::test1, "test1"));
54 }
55
TEST(ResTableTest,resourceNameIsResolved)56 TEST(ResTableTest, resourceNameIsResolved) {
57 ResTable table;
58 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
59
60 String16 defPackage("com.android.test.basic");
61 String16 testName("@string/test1");
62 uint32_t resID = table.identifierForName(testName.string(), testName.size(),
63 0, 0,
64 defPackage.string(), defPackage.size());
65 ASSERT_NE(uint32_t(0x00000000), resID);
66 ASSERT_EQ(base::R::string::test1, resID);
67 }
68
TEST(ResTableTest,noParentThemeIsAppliedCorrectly)69 TEST(ResTableTest, noParentThemeIsAppliedCorrectly) {
70 ResTable table;
71 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
72
73 ResTable::Theme theme(table);
74 ASSERT_EQ(NO_ERROR, theme.applyStyle(base::R::style::Theme1));
75
76 Res_value val;
77 uint32_t specFlags = 0;
78 ssize_t index = theme.getAttribute(base::R::attr::attr1, &val, &specFlags);
79 ASSERT_GE(index, 0);
80 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
81 ASSERT_EQ(uint32_t(100), val.data);
82
83 index = theme.getAttribute(base::R::attr::attr2, &val, &specFlags);
84 ASSERT_GE(index, 0);
85 ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
86 ASSERT_EQ(base::R::integer::number1, val.data);
87 }
88
TEST(ResTableTest,parentThemeIsAppliedCorrectly)89 TEST(ResTableTest, parentThemeIsAppliedCorrectly) {
90 ResTable table;
91 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
92
93 ResTable::Theme theme(table);
94 ASSERT_EQ(NO_ERROR, theme.applyStyle(base::R::style::Theme2));
95
96 Res_value val;
97 uint32_t specFlags = 0;
98 ssize_t index = theme.getAttribute(base::R::attr::attr1, &val, &specFlags);
99 ASSERT_GE(index, 0);
100 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
101 ASSERT_EQ(uint32_t(300), val.data);
102
103 index = theme.getAttribute(base::R::attr::attr2, &val, &specFlags);
104 ASSERT_GE(index, 0);
105 ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
106 ASSERT_EQ(base::R::integer::number1, val.data);
107 }
108
TEST(ResTableTest,libraryThemeIsAppliedCorrectly)109 TEST(ResTableTest, libraryThemeIsAppliedCorrectly) {
110 ResTable table;
111 ASSERT_EQ(NO_ERROR, table.add(lib_arsc, lib_arsc_len));
112
113 ResTable::Theme theme(table);
114 ASSERT_EQ(NO_ERROR, theme.applyStyle(lib::R::style::Theme));
115
116 Res_value val;
117 uint32_t specFlags = 0;
118 ssize_t index = theme.getAttribute(lib::R::attr::attr1, &val, &specFlags);
119 ASSERT_GE(index, 0);
120 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
121 ASSERT_EQ(uint32_t(700), val.data);
122 }
123
TEST(ResTableTest,referenceToBagIsNotResolved)124 TEST(ResTableTest, referenceToBagIsNotResolved) {
125 ResTable table;
126 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
127
128 Res_value val;
129 ssize_t block = table.getResource(base::R::integer::number2, &val, MAY_NOT_BE_BAG);
130 ASSERT_GE(block, 0);
131 ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
132 ASSERT_EQ(base::R::array::integerArray1, val.data);
133
134 ssize_t newBlock = table.resolveReference(&val, block);
135 EXPECT_EQ(block, newBlock);
136 EXPECT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
137 EXPECT_EQ(base::R::array::integerArray1, val.data);
138 }
139
TEST(ResTableTest,resourcesStillAccessibleAfterParameterChange)140 TEST(ResTableTest, resourcesStillAccessibleAfterParameterChange) {
141 ResTable table;
142 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
143
144 Res_value val;
145 ssize_t block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
146 ASSERT_GE(block, 0);
147 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
148
149 const ResTable::bag_entry* entry;
150 ssize_t count = table.lockBag(base::R::array::integerArray1, &entry);
151 ASSERT_GE(count, 0);
152 table.unlockBag(entry);
153
154 ResTable_config param;
155 memset(¶m, 0, sizeof(param));
156 param.density = 320;
157 table.setParameters(¶m);
158
159 block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
160 ASSERT_GE(block, 0);
161 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
162
163 count = table.lockBag(base::R::array::integerArray1, &entry);
164 ASSERT_GE(count, 0);
165 table.unlockBag(entry);
166 }
167
TEST(ResTableTest,resourceIsOverridenWithBetterConfig)168 TEST(ResTableTest, resourceIsOverridenWithBetterConfig) {
169 ResTable table;
170 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
171
172 Res_value val;
173 ssize_t block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
174 ASSERT_GE(block, 0);
175 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
176 ASSERT_EQ(uint32_t(200), val.data);
177
178 ResTable_config param;
179 memset(¶m, 0, sizeof(param));
180 param.language[0] = 's';
181 param.language[1] = 'v';
182 param.country[0] = 'S';
183 param.country[1] = 'E';
184 table.setParameters(¶m);
185
186 block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
187 ASSERT_GE(block, 0);
188 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
189 ASSERT_EQ(uint32_t(400), val.data);
190 }
191
TEST(ResTableTest,emptyTableHasSensibleDefaults)192 TEST(ResTableTest, emptyTableHasSensibleDefaults) {
193 const int32_t assetCookie = 1;
194
195 ResTable table;
196 ASSERT_EQ(NO_ERROR, table.addEmpty(assetCookie));
197
198 // Adding an empty table gives us one table!
199 ASSERT_EQ(uint32_t(1), table.getTableCount());
200
201 // Adding an empty table doesn't mean we get packages.
202 ASSERT_EQ(uint32_t(0), table.getBasePackageCount());
203
204 Res_value val;
205 ASSERT_LT(table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG), 0);
206 }
207
testU16StringToInt(const char16_t * str,uint32_t expectedValue,bool expectSuccess,bool expectHex)208 void testU16StringToInt(const char16_t* str, uint32_t expectedValue,
209 bool expectSuccess, bool expectHex) {
210 size_t len = std::char_traits<char16_t>::length(str);
211
212 // Gtest can't print UTF-16 strings, so we have to convert to UTF-8 :(
213 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
214 std::string s = convert.to_bytes(std::u16string(str, len));
215
216 Res_value out = {};
217 ASSERT_EQ(expectSuccess, U16StringToInt(str, len, &out))
218 << "Failed with " << s;
219
220 if (!expectSuccess) {
221 ASSERT_EQ(out.TYPE_NULL, out.dataType) << "Failed with " << s;
222 return;
223 }
224
225 if (expectHex) {
226 ASSERT_EQ(out.TYPE_INT_HEX, out.dataType) << "Failed with " << s;
227 } else {
228 ASSERT_EQ(out.TYPE_INT_DEC, out.dataType) << "Failed with " << s;
229 }
230
231 ASSERT_EQ(expectedValue, out.data) << "Failed with " << s;
232 }
233
TEST(ResTableTest,U16StringToInt)234 TEST(ResTableTest, U16StringToInt) {
235 testU16StringToInt(u"", 0U, false, false);
236 testU16StringToInt(u" ", 0U, false, false);
237 testU16StringToInt(u"\t\n", 0U, false, false);
238
239 testU16StringToInt(u"abcd", 0U, false, false);
240 testU16StringToInt(u"10abcd", 0U, false, false);
241 testU16StringToInt(u"42 42", 0U, false, false);
242 testU16StringToInt(u"- 42", 0U, false, false);
243 testU16StringToInt(u"-", 0U, false, false);
244
245 testU16StringToInt(u"0x", 0U, false, true);
246 testU16StringToInt(u"0xnope", 0U, false, true);
247 testU16StringToInt(u"0X42", 0U, false, true);
248 testU16StringToInt(u"0x42 0x42", 0U, false, true);
249 testU16StringToInt(u"-0x0", 0U, false, true);
250 testU16StringToInt(u"-0x42", 0U, false, true);
251 testU16StringToInt(u"- 0x42", 0U, false, true);
252
253 // Note that u" 42" would pass. This preserves the old behavior, but it may
254 // not be desired.
255 testU16StringToInt(u"42 ", 0U, false, false);
256 testU16StringToInt(u"0x42 ", 0U, false, true);
257
258 // Decimal cases.
259 testU16StringToInt(u"0", 0U, true, false);
260 testU16StringToInt(u"-0", 0U, true, false);
261 testU16StringToInt(u"42", 42U, true, false);
262 testU16StringToInt(u" 42", 42U, true, false);
263 testU16StringToInt(u"-42", static_cast<uint32_t>(-42), true, false);
264 testU16StringToInt(u" -42", static_cast<uint32_t>(-42), true, false);
265 testU16StringToInt(u"042", 42U, true, false);
266 testU16StringToInt(u"-042", static_cast<uint32_t>(-42), true, false);
267
268 // Hex cases.
269 testU16StringToInt(u"0x0", 0x0, true, true);
270 testU16StringToInt(u"0x42", 0x42, true, true);
271 testU16StringToInt(u" 0x42", 0x42, true, true);
272
273 // Just before overflow cases:
274 testU16StringToInt(u"2147483647", INT_MAX, true, false);
275 testU16StringToInt(u"-2147483648", static_cast<uint32_t>(INT_MIN), true,
276 false);
277 testU16StringToInt(u"0xffffffff", UINT_MAX, true, true);
278
279 // Overflow cases:
280 testU16StringToInt(u"2147483648", 0U, false, false);
281 testU16StringToInt(u"-2147483649", 0U, false, false);
282 testU16StringToInt(u"0x1ffffffff", 0U, false, true);
283 }
284
285 }
286