• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TEST(IdAssignerTest,AssignIds)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 
TEST(IdAssignerTest,AssignIdsWithReservedIds)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 
TEST(IdAssignerTest,FailWhenNonUniqueIdsAssigned)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 
TEST(IdAssignerTest,AssignIdsWithIdMap)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 
VerifyIds(ResourceTable * table)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