• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /**
43  * Include a binary library resource table.
44  *
45  * Package: com.android.test.basic
46  */
47 #include "data/lib/lib_arsc.h"
48 
49 /**
50  * Include a system resource table.
51  *
52  * Package: android
53  */
54 #include "data/system/system_arsc.h"
55 
TEST(ResTableTest,shouldLoadSuccessfully)56 TEST(ResTableTest, shouldLoadSuccessfully) {
57     ResTable table;
58     ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
59 }
60 
TEST(ResTableTest,simpleTypeIsRetrievedCorrectly)61 TEST(ResTableTest, simpleTypeIsRetrievedCorrectly) {
62     ResTable table;
63     ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
64 
65     EXPECT_TRUE(IsStringEqual(table, base::R::string::test1, "test1"));
66 }
67 
TEST(ResTableTest,resourceNameIsResolved)68 TEST(ResTableTest, resourceNameIsResolved) {
69     ResTable table;
70     ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
71 
72     String16 defPackage("com.android.test.basic");
73     String16 testName("@string/test1");
74     uint32_t resID = table.identifierForName(testName.string(), testName.size(),
75                                              0, 0,
76                                              defPackage.string(), defPackage.size());
77     ASSERT_NE(uint32_t(0x00000000), resID);
78     ASSERT_EQ(base::R::string::test1, resID);
79 }
80 
TEST(ResTableTest,noParentThemeIsAppliedCorrectly)81 TEST(ResTableTest, noParentThemeIsAppliedCorrectly) {
82     ResTable table;
83     ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
84 
85     ResTable::Theme theme(table);
86     ASSERT_EQ(NO_ERROR, theme.applyStyle(base::R::style::Theme1));
87 
88     Res_value val;
89     uint32_t specFlags = 0;
90     ssize_t index = theme.getAttribute(base::R::attr::attr1, &val, &specFlags);
91     ASSERT_GE(index, 0);
92     ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
93     ASSERT_EQ(uint32_t(100), val.data);
94 
95     index = theme.getAttribute(base::R::attr::attr2, &val, &specFlags);
96     ASSERT_GE(index, 0);
97     ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
98     ASSERT_EQ(base::R::integer::number1, val.data);
99 }
100 
TEST(ResTableTest,parentThemeIsAppliedCorrectly)101 TEST(ResTableTest, parentThemeIsAppliedCorrectly) {
102     ResTable table;
103     ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
104 
105     ResTable::Theme theme(table);
106     ASSERT_EQ(NO_ERROR, theme.applyStyle(base::R::style::Theme2));
107 
108     Res_value val;
109     uint32_t specFlags = 0;
110     ssize_t index = theme.getAttribute(base::R::attr::attr1, &val, &specFlags);
111     ASSERT_GE(index, 0);
112     ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
113     ASSERT_EQ(uint32_t(300), val.data);
114 
115     index = theme.getAttribute(base::R::attr::attr2, &val, &specFlags);
116     ASSERT_GE(index, 0);
117     ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
118     ASSERT_EQ(base::R::integer::number1, val.data);
119 }
120 
TEST(ResTableTest,libraryThemeIsAppliedCorrectly)121 TEST(ResTableTest, libraryThemeIsAppliedCorrectly) {
122     ResTable table;
123     ASSERT_EQ(NO_ERROR, table.add(lib_arsc, lib_arsc_len));
124 
125     ResTable::Theme theme(table);
126     ASSERT_EQ(NO_ERROR, theme.applyStyle(lib::R::style::Theme));
127 
128     Res_value val;
129     uint32_t specFlags = 0;
130     ssize_t index = theme.getAttribute(lib::R::attr::attr1, &val, &specFlags);
131     ASSERT_GE(index, 0);
132     ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
133     ASSERT_EQ(uint32_t(700), val.data);
134 
135     index = theme.getAttribute(lib::R::attr::attr2, &val, &specFlags);
136     ASSERT_GE(index, 0);
137     ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
138     ASSERT_EQ(uint32_t(700), val.data);
139 }
140 
TEST(ResTableTest,referenceToBagIsNotResolved)141 TEST(ResTableTest, referenceToBagIsNotResolved) {
142     ResTable table;
143     ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
144 
145     Res_value val;
146     ssize_t block = table.getResource(base::R::integer::number2, &val, MAY_NOT_BE_BAG);
147     ASSERT_GE(block, 0);
148     ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
149     ASSERT_EQ(base::R::array::integerArray1, val.data);
150 
151     ssize_t newBlock = table.resolveReference(&val, block);
152     EXPECT_EQ(block, newBlock);
153     EXPECT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
154     EXPECT_EQ(base::R::array::integerArray1, val.data);
155 }
156 
TEST(ResTableTest,resourcesStillAccessibleAfterParameterChange)157 TEST(ResTableTest, resourcesStillAccessibleAfterParameterChange) {
158     ResTable table;
159     ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
160 
161     Res_value val;
162     ssize_t block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
163     ASSERT_GE(block, 0);
164     ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
165 
166     const ResTable::bag_entry* entry;
167     ssize_t count = table.lockBag(base::R::array::integerArray1, &entry);
168     ASSERT_GE(count, 0);
169     table.unlockBag(entry);
170 
171     ResTable_config param;
172     memset(&param, 0, sizeof(param));
173     param.density = 320;
174     table.setParameters(&param);
175 
176     block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
177     ASSERT_GE(block, 0);
178     ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
179 
180     count = table.lockBag(base::R::array::integerArray1, &entry);
181     ASSERT_GE(count, 0);
182     table.unlockBag(entry);
183 }
184 
TEST(ResTableTest,resourceIsOverridenWithBetterConfig)185 TEST(ResTableTest, resourceIsOverridenWithBetterConfig) {
186     ResTable table;
187     ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
188 
189     Res_value val;
190     ssize_t block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
191     ASSERT_GE(block, 0);
192     ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
193     ASSERT_EQ(uint32_t(200), val.data);
194 
195     ResTable_config param;
196     memset(&param, 0, sizeof(param));
197     param.language[0] = 's';
198     param.language[1] = 'v';
199     param.country[0] = 'S';
200     param.country[1] = 'E';
201     table.setParameters(&param);
202 
203     block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
204     ASSERT_GE(block, 0);
205     ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
206     ASSERT_EQ(uint32_t(400), val.data);
207 }
208 
TEST(ResTableTest,emptyTableHasSensibleDefaults)209 TEST(ResTableTest, emptyTableHasSensibleDefaults) {
210     const int32_t assetCookie = 1;
211 
212     ResTable table;
213     ASSERT_EQ(NO_ERROR, table.addEmpty(assetCookie));
214 
215     // Adding an empty table gives us one table!
216     ASSERT_EQ(uint32_t(1), table.getTableCount());
217 
218     // Adding an empty table doesn't mean we get packages.
219     ASSERT_EQ(uint32_t(0), table.getBasePackageCount());
220 
221     Res_value val;
222     ASSERT_LT(table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG), 0);
223 }
224 
testU16StringToInt(const char16_t * str,uint32_t expectedValue,bool expectSuccess,bool expectHex)225 void testU16StringToInt(const char16_t* str, uint32_t expectedValue,
226                         bool expectSuccess, bool expectHex) {
227     size_t len = std::char_traits<char16_t>::length(str);
228 
229     // Gtest can't print UTF-16 strings, so we have to convert to UTF-8 :(
230     std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
231     std::string s = convert.to_bytes(std::u16string(str, len));
232 
233     Res_value out = {};
234     ASSERT_EQ(expectSuccess, U16StringToInt(str, len, &out))
235         << "Failed with " << s;
236 
237     if (!expectSuccess) {
238         ASSERT_EQ(out.TYPE_NULL, out.dataType) << "Failed with " << s;
239         return;
240     }
241 
242     if (expectHex) {
243         ASSERT_EQ(out.TYPE_INT_HEX, out.dataType) << "Failed with " << s;
244     } else {
245         ASSERT_EQ(out.TYPE_INT_DEC, out.dataType) << "Failed with " << s;
246     }
247 
248     ASSERT_EQ(expectedValue, out.data) << "Failed with " << s;
249 }
250 
TEST(ResTableTest,U16StringToInt)251 TEST(ResTableTest, U16StringToInt) {
252     testU16StringToInt(u"", 0U, false, false);
253     testU16StringToInt(u"    ", 0U, false, false);
254     testU16StringToInt(u"\t\n", 0U, false, false);
255 
256     testU16StringToInt(u"abcd", 0U, false, false);
257     testU16StringToInt(u"10abcd", 0U, false, false);
258     testU16StringToInt(u"42 42", 0U, false, false);
259     testU16StringToInt(u"- 42", 0U, false, false);
260     testU16StringToInt(u"-", 0U, false, false);
261 
262     testU16StringToInt(u"0x", 0U, false, true);
263     testU16StringToInt(u"0xnope", 0U, false, true);
264     testU16StringToInt(u"0X42", 0U, false, true);
265     testU16StringToInt(u"0x42 0x42", 0U, false, true);
266     testU16StringToInt(u"-0x0", 0U, false, true);
267     testU16StringToInt(u"-0x42", 0U, false, true);
268     testU16StringToInt(u"- 0x42", 0U, false, true);
269 
270     // Note that u" 42" would pass. This preserves the old behavior, but it may
271     // not be desired.
272     testU16StringToInt(u"42 ", 0U, false, false);
273     testU16StringToInt(u"0x42 ", 0U, false, true);
274 
275     // Decimal cases.
276     testU16StringToInt(u"0", 0U, true, false);
277     testU16StringToInt(u"-0", 0U, true, false);
278     testU16StringToInt(u"42", 42U, true, false);
279     testU16StringToInt(u" 42", 42U, true, false);
280     testU16StringToInt(u"-42", static_cast<uint32_t>(-42), true, false);
281     testU16StringToInt(u" -42", static_cast<uint32_t>(-42), true, false);
282     testU16StringToInt(u"042", 42U, true, false);
283     testU16StringToInt(u"-042", static_cast<uint32_t>(-42), true, false);
284 
285     // Hex cases.
286     testU16StringToInt(u"0x0", 0x0, true, true);
287     testU16StringToInt(u"0x42", 0x42, true, true);
288     testU16StringToInt(u" 0x42", 0x42, true, true);
289 
290     // Just before overflow cases:
291     testU16StringToInt(u"2147483647", INT_MAX, true, false);
292     testU16StringToInt(u"-2147483648", static_cast<uint32_t>(INT_MIN), true,
293                        false);
294     testU16StringToInt(u"0xffffffff", UINT_MAX, true, true);
295 
296     // Overflow cases:
297     testU16StringToInt(u"2147483648", 0U, false, false);
298     testU16StringToInt(u"-2147483649", 0U, false, false);
299     testU16StringToInt(u"0x1ffffffff", 0U, false, true);
300 }
301 
TEST(ResTableTest,ShareButDontModifyResTable)302 TEST(ResTableTest, ShareButDontModifyResTable) {
303     ResTable sharedTable;
304     ASSERT_EQ(NO_ERROR, sharedTable.add(basic_arsc, basic_arsc_len));
305 
306     ResTable_config param;
307     memset(&param, 0, sizeof(param));
308     param.language[0] = 'v';
309     param.language[1] = 's';
310     sharedTable.setParameters(&param);
311 
312     // Check that we get the default value for @integer:number1
313     Res_value val;
314     ssize_t block = sharedTable.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
315     ASSERT_GE(block, 0);
316     ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
317     ASSERT_EQ(uint32_t(600), val.data);
318 
319     // Create a new table that shares the entries of the shared table.
320     ResTable table;
321     ASSERT_EQ(NO_ERROR, table.add(&sharedTable, false));
322 
323     // Set a new configuration on the new table.
324     memset(&param, 0, sizeof(param));
325     param.language[0] = 's';
326     param.language[1] = 'v';
327     param.country[0] = 'S';
328     param.country[1] = 'E';
329     table.setParameters(&param);
330 
331     // Check that we get a new value in the new table.
332     block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
333     ASSERT_GE(block, 0);
334     ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
335     ASSERT_EQ(uint32_t(400), val.data);
336 
337     // Check that we still get the old value in the shared table.
338     block = sharedTable.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
339     ASSERT_GE(block, 0);
340     ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
341     ASSERT_EQ(uint32_t(600), val.data);
342 }
343 
TEST(ResTableTest,GetConfigurationsReturnsUniqueList)344 TEST(ResTableTest, GetConfigurationsReturnsUniqueList) {
345     ResTable table;
346     ASSERT_EQ(NO_ERROR, table.add(system_arsc, system_arsc_len));
347     ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
348 
349     ResTable_config configSv;
350     memset(&configSv, 0, sizeof(configSv));
351     configSv.language[0] = 's';
352     configSv.language[1] = 'v';
353 
354     Vector<ResTable_config> configs;
355     table.getConfigurations(&configs);
356 
357     EXPECT_EQ(1, std::count(configs.begin(), configs.end(), configSv));
358 
359     Vector<String8> locales;
360     table.getLocales(&locales);
361 
362     EXPECT_EQ(1, std::count(locales.begin(), locales.end(), String8("sv")));
363 }
364 
365 } // namespace
366