blob: 31095c4d88c877756bc2f6eaeea45ece57225967 [file] [log] [blame]
Adam Lesinski6f6ceb72014-11-14 14:48:12 -08001/*
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 "ResourceTable.h"
Adam Lesinskicacb28f2016-10-19 12:18:14 -070018#include "Diagnostics.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080019#include "ResourceValues.h"
Adam Lesinskid0f116b2016-07-08 15:00:32 -070020#include "test/Test.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070021#include "util/Util.h"
22
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080023#include <algorithm>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080024#include <ostream>
25#include <string>
26
MÃ¥rten Kongstad24c9aa62018-06-20 08:46:41 +020027using ::android::ConfigDescription;
Adam Lesinski71be7052017-12-12 16:48:07 -080028using ::android::StringPiece;
29using ::testing::Eq;
Adam Lesinskia45893a2017-05-30 15:19:02 -070030using ::testing::NotNull;
Adam Lesinski71be7052017-12-12 16:48:07 -080031using ::testing::StrEq;
Adam Lesinskia45893a2017-05-30 15:19:02 -070032
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080033namespace aapt {
34
Adam Lesinskicc5609d2016-04-05 12:41:07 -070035TEST(ResourceTableTest, FailToAddResourceWithBadName) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070036 ResourceTable table;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080037
Adam Lesinskice5e56e2016-10-21 17:56:45 -070038 EXPECT_FALSE(table.AddResource(
39 test::ParseNameOrDie("android:id/hey,there"), ConfigDescription{}, "",
40 test::ValueBuilder<Id>().SetSource("test.xml", 21u).Build(),
41 test::GetDiagnostics()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080042
Adam Lesinskice5e56e2016-10-21 17:56:45 -070043 EXPECT_FALSE(table.AddResource(
44 test::ParseNameOrDie("android:id/hey:there"), ConfigDescription{}, "",
45 test::ValueBuilder<Id>().SetSource("test.xml", 21u).Build(),
46 test::GetDiagnostics()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080047}
48
Adam Lesinskib1afa072017-03-29 13:52:38 -070049TEST(ResourceTableTest, AddResourceWithWeirdNameWhenAddingMangledResources) {
50 ResourceTable table;
51
Adam Lesinski71be7052017-12-12 16:48:07 -080052 EXPECT_TRUE(table.AddResourceMangled(
Adam Lesinskib1afa072017-03-29 13:52:38 -070053 test::ParseNameOrDie("android:id/heythere "), ConfigDescription{}, "",
54 test::ValueBuilder<Id>().SetSource("test.xml", 21u).Build(), test::GetDiagnostics()));
55}
56
Adam Lesinskicc5609d2016-04-05 12:41:07 -070057TEST(ResourceTableTest, AddOneResource) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070058 ResourceTable table;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080059
Adam Lesinskice5e56e2016-10-21 17:56:45 -070060 EXPECT_TRUE(table.AddResource(
61 test::ParseNameOrDie("android:attr/id"), ConfigDescription{}, "",
62 test::ValueBuilder<Id>().SetSource("test/path/file.xml", 23u).Build(),
63 test::GetDiagnostics()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080064
Adam Lesinskia45893a2017-05-30 15:19:02 -070065 EXPECT_THAT(test::GetValue<Id>(&table, "android:attr/id"), NotNull());
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080066}
67
Adam Lesinskicc5609d2016-04-05 12:41:07 -070068TEST(ResourceTableTest, AddMultipleResources) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070069 ResourceTable table;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080070
Adam Lesinskicacb28f2016-10-19 12:18:14 -070071 ConfigDescription config;
Adam Lesinskice5e56e2016-10-21 17:56:45 -070072 ConfigDescription language_config;
73 memcpy(language_config.language, "pl", sizeof(language_config.language));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080074
Adam Lesinskice5e56e2016-10-21 17:56:45 -070075 EXPECT_TRUE(table.AddResource(
76 test::ParseNameOrDie("android:attr/layout_width"), config, "",
77 test::ValueBuilder<Id>().SetSource("test/path/file.xml", 10u).Build(),
78 test::GetDiagnostics()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080079
Adam Lesinskice5e56e2016-10-21 17:56:45 -070080 EXPECT_TRUE(table.AddResource(
81 test::ParseNameOrDie("android:attr/id"), config, "",
82 test::ValueBuilder<Id>().SetSource("test/path/file.xml", 12u).Build(),
83 test::GetDiagnostics()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080084
Adam Lesinskice5e56e2016-10-21 17:56:45 -070085 EXPECT_TRUE(table.AddResource(
86 test::ParseNameOrDie("android:string/ok"), config, "",
87 test::ValueBuilder<Id>().SetSource("test/path/file.xml", 14u).Build(),
88 test::GetDiagnostics()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080089
Adam Lesinskice5e56e2016-10-21 17:56:45 -070090 EXPECT_TRUE(table.AddResource(
91 test::ParseNameOrDie("android:string/ok"), language_config, "",
Adam Lesinskicacb28f2016-10-19 12:18:14 -070092 test::ValueBuilder<BinaryPrimitive>(android::Res_value{})
Adam Lesinskice5e56e2016-10-21 17:56:45 -070093 .SetSource("test/path/file.xml", 20u)
94 .Build(),
95 test::GetDiagnostics()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080096
Adam Lesinskia45893a2017-05-30 15:19:02 -070097 EXPECT_THAT(test::GetValue<Id>(&table, "android:attr/layout_width"), NotNull());
98 EXPECT_THAT(test::GetValue<Id>(&table, "android:attr/id"), NotNull());
99 EXPECT_THAT(test::GetValue<Id>(&table, "android:string/ok"), NotNull());
100 EXPECT_THAT(test::GetValueForConfig<BinaryPrimitive>(&table, "android:string/ok", language_config), NotNull());
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800101}
102
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700103TEST(ResourceTableTest, OverrideWeakResourceValue) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700104 ResourceTable table;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800105
Adam Lesinski73bff1e2017-12-08 16:06:10 -0800106 ASSERT_TRUE(table.AddResource(test::ParseNameOrDie("android:attr/foo"), ConfigDescription{}, "",
107 test::AttributeBuilder().SetWeak(true).Build(),
108 test::GetDiagnostics()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800109
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700110 Attribute* attr = test::GetValue<Attribute>(&table, "android:attr/foo");
Adam Lesinskia45893a2017-05-30 15:19:02 -0700111 ASSERT_THAT(attr, NotNull());
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700112 EXPECT_TRUE(attr->IsWeak());
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800113
Adam Lesinski73bff1e2017-12-08 16:06:10 -0800114 ASSERT_TRUE(table.AddResource(test::ParseNameOrDie("android:attr/foo"), ConfigDescription{}, "",
115 util::make_unique<Attribute>(), test::GetDiagnostics()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800116
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700117 attr = test::GetValue<Attribute>(&table, "android:attr/foo");
Adam Lesinskia45893a2017-05-30 15:19:02 -0700118 ASSERT_THAT(attr, NotNull());
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700119 EXPECT_FALSE(attr->IsWeak());
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800120}
121
Adam Lesinski73bff1e2017-12-08 16:06:10 -0800122TEST(ResourceTableTest, AllowCompatibleDuplicateAttributes) {
123 ResourceTable table;
124
125 const ResourceName name = test::ParseNameOrDie("android:attr/foo");
126 Attribute attr_one(android::ResTable_map::TYPE_STRING);
127 attr_one.SetWeak(true);
128 Attribute attr_two(android::ResTable_map::TYPE_STRING | android::ResTable_map::TYPE_REFERENCE);
129 attr_two.SetWeak(true);
130
131 ASSERT_TRUE(table.AddResource(name, ConfigDescription{}, "",
132 util::make_unique<Attribute>(attr_one), test::GetDiagnostics()));
133 ASSERT_TRUE(table.AddResource(name, ConfigDescription{}, "",
134 util::make_unique<Attribute>(attr_two), test::GetDiagnostics()));
135}
136
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700137TEST(ResourceTableTest, ProductVaryingValues) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700138 ResourceTable table;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800139
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700140 EXPECT_TRUE(table.AddResource(test::ParseNameOrDie("android:string/foo"),
141 test::ParseConfigOrDie("land"), "tablet",
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700142 util::make_unique<Id>(),
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700143 test::GetDiagnostics()));
144 EXPECT_TRUE(table.AddResource(test::ParseNameOrDie("android:string/foo"),
145 test::ParseConfigOrDie("land"), "phone",
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700146 util::make_unique<Id>(),
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700147 test::GetDiagnostics()));
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800148
Adam Lesinskia45893a2017-05-30 15:19:02 -0700149 EXPECT_THAT(test::GetValueForConfigAndProduct<Id>(&table, "android:string/foo",test::ParseConfigOrDie("land"), "tablet"), NotNull());
150 EXPECT_THAT(test::GetValueForConfigAndProduct<Id>(&table, "android:string/foo",test::ParseConfigOrDie("land"), "phone"), NotNull());
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800151
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700152 Maybe<ResourceTable::SearchResult> sr =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700153 table.FindResource(test::ParseNameOrDie("android:string/foo"));
Adam Lesinskia45893a2017-05-30 15:19:02 -0700154 ASSERT_TRUE(sr);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700155 std::vector<ResourceConfigValue*> values =
Adam Lesinskib1afa072017-03-29 13:52:38 -0700156 sr.value().entry->FindAllValues(test::ParseConfigOrDie("land"));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700157 ASSERT_EQ(2u, values.size());
158 EXPECT_EQ(std::string("phone"), values[0]->product);
159 EXPECT_EQ(std::string("tablet"), values[1]->product);
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800160}
161
Adam Lesinski71be7052017-12-12 16:48:07 -0800162static StringPiece LevelToString(Visibility::Level level) {
163 switch (level) {
164 case Visibility::Level::kPrivate:
165 return "private";
166 case Visibility::Level::kPublic:
167 return "private";
168 default:
169 return "undefined";
170 }
171}
172
173static ::testing::AssertionResult VisibilityOfResource(const ResourceTable& table,
174 const ResourceNameRef& name,
175 Visibility::Level level,
176 const StringPiece& comment) {
177 Maybe<ResourceTable::SearchResult> result = table.FindResource(name);
178 if (!result) {
179 return ::testing::AssertionFailure() << "no resource '" << name << "' found in table";
180 }
181
182 const Visibility& visibility = result.value().entry->visibility;
183 if (visibility.level != level) {
184 return ::testing::AssertionFailure() << "expected visibility " << LevelToString(level)
185 << " but got " << LevelToString(visibility.level);
186 }
187
188 if (visibility.comment != comment) {
189 return ::testing::AssertionFailure() << "expected visibility comment '" << comment
190 << "' but got '" << visibility.comment << "'";
191 }
192 return ::testing::AssertionSuccess();
193}
194
195TEST(ResourceTableTest, SetVisibility) {
196 using Level = Visibility::Level;
197
198 ResourceTable table;
199 const ResourceName name = test::ParseNameOrDie("android:string/foo");
200
201 Visibility visibility;
202 visibility.level = Visibility::Level::kPrivate;
203 visibility.comment = "private";
204 ASSERT_TRUE(table.SetVisibility(name, visibility, test::GetDiagnostics()));
205 ASSERT_TRUE(VisibilityOfResource(table, name, Level::kPrivate, "private"));
206
207 visibility.level = Visibility::Level::kUndefined;
208 visibility.comment = "undefined";
209 ASSERT_TRUE(table.SetVisibility(name, visibility, test::GetDiagnostics()));
210 ASSERT_TRUE(VisibilityOfResource(table, name, Level::kPrivate, "private"));
211
212 visibility.level = Visibility::Level::kPublic;
213 visibility.comment = "public";
214 ASSERT_TRUE(table.SetVisibility(name, visibility, test::GetDiagnostics()));
215 ASSERT_TRUE(VisibilityOfResource(table, name, Level::kPublic, "public"));
216
217 visibility.level = Visibility::Level::kPrivate;
218 visibility.comment = "private";
219 ASSERT_TRUE(table.SetVisibility(name, visibility, test::GetDiagnostics()));
220 ASSERT_TRUE(VisibilityOfResource(table, name, Level::kPublic, "public"));
221}
222
223TEST(ResourceTableTest, SetAllowNew) {
224 ResourceTable table;
225 const ResourceName name = test::ParseNameOrDie("android:string/foo");
226
227 AllowNew allow_new;
228 Maybe<ResourceTable::SearchResult> result;
229
230 allow_new.comment = "first";
231 ASSERT_TRUE(table.SetAllowNew(name, allow_new, test::GetDiagnostics()));
232 result = table.FindResource(name);
233 ASSERT_TRUE(result);
234 ASSERT_TRUE(result.value().entry->allow_new);
235 ASSERT_THAT(result.value().entry->allow_new.value().comment, StrEq("first"));
236
237 allow_new.comment = "second";
238 ASSERT_TRUE(table.SetAllowNew(name, allow_new, test::GetDiagnostics()));
239 result = table.FindResource(name);
240 ASSERT_TRUE(result);
241 ASSERT_TRUE(result.value().entry->allow_new);
242 ASSERT_THAT(result.value().entry->allow_new.value().comment, StrEq("second"));
243}
244
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800245TEST(ResourceTableTest, SetOverlayable) {
Adam Lesinski71be7052017-12-12 16:48:07 -0800246 ResourceTable table;
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800247 Overlayable overlayable{};
248 overlayable.policies |= Overlayable::Policy::kProduct;
249 overlayable.policies |= Overlayable::Policy::kProductServices;
250 overlayable.comment = "comment";
251
Adam Lesinski71be7052017-12-12 16:48:07 -0800252 const ResourceName name = test::ParseNameOrDie("android:string/foo");
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800253 ASSERT_TRUE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
254 Maybe<ResourceTable::SearchResult> search_result = table.FindResource(name);
Adam Lesinski71be7052017-12-12 16:48:07 -0800255
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800256 ASSERT_TRUE(search_result);
257 ASSERT_TRUE(search_result.value().entry->overlayable);
Adam Lesinski71be7052017-12-12 16:48:07 -0800258
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800259 Overlayable& result_overlayable = search_result.value().entry->overlayable.value();
260 ASSERT_THAT(result_overlayable.comment, StrEq("comment"));
261 EXPECT_THAT(result_overlayable.policies, Eq(Overlayable::Policy::kProduct
262 | Overlayable::Policy::kProductServices));
Ryan Mitchelle4e989c2018-10-29 02:21:50 -0700263}
264
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800265TEST(ResourceTableTest, AddDuplicateOverlayableSamePolicyFail) {
Ryan Mitchelle4e989c2018-10-29 02:21:50 -0700266 ResourceTable table;
267 const ResourceName name = test::ParseNameOrDie("android:string/foo");
268
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800269 Overlayable overlayable{};
270 overlayable.policies = Overlayable::Policy::kProduct;
271 ASSERT_TRUE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
Ryan Mitchelle4e989c2018-10-29 02:21:50 -0700272
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800273 Overlayable overlayable2{};
274 overlayable2.policies = Overlayable::Policy::kProduct;
275 ASSERT_FALSE(table.SetOverlayable(name, overlayable2, test::GetDiagnostics()));
Ryan Mitchelle4e989c2018-10-29 02:21:50 -0700276}
277
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800278TEST(ResourceTableTest, AddDuplicateOverlayableDifferentPolicyFail) {
Ryan Mitchelle4e989c2018-10-29 02:21:50 -0700279 ResourceTable table;
280 const ResourceName name = test::ParseNameOrDie("android:string/foo");
281
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800282 Overlayable overlayable{};
283 overlayable.policies = Overlayable::Policy::kProduct;
284 ASSERT_TRUE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
Ryan Mitchelle4e989c2018-10-29 02:21:50 -0700285
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800286 Overlayable overlayable2{};
287 overlayable2.policies = Overlayable::Policy::kVendor;
288 ASSERT_FALSE(table.SetOverlayable(name, overlayable2, test::GetDiagnostics()));
Adam Lesinski71be7052017-12-12 16:48:07 -0800289}
290
Ryan Mitchell8d4ee972018-08-27 11:24:04 -0700291TEST(ResourceTableTest, AllowDuplictaeResourcesNames) {
292 ResourceTable table(/* validate_resources */ false);
293
294 const ResourceName foo_name = test::ParseNameOrDie("android:bool/foo");
295 ASSERT_TRUE(table.AddResourceWithId(foo_name, ResourceId(0x7f0100ff), ConfigDescription{} , "",
296 test::BuildPrimitive(android::Res_value::TYPE_INT_BOOLEAN, 0),
297 test::GetDiagnostics()));
298 ASSERT_TRUE(table.AddResourceWithId(foo_name, ResourceId(0x7f010100), ConfigDescription{} , "",
299 test::BuildPrimitive(android::Res_value::TYPE_INT_BOOLEAN, 1),
300 test::GetDiagnostics()));
301
302 ASSERT_TRUE(table.SetVisibilityWithId(foo_name, Visibility{Visibility::Level::kPublic},
303 ResourceId(0x7f0100ff), test::GetDiagnostics()));
304 ASSERT_TRUE(table.SetVisibilityWithId(foo_name, Visibility{Visibility::Level::kPrivate},
305 ResourceId(0x7f010100), test::GetDiagnostics()));
306
307 auto package = table.FindPackageById(0x7f);
308 ASSERT_THAT(package, NotNull());
309 auto type = package->FindType(ResourceType::kBool);
310 ASSERT_THAT(type, NotNull());
311
312 auto entry1 = type->FindEntry("foo", 0x00ff);
313 ASSERT_THAT(entry1, NotNull());
314 ASSERT_THAT(entry1->id, Eq(0x00ff));
315 ASSERT_THAT(entry1->values[0], NotNull());
316 ASSERT_THAT(entry1->values[0]->value, NotNull());
317 ASSERT_THAT(ValueCast<BinaryPrimitive>(entry1->values[0]->value.get()), NotNull());
318 ASSERT_THAT(ValueCast<BinaryPrimitive>(entry1->values[0]->value.get())->value.data, Eq(0u));
319 ASSERT_THAT(entry1->visibility.level, Visibility::Level::kPublic);
320
321 auto entry2 = type->FindEntry("foo", 0x0100);
322 ASSERT_THAT(entry2, NotNull());
323 ASSERT_THAT(entry2->id, Eq(0x0100));
324 ASSERT_THAT(entry2->values[0], NotNull());
325 ASSERT_THAT(entry1->values[0]->value, NotNull());
326 ASSERT_THAT(ValueCast<BinaryPrimitive>(entry2->values[0]->value.get()), NotNull());
327 ASSERT_THAT(ValueCast<BinaryPrimitive>(entry2->values[0]->value.get())->value.data, Eq(1u));
328 ASSERT_THAT(entry2->visibility.level, Visibility::Level::kPrivate);
329}
330
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700331} // namespace aapt