TableFlattener_test.cpp revision cacb28f2d60858106e2819cc7d95a65e8bda890b
1/* 2 * Copyright (C) 2015 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 "flatten/TableFlattener.h" 18#include "ResourceUtils.h" 19#include "test/Test.h" 20#include "unflatten/BinaryResourceParser.h" 21#include "util/Util.h" 22 23using namespace android; 24 25namespace aapt { 26 27class TableFlattenerTest : public ::testing::Test { 28 public: 29 void SetUp() override { 30 mContext = test::ContextBuilder() 31 .setCompilationPackage("com.app.test") 32 .setPackageId(0x7f) 33 .build(); 34 } 35 36 ::testing::AssertionResult flatten(ResourceTable* table, ResTable* outTable) { 37 BigBuffer buffer(1024); 38 TableFlattener flattener(&buffer); 39 if (!flattener.consume(mContext.get(), table)) { 40 return ::testing::AssertionFailure() << "failed to flatten ResourceTable"; 41 } 42 43 std::unique_ptr<uint8_t[]> data = util::copy(buffer); 44 if (outTable->add(data.get(), buffer.size(), -1, true) != NO_ERROR) { 45 return ::testing::AssertionFailure() << "flattened ResTable is corrupt"; 46 } 47 return ::testing::AssertionSuccess(); 48 } 49 50 ::testing::AssertionResult flatten(ResourceTable* table, 51 ResourceTable* outTable) { 52 BigBuffer buffer(1024); 53 TableFlattener flattener(&buffer); 54 if (!flattener.consume(mContext.get(), table)) { 55 return ::testing::AssertionFailure() << "failed to flatten ResourceTable"; 56 } 57 58 std::unique_ptr<uint8_t[]> data = util::copy(buffer); 59 BinaryResourceParser parser(mContext.get(), outTable, {}, data.get(), 60 buffer.size()); 61 if (!parser.parse()) { 62 return ::testing::AssertionFailure() << "flattened ResTable is corrupt"; 63 } 64 return ::testing::AssertionSuccess(); 65 } 66 67 ::testing::AssertionResult exists(ResTable* table, 68 const StringPiece& expectedName, 69 const ResourceId& expectedId, 70 const ConfigDescription& expectedConfig, 71 const uint8_t expectedDataType, 72 const uint32_t expectedData, 73 const uint32_t expectedSpecFlags) { 74 const ResourceName expectedResName = test::parseNameOrDie(expectedName); 75 76 table->setParameters(&expectedConfig); 77 78 ResTable_config config; 79 Res_value val; 80 uint32_t specFlags; 81 if (table->getResource(expectedId.id, &val, false, 0, &specFlags, &config) < 82 0) { 83 return ::testing::AssertionFailure() << "could not find resource with"; 84 } 85 86 if (expectedDataType != val.dataType) { 87 return ::testing::AssertionFailure() 88 << "expected data type " << std::hex << (int)expectedDataType 89 << " but got data type " << (int)val.dataType << std::dec 90 << " instead"; 91 } 92 93 if (expectedData != val.data) { 94 return ::testing::AssertionFailure() 95 << "expected data " << std::hex << expectedData << " but got data " 96 << val.data << std::dec << " instead"; 97 } 98 99 if (expectedSpecFlags != specFlags) { 100 return ::testing::AssertionFailure() 101 << "expected specFlags " << std::hex << expectedSpecFlags 102 << " but got specFlags " << specFlags << std::dec << " instead"; 103 } 104 105 ResTable::resource_name actualName; 106 if (!table->getResourceName(expectedId.id, false, &actualName)) { 107 return ::testing::AssertionFailure() << "failed to find resource name"; 108 } 109 110 Maybe<ResourceName> resName = ResourceUtils::toResourceName(actualName); 111 if (!resName) { 112 return ::testing::AssertionFailure() 113 << "expected name '" << expectedResName << "' but got '" 114 << StringPiece16(actualName.package, actualName.packageLen) << ":" 115 << StringPiece16(actualName.type, actualName.typeLen) << "/" 116 << StringPiece16(actualName.name, actualName.nameLen) << "'"; 117 } 118 119 if (expectedConfig != config) { 120 return ::testing::AssertionFailure() << "expected config '" 121 << expectedConfig << "' but got '" 122 << ConfigDescription(config) << "'"; 123 } 124 return ::testing::AssertionSuccess(); 125 } 126 127 private: 128 std::unique_ptr<IAaptContext> mContext; 129}; 130 131TEST_F(TableFlattenerTest, FlattenFullyLinkedTable) { 132 std::unique_ptr<ResourceTable> table = 133 test::ResourceTableBuilder() 134 .setPackageId("com.app.test", 0x7f) 135 .addSimple("com.app.test:id/one", ResourceId(0x7f020000)) 136 .addSimple("com.app.test:id/two", ResourceId(0x7f020001)) 137 .addValue("com.app.test:id/three", ResourceId(0x7f020002), 138 test::buildReference("com.app.test:id/one", 139 ResourceId(0x7f020000))) 140 .addValue("com.app.test:integer/one", ResourceId(0x7f030000), 141 util::make_unique<BinaryPrimitive>( 142 uint8_t(Res_value::TYPE_INT_DEC), 1u)) 143 .addValue("com.app.test:integer/one", test::parseConfigOrDie("v1"), 144 ResourceId(0x7f030000), 145 util::make_unique<BinaryPrimitive>( 146 uint8_t(Res_value::TYPE_INT_DEC), 2u)) 147 .addString("com.app.test:string/test", ResourceId(0x7f040000), "foo") 148 .addString("com.app.test:layout/bar", ResourceId(0x7f050000), 149 "res/layout/bar.xml") 150 .build(); 151 152 ResTable resTable; 153 ASSERT_TRUE(flatten(table.get(), &resTable)); 154 155 EXPECT_TRUE(exists(&resTable, "com.app.test:id/one", ResourceId(0x7f020000), 156 {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u)); 157 158 EXPECT_TRUE(exists(&resTable, "com.app.test:id/two", ResourceId(0x7f020001), 159 {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u)); 160 161 EXPECT_TRUE(exists(&resTable, "com.app.test:id/three", ResourceId(0x7f020002), 162 {}, Res_value::TYPE_REFERENCE, 0x7f020000u, 0u)); 163 164 EXPECT_TRUE(exists(&resTable, "com.app.test:integer/one", 165 ResourceId(0x7f030000), {}, Res_value::TYPE_INT_DEC, 1u, 166 ResTable_config::CONFIG_VERSION)); 167 168 EXPECT_TRUE(exists(&resTable, "com.app.test:integer/one", 169 ResourceId(0x7f030000), test::parseConfigOrDie("v1"), 170 Res_value::TYPE_INT_DEC, 2u, 171 ResTable_config::CONFIG_VERSION)); 172 173 std::u16string fooStr = u"foo"; 174 ssize_t idx = resTable.getTableStringBlock(0)->indexOfString(fooStr.data(), 175 fooStr.size()); 176 ASSERT_GE(idx, 0); 177 EXPECT_TRUE(exists(&resTable, "com.app.test:string/test", 178 ResourceId(0x7f040000), {}, Res_value::TYPE_STRING, 179 (uint32_t)idx, 0u)); 180 181 std::u16string barPath = u"res/layout/bar.xml"; 182 idx = resTable.getTableStringBlock(0)->indexOfString(barPath.data(), 183 barPath.size()); 184 ASSERT_GE(idx, 0); 185 EXPECT_TRUE(exists(&resTable, "com.app.test:layout/bar", 186 ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, 187 (uint32_t)idx, 0u)); 188} 189 190TEST_F(TableFlattenerTest, FlattenEntriesWithGapsInIds) { 191 std::unique_ptr<ResourceTable> table = 192 test::ResourceTableBuilder() 193 .setPackageId("com.app.test", 0x7f) 194 .addSimple("com.app.test:id/one", ResourceId(0x7f020001)) 195 .addSimple("com.app.test:id/three", ResourceId(0x7f020003)) 196 .build(); 197 198 ResTable resTable; 199 ASSERT_TRUE(flatten(table.get(), &resTable)); 200 201 EXPECT_TRUE(exists(&resTable, "com.app.test:id/one", ResourceId(0x7f020001), 202 {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u)); 203 EXPECT_TRUE(exists(&resTable, "com.app.test:id/three", ResourceId(0x7f020003), 204 {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u)); 205} 206 207TEST_F(TableFlattenerTest, FlattenMinMaxAttributes) { 208 Attribute attr(false); 209 attr.typeMask = android::ResTable_map::TYPE_INTEGER; 210 attr.minInt = 10; 211 attr.maxInt = 23; 212 std::unique_ptr<ResourceTable> table = 213 test::ResourceTableBuilder() 214 .setPackageId("android", 0x01) 215 .addValue("android:attr/foo", ResourceId(0x01010000), 216 util::make_unique<Attribute>(attr)) 217 .build(); 218 219 ResourceTable result; 220 ASSERT_TRUE(flatten(table.get(), &result)); 221 222 Attribute* actualAttr = 223 test::getValue<Attribute>(&result, "android:attr/foo"); 224 ASSERT_NE(nullptr, actualAttr); 225 EXPECT_EQ(attr.isWeak(), actualAttr->isWeak()); 226 EXPECT_EQ(attr.typeMask, actualAttr->typeMask); 227 EXPECT_EQ(attr.minInt, actualAttr->minInt); 228 EXPECT_EQ(attr.maxInt, actualAttr->maxInt); 229} 230 231} // namespace aapt 232