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