blob: 0065a224bfa741ad94618bc3a3303a233d96b747 [file] [log] [blame]
Adam Lesinski1ab598f2015-08-14 14:26:04 -07001/*
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"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070018
Adam Lesinskibf0bd0f2016-06-01 15:31:50 -070019#include "test/Test.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070020
21namespace aapt {
22
Ryan Mitchell1d008d12021-03-19 14:54:17 -070023struct IdAssignerTests : public ::testing::Test {
24 void SetUp() override {
25 context = test::ContextBuilder().SetCompilationPackage("android").SetPackageId(0x01).Build();
26 }
27 std::unique_ptr<IAaptContext> context;
28};
29
Adam Lesinskice5e56e2016-10-21 17:56:45 -070030::testing::AssertionResult VerifyIds(ResourceTable* table);
Adam Lesinski1ab598f2015-08-14 14:26:04 -070031
Ryan Mitchell1d008d12021-03-19 14:54:17 -070032TEST_F(IdAssignerTests, AssignIds) {
33 auto table = test::ResourceTableBuilder()
34 .AddSimple("android:attr/foo")
35 .AddSimple("android:attr/bar")
36 .AddSimple("android:id/foo")
37 .Build();
Adam Lesinskicacb28f2016-10-19 12:18:14 -070038 IdAssigner assigner;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070039
Adam Lesinskice5e56e2016-10-21 17:56:45 -070040 ASSERT_TRUE(assigner.Consume(context.get(), table.get()));
41 ASSERT_TRUE(VerifyIds(table.get()));
Adam Lesinski1ab598f2015-08-14 14:26:04 -070042}
43
Ryan Mitchell1d008d12021-03-19 14:54:17 -070044TEST_F(IdAssignerTests, AssignIdsWithReservedIds) {
45 auto table = test::ResourceTableBuilder()
46 .AddSimple("android:id/foo", ResourceId(0x01010000))
47 .AddSimple("android:dimen/two")
48 .AddSimple("android:integer/three")
49 .AddSimple("android:string/five")
50 .AddSimple("android:attr/fun", ResourceId(0x01040000))
51 .AddSimple("android:attr/foo", ResourceId(0x01040006))
52 .AddSimple("android:attr/bar")
53 .AddSimple("android:attr/baz")
54 .Build();
Adam Lesinski1ab598f2015-08-14 14:26:04 -070055
Adam Lesinskicacb28f2016-10-19 12:18:14 -070056 IdAssigner assigner;
Adam Lesinskice5e56e2016-10-21 17:56:45 -070057 ASSERT_TRUE(assigner.Consume(context.get(), table.get()));
58 ASSERT_TRUE(VerifyIds(table.get()));
Adam Lesinskibf0bd0f2016-06-01 15:31:50 -070059
Adam Lesinskice5e56e2016-10-21 17:56:45 -070060 Maybe<ResourceTable::SearchResult> maybe_result;
Adam Lesinskibf0bd0f2016-06-01 15:31:50 -070061
Adam Lesinskicacb28f2016-10-19 12:18:14 -070062 // Expect to fill in the gaps between 0x0101XXXX and 0x0104XXXX.
Adam Lesinskibf0bd0f2016-06-01 15:31:50 -070063
Adam Lesinskice5e56e2016-10-21 17:56:45 -070064 maybe_result = table->FindResource(test::ParseNameOrDie("android:dimen/two"));
Adam Lesinskia45893a2017-05-30 15:19:02 -070065 ASSERT_TRUE(maybe_result);
Ryan Mitchell1d008d12021-03-19 14:54:17 -070066 EXPECT_EQ(make_value<ResourceId>(0x01020000), maybe_result.value().entry->id);
Adam Lesinskibf0bd0f2016-06-01 15:31:50 -070067
Adam Lesinskice5e56e2016-10-21 17:56:45 -070068 maybe_result =
69 table->FindResource(test::ParseNameOrDie("android:integer/three"));
Adam Lesinskia45893a2017-05-30 15:19:02 -070070 ASSERT_TRUE(maybe_result);
Ryan Mitchell1d008d12021-03-19 14:54:17 -070071 EXPECT_EQ(make_value<ResourceId>(0x01030000), maybe_result.value().entry->id);
Adam Lesinskibf0bd0f2016-06-01 15:31:50 -070072
Adam Lesinskicacb28f2016-10-19 12:18:14 -070073 // Expect to bypass the reserved 0x0104XXXX IDs and use the next 0x0105XXXX
74 // IDs.
Adam Lesinskibf0bd0f2016-06-01 15:31:50 -070075
Adam Lesinskice5e56e2016-10-21 17:56:45 -070076 maybe_result =
77 table->FindResource(test::ParseNameOrDie("android:string/five"));
Adam Lesinskia45893a2017-05-30 15:19:02 -070078 ASSERT_TRUE(maybe_result);
Ryan Mitchell1d008d12021-03-19 14:54:17 -070079 EXPECT_EQ(make_value<ResourceId>(0x01050000), maybe_result.value().entry->id);
Adam Lesinskibf0bd0f2016-06-01 15:31:50 -070080
Adam Lesinskicacb28f2016-10-19 12:18:14 -070081 // Expect to fill in the gaps between 0x01040000 and 0x01040006.
Adam Lesinskibf0bd0f2016-06-01 15:31:50 -070082
Adam Lesinskice5e56e2016-10-21 17:56:45 -070083 maybe_result = table->FindResource(test::ParseNameOrDie("android:attr/bar"));
Adam Lesinskia45893a2017-05-30 15:19:02 -070084 ASSERT_TRUE(maybe_result);
Ryan Mitchell1d008d12021-03-19 14:54:17 -070085 EXPECT_EQ(make_value<ResourceId>(0x01040001), maybe_result.value().entry->id);
Adam Lesinskibf0bd0f2016-06-01 15:31:50 -070086
Adam Lesinskice5e56e2016-10-21 17:56:45 -070087 maybe_result = table->FindResource(test::ParseNameOrDie("android:attr/baz"));
Adam Lesinskia45893a2017-05-30 15:19:02 -070088 ASSERT_TRUE(maybe_result);
Ryan Mitchell1d008d12021-03-19 14:54:17 -070089 EXPECT_EQ(make_value<ResourceId>(0x01040002), maybe_result.value().entry->id);
Adam Lesinski1ab598f2015-08-14 14:26:04 -070090}
91
Ryan Mitchell1d008d12021-03-19 14:54:17 -070092TEST_F(IdAssignerTests, FailWhenNonUniqueIdsAssigned) {
93 auto table = test::ResourceTableBuilder()
94 .AddSimple("android:attr/foo", ResourceId(0x01040006))
95 .AddSimple("android:attr/bar", ResourceId(0x01040006))
96 .Build();
Adam Lesinskicacb28f2016-10-19 12:18:14 -070097 IdAssigner assigner;
Adam Lesinskice5e56e2016-10-21 17:56:45 -070098 ASSERT_FALSE(assigner.Consume(context.get(), table.get()));
Adam Lesinski1ab598f2015-08-14 14:26:04 -070099}
100
Ryan Mitchell1d008d12021-03-19 14:54:17 -0700101TEST_F(IdAssignerTests, AssignIdsWithIdMap) {
102 auto table = test::ResourceTableBuilder()
103 .AddSimple("android:attr/foo")
104 .AddSimple("android:attr/bar")
105 .Build();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700106 std::unordered_map<ResourceName, ResourceId> id_map = {
107 {test::ParseNameOrDie("android:attr/foo"), ResourceId(0x01010002)}};
108 IdAssigner assigner(&id_map);
109 ASSERT_TRUE(assigner.Consume(context.get(), table.get()));
110 ASSERT_TRUE(VerifyIds(table.get()));
Ryan Mitchell1d008d12021-03-19 14:54:17 -0700111 auto result = table->FindResource(test::ParseNameOrDie("android:attr/foo"));
Adam Lesinskia45893a2017-05-30 15:19:02 -0700112 ASSERT_TRUE(result);
Adam Lesinskibf0bd0f2016-06-01 15:31:50 -0700113
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700114 const ResourceTable::SearchResult& search_result = result.value();
Ryan Mitchell1d008d12021-03-19 14:54:17 -0700115 EXPECT_EQ(make_value<ResourceId>(0x01010002), search_result.entry->id);
116}
117
118TEST_F(IdAssignerTests, UseAllEntryIds) {
119 ResourceTable table;
120 const size_t max_entry_id = std::numeric_limits<uint16_t>::max();
121 for (size_t i = 0; i <= max_entry_id; i++) {
122 ASSERT_TRUE(
123 table.AddResource(NewResourceBuilder("android:attr/res" + std::to_string(i)).Build(),
124 context->GetDiagnostics()));
125 }
126 IdAssigner assigner;
127 ASSERT_TRUE(assigner.Consume(context.get(), &table));
128}
129
130TEST_F(IdAssignerTests, ExaustEntryIds) {
131 ResourceTable table;
132 const size_t max_entry_id = std::numeric_limits<uint16_t>::max() + 1u;
133 for (size_t i = 0; i <= max_entry_id; i++) {
134 ASSERT_TRUE(
135 table.AddResource(NewResourceBuilder("android:attr/res" + std::to_string(i)).Build(),
136 context->GetDiagnostics()));
137 }
138 IdAssigner assigner;
139 ASSERT_FALSE(assigner.Consume(context.get(), &table));
140}
141
142TEST_F(IdAssignerTests, ExaustEntryIdsLastIdIsPublic) {
143 ResourceTable table;
144 ASSERT_TRUE(table.AddResource(NewResourceBuilder("android:attr/res").SetId(0x0101ffff).Build(),
145 context->GetDiagnostics()));
146 const size_t max_entry_id = std::numeric_limits<uint16_t>::max();
147 for (size_t i = 0; i <= max_entry_id; i++) {
148 ASSERT_TRUE(
149 table.AddResource(NewResourceBuilder("android:attr/res" + std::to_string(i)).Build(),
150 context->GetDiagnostics()));
151 }
152 IdAssigner assigner;
153 ASSERT_FALSE(assigner.Consume(context.get(), &table));
Adam Lesinskibf0bd0f2016-06-01 15:31:50 -0700154}
155
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700156::testing::AssertionResult VerifyIds(ResourceTable* table) {
157 std::set<uint8_t> package_ids;
Ryan Mitchell1d008d12021-03-19 14:54:17 -0700158 auto table_view = table->GetPartitionedView();
159 for (auto& package : table_view.packages) {
160 if (!package.id) {
161 return ::testing::AssertionFailure() << "package " << package.name << " has no ID";
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700162 }
163
Ryan Mitchell1d008d12021-03-19 14:54:17 -0700164 if (!package_ids.insert(package.id.value()).second) {
165 return ::testing::AssertionFailure() << "package " << package.name << " has non-unique ID "
166 << std::hex << (int)package.id.value() << std::dec;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700167 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700168 }
169
Ryan Mitchell1d008d12021-03-19 14:54:17 -0700170 for (auto& package : table_view.packages) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700171 std::set<uint8_t> type_ids;
Ryan Mitchell1d008d12021-03-19 14:54:17 -0700172 for (auto& type : package.types) {
173 if (!type.id) {
174 return ::testing::AssertionFailure()
175 << "type " << type.type << " of package " << package.name << " has no ID";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700176 }
177
Ryan Mitchell1d008d12021-03-19 14:54:17 -0700178 if (!type_ids.insert(type.id.value()).second) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700179 return ::testing::AssertionFailure()
Ryan Mitchell1d008d12021-03-19 14:54:17 -0700180 << "type " << type.type << " of package " << package.name << " has non-unique ID "
181 << std::hex << (int)type.id.value() << std::dec;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700182 }
183 }
184
Ryan Mitchell1d008d12021-03-19 14:54:17 -0700185 for (auto& type : package.types) {
186 std::set<ResourceId> entry_ids;
187 for (auto& entry : type.entries) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700188 if (!entry->id) {
189 return ::testing::AssertionFailure()
Ryan Mitchell1d008d12021-03-19 14:54:17 -0700190 << "entry " << entry->name << " of type " << type.type << " of package "
191 << package.name << " has no ID";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700192 }
193
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700194 if (!entry_ids.insert(entry->id.value()).second) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700195 return ::testing::AssertionFailure()
Ryan Mitchell1d008d12021-03-19 14:54:17 -0700196 << "entry " << entry->name << " of type " << type.type << " of package "
197 << package.name << " has non-unique ID " << std::hex << entry->id.value()
198 << std::dec;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700199 }
200 }
201 }
202 }
203 return ::testing::AssertionSuccess() << "all IDs are unique and assigned";
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700204}
205
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700206} // namespace aapt