ResTable_test.cpp revision b7e1ce07756aaca829828c2053eca0d66dd4d440
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 136TEST(ResTableTest, referenceToBagIsNotResolved) { 137 ResTable table; 138 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); 139 140 Res_value val; 141 ssize_t block = table.getResource(base::R::integer::number2, &val, MAY_NOT_BE_BAG); 142 ASSERT_GE(block, 0); 143 ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType); 144 ASSERT_EQ(base::R::array::integerArray1, val.data); 145 146 ssize_t newBlock = table.resolveReference(&val, block); 147 EXPECT_EQ(block, newBlock); 148 EXPECT_EQ(Res_value::TYPE_REFERENCE, val.dataType); 149 EXPECT_EQ(base::R::array::integerArray1, val.data); 150} 151 152TEST(ResTableTest, resourcesStillAccessibleAfterParameterChange) { 153 ResTable table; 154 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); 155 156 Res_value val; 157 ssize_t block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG); 158 ASSERT_GE(block, 0); 159 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType); 160 161 const ResTable::bag_entry* entry; 162 ssize_t count = table.lockBag(base::R::array::integerArray1, &entry); 163 ASSERT_GE(count, 0); 164 table.unlockBag(entry); 165 166 ResTable_config param; 167 memset(¶m, 0, sizeof(param)); 168 param.density = 320; 169 table.setParameters(¶m); 170 171 block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG); 172 ASSERT_GE(block, 0); 173 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType); 174 175 count = table.lockBag(base::R::array::integerArray1, &entry); 176 ASSERT_GE(count, 0); 177 table.unlockBag(entry); 178} 179 180TEST(ResTableTest, resourceIsOverridenWithBetterConfig) { 181 ResTable table; 182 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); 183 184 Res_value val; 185 ssize_t block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG); 186 ASSERT_GE(block, 0); 187 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType); 188 ASSERT_EQ(uint32_t(200), val.data); 189 190 ResTable_config param; 191 memset(¶m, 0, sizeof(param)); 192 param.language[0] = 's'; 193 param.language[1] = 'v'; 194 param.country[0] = 'S'; 195 param.country[1] = 'E'; 196 table.setParameters(¶m); 197 198 block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG); 199 ASSERT_GE(block, 0); 200 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType); 201 ASSERT_EQ(uint32_t(400), val.data); 202} 203 204TEST(ResTableTest, emptyTableHasSensibleDefaults) { 205 const int32_t assetCookie = 1; 206 207 ResTable table; 208 ASSERT_EQ(NO_ERROR, table.addEmpty(assetCookie)); 209 210 // Adding an empty table gives us one table! 211 ASSERT_EQ(uint32_t(1), table.getTableCount()); 212 213 // Adding an empty table doesn't mean we get packages. 214 ASSERT_EQ(uint32_t(0), table.getBasePackageCount()); 215 216 Res_value val; 217 ASSERT_LT(table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG), 0); 218} 219 220void testU16StringToInt(const char16_t* str, uint32_t expectedValue, 221 bool expectSuccess, bool expectHex) { 222 size_t len = std::char_traits<char16_t>::length(str); 223 224 // Gtest can't print UTF-16 strings, so we have to convert to UTF-8 :( 225 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; 226 std::string s = convert.to_bytes(std::u16string(str, len)); 227 228 Res_value out = {}; 229 ASSERT_EQ(expectSuccess, U16StringToInt(str, len, &out)) 230 << "Failed with " << s; 231 232 if (!expectSuccess) { 233 ASSERT_EQ(out.TYPE_NULL, out.dataType) << "Failed with " << s; 234 return; 235 } 236 237 if (expectHex) { 238 ASSERT_EQ(out.TYPE_INT_HEX, out.dataType) << "Failed with " << s; 239 } else { 240 ASSERT_EQ(out.TYPE_INT_DEC, out.dataType) << "Failed with " << s; 241 } 242 243 ASSERT_EQ(expectedValue, out.data) << "Failed with " << s; 244} 245 246TEST(ResTableTest, U16StringToInt) { 247 testU16StringToInt(u"", 0U, false, false); 248 testU16StringToInt(u" ", 0U, false, false); 249 testU16StringToInt(u"\t\n", 0U, false, false); 250 251 testU16StringToInt(u"abcd", 0U, false, false); 252 testU16StringToInt(u"10abcd", 0U, false, false); 253 testU16StringToInt(u"42 42", 0U, false, false); 254 testU16StringToInt(u"- 42", 0U, false, false); 255 testU16StringToInt(u"-", 0U, false, false); 256 257 testU16StringToInt(u"0x", 0U, false, true); 258 testU16StringToInt(u"0xnope", 0U, false, true); 259 testU16StringToInt(u"0X42", 0U, false, true); 260 testU16StringToInt(u"0x42 0x42", 0U, false, true); 261 testU16StringToInt(u"-0x0", 0U, false, true); 262 testU16StringToInt(u"-0x42", 0U, false, true); 263 testU16StringToInt(u"- 0x42", 0U, false, true); 264 265 // Note that u" 42" would pass. This preserves the old behavior, but it may 266 // not be desired. 267 testU16StringToInt(u"42 ", 0U, false, false); 268 testU16StringToInt(u"0x42 ", 0U, false, true); 269 270 // Decimal cases. 271 testU16StringToInt(u"0", 0U, true, false); 272 testU16StringToInt(u"-0", 0U, true, false); 273 testU16StringToInt(u"42", 42U, true, false); 274 testU16StringToInt(u" 42", 42U, true, false); 275 testU16StringToInt(u"-42", static_cast<uint32_t>(-42), true, false); 276 testU16StringToInt(u" -42", static_cast<uint32_t>(-42), true, false); 277 testU16StringToInt(u"042", 42U, true, false); 278 testU16StringToInt(u"-042", static_cast<uint32_t>(-42), true, false); 279 280 // Hex cases. 281 testU16StringToInt(u"0x0", 0x0, true, true); 282 testU16StringToInt(u"0x42", 0x42, true, true); 283 testU16StringToInt(u" 0x42", 0x42, true, true); 284 285 // Just before overflow cases: 286 testU16StringToInt(u"2147483647", INT_MAX, true, false); 287 testU16StringToInt(u"-2147483648", static_cast<uint32_t>(INT_MIN), true, 288 false); 289 testU16StringToInt(u"0xffffffff", UINT_MAX, true, true); 290 291 // Overflow cases: 292 testU16StringToInt(u"2147483648", 0U, false, false); 293 testU16StringToInt(u"-2147483649", 0U, false, false); 294 testU16StringToInt(u"0x1ffffffff", 0U, false, true); 295} 296 297TEST(ResTableTest, ShareButDontModifyResTable) { 298 ResTable sharedTable; 299 ASSERT_EQ(NO_ERROR, sharedTable.add(basic_arsc, basic_arsc_len)); 300 301 ResTable_config param; 302 memset(¶m, 0, sizeof(param)); 303 param.language[0] = 'v'; 304 param.language[1] = 's'; 305 sharedTable.setParameters(¶m); 306 307 // Check that we get the default value for @integer:number1 308 Res_value val; 309 ssize_t block = sharedTable.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG); 310 ASSERT_GE(block, 0); 311 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType); 312 ASSERT_EQ(uint32_t(600), val.data); 313 314 // Create a new table that shares the entries of the shared table. 315 ResTable table; 316 ASSERT_EQ(NO_ERROR, table.add(&sharedTable, false)); 317 318 // Set a new configuration on the new table. 319 memset(¶m, 0, sizeof(param)); 320 param.language[0] = 's'; 321 param.language[1] = 'v'; 322 param.country[0] = 'S'; 323 param.country[1] = 'E'; 324 table.setParameters(¶m); 325 326 // Check that we get a new value in the new table. 327 block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG); 328 ASSERT_GE(block, 0); 329 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType); 330 ASSERT_EQ(uint32_t(400), val.data); 331 332 // Check that we still get the old value in the shared table. 333 block = sharedTable.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG); 334 ASSERT_GE(block, 0); 335 ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType); 336 ASSERT_EQ(uint32_t(600), val.data); 337} 338 339TEST(ResTableTest, GetConfigurationsReturnsUniqueList) { 340 ResTable table; 341 ASSERT_EQ(NO_ERROR, table.add(system_arsc, system_arsc_len)); 342 ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); 343 344 ResTable_config configSv; 345 memset(&configSv, 0, sizeof(configSv)); 346 configSv.language[0] = 's'; 347 configSv.language[1] = 'v'; 348 349 Vector<ResTable_config> configs; 350 table.getConfigurations(&configs); 351 352 EXPECT_EQ(1, std::count(configs.begin(), configs.end(), configSv)); 353 354 Vector<String8> locales; 355 table.getLocales(&locales); 356 357 EXPECT_EQ(1, std::count(locales.begin(), locales.end(), String8("sv"))); 358} 359 360} // namespace 361