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 "compile/IdAssigner.h" 18 19 #include "test/Test.h" 20 21 namespace aapt { 22 23 ::testing::AssertionResult VerifyIds(ResourceTable* table); 24 25 TEST(IdAssignerTest, AssignIds) { 26 std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() 27 .AddSimple("android:attr/foo") 28 .AddSimple("android:attr/bar") 29 .AddSimple("android:id/foo") 30 .SetPackageId("android", 0x01) 31 .Build(); 32 33 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 34 IdAssigner assigner; 35 36 ASSERT_TRUE(assigner.Consume(context.get(), table.get())); 37 ASSERT_TRUE(VerifyIds(table.get())); 38 } 39 40 TEST(IdAssignerTest, AssignIdsWithReservedIds) { 41 std::unique_ptr<ResourceTable> table = 42 test::ResourceTableBuilder() 43 .AddSimple("android:id/foo", ResourceId(0x01010000)) 44 .AddSimple("android:dimen/two") 45 .AddSimple("android:integer/three") 46 .AddSimple("android:string/five") 47 .AddSimple("android:attr/fun", ResourceId(0x01040000)) 48 .AddSimple("android:attr/foo", ResourceId(0x01040006)) 49 .AddSimple("android:attr/bar") 50 .AddSimple("android:attr/baz") 51 .AddSimple("app:id/biz") 52 .SetPackageId("android", 0x01) 53 .SetPackageId("app", 0x7f) 54 .Build(); 55 56 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 57 IdAssigner assigner; 58 59 ASSERT_TRUE(assigner.Consume(context.get(), table.get())); 60 ASSERT_TRUE(VerifyIds(table.get())); 61 62 Maybe<ResourceTable::SearchResult> maybe_result; 63 64 // Expect to fill in the gaps between 0x0101XXXX and 0x0104XXXX. 65 66 maybe_result = table->FindResource(test::ParseNameOrDie("android:dimen/two")); 67 ASSERT_TRUE(maybe_result); 68 EXPECT_EQ(make_value<uint8_t>(2), maybe_result.value().type->id); 69 70 maybe_result = 71 table->FindResource(test::ParseNameOrDie("android:integer/three")); 72 ASSERT_TRUE(maybe_result); 73 EXPECT_EQ(make_value<uint8_t>(3), maybe_result.value().type->id); 74 75 // Expect to bypass the reserved 0x0104XXXX IDs and use the next 0x0105XXXX 76 // IDs. 77 78 maybe_result = 79 table->FindResource(test::ParseNameOrDie("android:string/five")); 80 ASSERT_TRUE(maybe_result); 81 EXPECT_EQ(make_value<uint8_t>(5), maybe_result.value().type->id); 82 83 // Expect to fill in the gaps between 0x01040000 and 0x01040006. 84 85 maybe_result = table->FindResource(test::ParseNameOrDie("android:attr/bar")); 86 ASSERT_TRUE(maybe_result); 87 EXPECT_EQ(make_value<uint16_t>(1), maybe_result.value().entry->id); 88 89 maybe_result = table->FindResource(test::ParseNameOrDie("android:attr/baz")); 90 ASSERT_TRUE(maybe_result); 91 EXPECT_EQ(make_value<uint16_t>(2), maybe_result.value().entry->id); 92 } 93 94 TEST(IdAssignerTest, FailWhenNonUniqueIdsAssigned) { 95 std::unique_ptr<ResourceTable> table = 96 test::ResourceTableBuilder() 97 .AddSimple("android:attr/foo", ResourceId(0x01040006)) 98 .AddSimple("android:attr/bar", ResourceId(0x01040006)) 99 .SetPackageId("android", 0x01) 100 .SetPackageId("app", 0x7f) 101 .Build(); 102 103 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 104 IdAssigner assigner; 105 106 ASSERT_FALSE(assigner.Consume(context.get(), table.get())); 107 } 108 109 TEST(IdAssignerTest, AssignIdsWithIdMap) { 110 std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() 111 .AddSimple("android:attr/foo") 112 .AddSimple("android:attr/bar") 113 .SetPackageId("android", 0x01) 114 .Build(); 115 116 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 117 std::unordered_map<ResourceName, ResourceId> id_map = { 118 {test::ParseNameOrDie("android:attr/foo"), ResourceId(0x01010002)}}; 119 IdAssigner assigner(&id_map); 120 ASSERT_TRUE(assigner.Consume(context.get(), table.get())); 121 ASSERT_TRUE(VerifyIds(table.get())); 122 Maybe<ResourceTable::SearchResult> result = 123 table->FindResource(test::ParseNameOrDie("android:attr/foo")); 124 ASSERT_TRUE(result); 125 126 const ResourceTable::SearchResult& search_result = result.value(); 127 EXPECT_EQ(make_value<uint8_t>(0x01), search_result.package->id); 128 EXPECT_EQ(make_value<uint8_t>(0x01), search_result.type->id); 129 EXPECT_EQ(make_value<uint16_t>(0x0002), search_result.entry->id); 130 } 131 132 ::testing::AssertionResult VerifyIds(ResourceTable* table) { 133 std::set<uint8_t> package_ids; 134 for (auto& package : table->packages) { 135 if (!package->id) { 136 return ::testing::AssertionFailure() << "package " << package->name 137 << " has no ID"; 138 } 139 140 if (!package_ids.insert(package->id.value()).second) { 141 return ::testing::AssertionFailure() 142 << "package " << package->name << " has non-unique ID " << std::hex 143 << (int)package->id.value() << std::dec; 144 } 145 } 146 147 for (auto& package : table->packages) { 148 std::set<uint8_t> type_ids; 149 for (auto& type : package->types) { 150 if (!type->id) { 151 return ::testing::AssertionFailure() << "type " << type->type 152 << " of package " << package->name 153 << " has no ID"; 154 } 155 156 if (!type_ids.insert(type->id.value()).second) { 157 return ::testing::AssertionFailure() 158 << "type " << type->type << " of package " << package->name 159 << " has non-unique ID " << std::hex << (int)type->id.value() 160 << std::dec; 161 } 162 } 163 164 for (auto& type : package->types) { 165 std::set<uint16_t> entry_ids; 166 for (auto& entry : type->entries) { 167 if (!entry->id) { 168 return ::testing::AssertionFailure() 169 << "entry " << entry->name << " of type " << type->type 170 << " of package " << package->name << " has no ID"; 171 } 172 173 if (!entry_ids.insert(entry->id.value()).second) { 174 return ::testing::AssertionFailure() 175 << "entry " << entry->name << " of type " << type->type 176 << " of package " << package->name << " has non-unique ID " 177 << std::hex << (int)entry->id.value() << std::dec; 178 } 179 } 180 } 181 } 182 return ::testing::AssertionSuccess() << "all IDs are unique and assigned"; 183 } 184 185 } // namespace aapt 186