blob: 7cd7fb5cd71184cbdeb4f94cd22911391134f208 [file] [log] [blame]
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -07001/*
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
Dan Albert1b4f3162015-04-07 18:43:15 -070019#include <codecvt>
20#include <locale>
21#include <string>
22
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070023#include <utils/String8.h>
24#include <utils/String16.h>
25#include "TestHelpers.h"
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -070026#include "data/basic/R.h"
27#include "data/lib/R.h"
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070028
29#include <gtest/gtest.h>
30
31using namespace android;
32
33namespace {
34
35/**
36 * Include a binary resource table.
37 *
38 * Package: com.android.test.basic
39 */
40#include "data/basic/basic_arsc.h"
41
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -070042#include "data/lib/lib_arsc.h"
43
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070044TEST(ResTableTest, shouldLoadSuccessfully) {
45 ResTable table;
46 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
47}
48
49TEST(ResTableTest, simpleTypeIsRetrievedCorrectly) {
50 ResTable table;
51 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
52
Adam Lesinski60293192014-10-21 18:36:42 -070053 EXPECT_TRUE(IsStringEqual(table, base::R::string::test1, "test1"));
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070054}
55
56TEST(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);
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -070066 ASSERT_EQ(base::R::string::test1, resID);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070067}
68
69TEST(ResTableTest, noParentThemeIsAppliedCorrectly) {
70 ResTable table;
71 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
72
73 ResTable::Theme theme(table);
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -070074 ASSERT_EQ(NO_ERROR, theme.applyStyle(base::R::style::Theme1));
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070075
76 Res_value val;
77 uint32_t specFlags = 0;
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -070078 ssize_t index = theme.getAttribute(base::R::attr::attr1, &val, &specFlags);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070079 ASSERT_GE(index, 0);
80 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
81 ASSERT_EQ(uint32_t(100), val.data);
82
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -070083 index = theme.getAttribute(base::R::attr::attr2, &val, &specFlags);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070084 ASSERT_GE(index, 0);
85 ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -070086 ASSERT_EQ(base::R::integer::number1, val.data);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070087}
88
89TEST(ResTableTest, parentThemeIsAppliedCorrectly) {
90 ResTable table;
91 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
92
93 ResTable::Theme theme(table);
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -070094 ASSERT_EQ(NO_ERROR, theme.applyStyle(base::R::style::Theme2));
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070095
96 Res_value val;
97 uint32_t specFlags = 0;
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -070098 ssize_t index = theme.getAttribute(base::R::attr::attr1, &val, &specFlags);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070099 ASSERT_GE(index, 0);
100 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
101 ASSERT_EQ(uint32_t(300), val.data);
102
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -0700103 index = theme.getAttribute(base::R::attr::attr2, &val, &specFlags);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700104 ASSERT_GE(index, 0);
105 ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -0700106 ASSERT_EQ(base::R::integer::number1, val.data);
107}
108
109TEST(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);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700122}
123
124TEST(ResTableTest, referenceToBagIsNotResolved) {
125 ResTable table;
126 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
127
128 Res_value val;
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -0700129 ssize_t block = table.getResource(base::R::integer::number2, &val, MAY_NOT_BE_BAG);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700130 ASSERT_GE(block, 0);
131 ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -0700132 ASSERT_EQ(base::R::array::integerArray1, val.data);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700133
134 ssize_t newBlock = table.resolveReference(&val, block);
135 EXPECT_EQ(block, newBlock);
136 EXPECT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -0700137 EXPECT_EQ(base::R::array::integerArray1, val.data);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700138}
139
140TEST(ResTableTest, resourcesStillAccessibleAfterParameterChange) {
141 ResTable table;
142 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
143
144 Res_value val;
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -0700145 ssize_t block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700146 ASSERT_GE(block, 0);
147 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
148
149 const ResTable::bag_entry* entry;
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -0700150 ssize_t count = table.lockBag(base::R::array::integerArray1, &entry);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700151 ASSERT_GE(count, 0);
152 table.unlockBag(entry);
153
154 ResTable_config param;
155 memset(&param, 0, sizeof(param));
156 param.density = 320;
157 table.setParameters(&param);
158
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -0700159 block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700160 ASSERT_GE(block, 0);
161 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
162
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -0700163 count = table.lockBag(base::R::array::integerArray1, &entry);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700164 ASSERT_GE(count, 0);
165 table.unlockBag(entry);
166}
167
168TEST(ResTableTest, resourceIsOverridenWithBetterConfig) {
169 ResTable table;
170 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
171
172 Res_value val;
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -0700173 ssize_t block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700174 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(&param, 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(&param);
185
Adam Lesinskiccf25c7b2014-08-08 15:32:40 -0700186 block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700187 ASSERT_GE(block, 0);
188 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
189 ASSERT_EQ(uint32_t(400), val.data);
190}
191
Adam Lesinski2cb761e2014-08-15 13:59:02 -0700192TEST(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
Dan Albert1b4f3162015-04-07 18:43:15 -0700208void 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
234TEST(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
Adam Lesinskiff5808d2016-02-23 17:49:53 -0800285TEST(ResTableTest, ShareButDontModifyResTable) {
286 ResTable sharedTable;
287 ASSERT_EQ(NO_ERROR, sharedTable.add(basic_arsc, basic_arsc_len));
288
289 ResTable_config param;
290 memset(&param, 0, sizeof(param));
291 param.language[0] = 'v';
292 param.language[1] = 's';
293 sharedTable.setParameters(&param);
294
295 // Check that we get the default value for @integer:number1
296 Res_value val;
297 ssize_t block = sharedTable.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
298 ASSERT_GE(block, 0);
299 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
300 ASSERT_EQ(uint32_t(600), val.data);
301
302 // Create a new table that shares the entries of the shared table.
303 ResTable table;
304 ASSERT_EQ(NO_ERROR, table.add(&sharedTable, false));
305
306 // Set a new configuration on the new table.
307 memset(&param, 0, sizeof(param));
308 param.language[0] = 's';
309 param.language[1] = 'v';
310 param.country[0] = 'S';
311 param.country[1] = 'E';
312 table.setParameters(&param);
313
314 // Check that we get a new value in the new table.
315 block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
316 ASSERT_GE(block, 0);
317 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
318 ASSERT_EQ(uint32_t(400), val.data);
319
320 // Check that we still get the old value in the shared table.
321 block = sharedTable.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
322 ASSERT_GE(block, 0);
323 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
324 ASSERT_EQ(uint32_t(600), val.data);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700325}
Adam Lesinskiff5808d2016-02-23 17:49:53 -0800326
327} // namespace