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 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 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 56TEST(ResTableTest, shouldLoadSuccessfully) { 57 ResTable table; 58 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); 59} 60 61TEST(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 68TEST(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 81TEST(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 101TEST(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 121TEST(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 141TEST(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 157TEST(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(¶m, 0, sizeof(param)); 173 param.density = 320; 174 table.setParameters(¶m); 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 185TEST(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(¶m, 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(¶m); 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 209TEST(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 225void 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 251TEST(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 302TEST(ResTableTest, ShareButDontModifyResTable) { 303 ResTable sharedTable; 304 ASSERT_EQ(NO_ERROR, sharedTable.add(basic_arsc, basic_arsc_len)); 305 306 ResTable_config param; 307 memset(¶m, 0, sizeof(param)); 308 param.language[0] = 'v'; 309 param.language[1] = 's'; 310 sharedTable.setParameters(¶m); 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(¶m, 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(¶m); 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 344TEST(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