• 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 "ResourceTable.h"
18 #include "Diagnostics.h"
19 #include "ResourceValues.h"
20 #include "test/Test.h"
21 #include "util/Util.h"
22 
23 #include <algorithm>
24 #include <ostream>
25 #include <string>
26 
27 using ::android::StringPiece;
28 using ::testing::Eq;
29 using ::testing::NotNull;
30 using ::testing::StrEq;
31 
32 namespace aapt {
33 
TEST(ResourceTableTest,FailToAddResourceWithBadName)34 TEST(ResourceTableTest, FailToAddResourceWithBadName) {
35   ResourceTable table;
36 
37   EXPECT_FALSE(table.AddResource(
38       test::ParseNameOrDie("android:id/hey,there"), ConfigDescription{}, "",
39       test::ValueBuilder<Id>().SetSource("test.xml", 21u).Build(),
40       test::GetDiagnostics()));
41 
42   EXPECT_FALSE(table.AddResource(
43       test::ParseNameOrDie("android:id/hey:there"), ConfigDescription{}, "",
44       test::ValueBuilder<Id>().SetSource("test.xml", 21u).Build(),
45       test::GetDiagnostics()));
46 }
47 
TEST(ResourceTableTest,AddResourceWithWeirdNameWhenAddingMangledResources)48 TEST(ResourceTableTest, AddResourceWithWeirdNameWhenAddingMangledResources) {
49   ResourceTable table;
50 
51   EXPECT_TRUE(table.AddResourceMangled(
52       test::ParseNameOrDie("android:id/heythere       "), ConfigDescription{}, "",
53       test::ValueBuilder<Id>().SetSource("test.xml", 21u).Build(), test::GetDiagnostics()));
54 }
55 
TEST(ResourceTableTest,AddOneResource)56 TEST(ResourceTableTest, AddOneResource) {
57   ResourceTable table;
58 
59   EXPECT_TRUE(table.AddResource(
60       test::ParseNameOrDie("android:attr/id"), ConfigDescription{}, "",
61       test::ValueBuilder<Id>().SetSource("test/path/file.xml", 23u).Build(),
62       test::GetDiagnostics()));
63 
64   EXPECT_THAT(test::GetValue<Id>(&table, "android:attr/id"), NotNull());
65 }
66 
TEST(ResourceTableTest,AddMultipleResources)67 TEST(ResourceTableTest, AddMultipleResources) {
68   ResourceTable table;
69 
70   ConfigDescription config;
71   ConfigDescription language_config;
72   memcpy(language_config.language, "pl", sizeof(language_config.language));
73 
74   EXPECT_TRUE(table.AddResource(
75       test::ParseNameOrDie("android:attr/layout_width"), config, "",
76       test::ValueBuilder<Id>().SetSource("test/path/file.xml", 10u).Build(),
77       test::GetDiagnostics()));
78 
79   EXPECT_TRUE(table.AddResource(
80       test::ParseNameOrDie("android:attr/id"), config, "",
81       test::ValueBuilder<Id>().SetSource("test/path/file.xml", 12u).Build(),
82       test::GetDiagnostics()));
83 
84   EXPECT_TRUE(table.AddResource(
85       test::ParseNameOrDie("android:string/ok"), config, "",
86       test::ValueBuilder<Id>().SetSource("test/path/file.xml", 14u).Build(),
87       test::GetDiagnostics()));
88 
89   EXPECT_TRUE(table.AddResource(
90       test::ParseNameOrDie("android:string/ok"), language_config, "",
91       test::ValueBuilder<BinaryPrimitive>(android::Res_value{})
92           .SetSource("test/path/file.xml", 20u)
93           .Build(),
94       test::GetDiagnostics()));
95 
96   EXPECT_THAT(test::GetValue<Id>(&table, "android:attr/layout_width"), NotNull());
97   EXPECT_THAT(test::GetValue<Id>(&table, "android:attr/id"), NotNull());
98   EXPECT_THAT(test::GetValue<Id>(&table, "android:string/ok"), NotNull());
99   EXPECT_THAT(test::GetValueForConfig<BinaryPrimitive>(&table, "android:string/ok", language_config), NotNull());
100 }
101 
TEST(ResourceTableTest,OverrideWeakResourceValue)102 TEST(ResourceTableTest, OverrideWeakResourceValue) {
103   ResourceTable table;
104 
105   ASSERT_TRUE(table.AddResource(test::ParseNameOrDie("android:attr/foo"), ConfigDescription{}, "",
106                                 test::AttributeBuilder().SetWeak(true).Build(),
107                                 test::GetDiagnostics()));
108 
109   Attribute* attr = test::GetValue<Attribute>(&table, "android:attr/foo");
110   ASSERT_THAT(attr, NotNull());
111   EXPECT_TRUE(attr->IsWeak());
112 
113   ASSERT_TRUE(table.AddResource(test::ParseNameOrDie("android:attr/foo"), ConfigDescription{}, "",
114                                 util::make_unique<Attribute>(), test::GetDiagnostics()));
115 
116   attr = test::GetValue<Attribute>(&table, "android:attr/foo");
117   ASSERT_THAT(attr, NotNull());
118   EXPECT_FALSE(attr->IsWeak());
119 }
120 
TEST(ResourceTableTest,AllowCompatibleDuplicateAttributes)121 TEST(ResourceTableTest, AllowCompatibleDuplicateAttributes) {
122   ResourceTable table;
123 
124   const ResourceName name = test::ParseNameOrDie("android:attr/foo");
125   Attribute attr_one(android::ResTable_map::TYPE_STRING);
126   attr_one.SetWeak(true);
127   Attribute attr_two(android::ResTable_map::TYPE_STRING | android::ResTable_map::TYPE_REFERENCE);
128   attr_two.SetWeak(true);
129 
130   ASSERT_TRUE(table.AddResource(name, ConfigDescription{}, "",
131                                 util::make_unique<Attribute>(attr_one), test::GetDiagnostics()));
132   ASSERT_TRUE(table.AddResource(name, ConfigDescription{}, "",
133                                 util::make_unique<Attribute>(attr_two), test::GetDiagnostics()));
134 }
135 
TEST(ResourceTableTest,ProductVaryingValues)136 TEST(ResourceTableTest, ProductVaryingValues) {
137   ResourceTable table;
138 
139   EXPECT_TRUE(table.AddResource(test::ParseNameOrDie("android:string/foo"),
140                                 test::ParseConfigOrDie("land"), "tablet",
141                                 util::make_unique<Id>(),
142                                 test::GetDiagnostics()));
143   EXPECT_TRUE(table.AddResource(test::ParseNameOrDie("android:string/foo"),
144                                 test::ParseConfigOrDie("land"), "phone",
145                                 util::make_unique<Id>(),
146                                 test::GetDiagnostics()));
147 
148   EXPECT_THAT(test::GetValueForConfigAndProduct<Id>(&table, "android:string/foo",test::ParseConfigOrDie("land"), "tablet"), NotNull());
149   EXPECT_THAT(test::GetValueForConfigAndProduct<Id>(&table, "android:string/foo",test::ParseConfigOrDie("land"), "phone"), NotNull());
150 
151   Maybe<ResourceTable::SearchResult> sr =
152       table.FindResource(test::ParseNameOrDie("android:string/foo"));
153   ASSERT_TRUE(sr);
154   std::vector<ResourceConfigValue*> values =
155       sr.value().entry->FindAllValues(test::ParseConfigOrDie("land"));
156   ASSERT_EQ(2u, values.size());
157   EXPECT_EQ(std::string("phone"), values[0]->product);
158   EXPECT_EQ(std::string("tablet"), values[1]->product);
159 }
160 
LevelToString(Visibility::Level level)161 static StringPiece LevelToString(Visibility::Level level) {
162   switch (level) {
163     case Visibility::Level::kPrivate:
164       return "private";
165     case Visibility::Level::kPublic:
166       return "private";
167     default:
168       return "undefined";
169   }
170 }
171 
VisibilityOfResource(const ResourceTable & table,const ResourceNameRef & name,Visibility::Level level,const StringPiece & comment)172 static ::testing::AssertionResult VisibilityOfResource(const ResourceTable& table,
173                                                        const ResourceNameRef& name,
174                                                        Visibility::Level level,
175                                                        const StringPiece& comment) {
176   Maybe<ResourceTable::SearchResult> result = table.FindResource(name);
177   if (!result) {
178     return ::testing::AssertionFailure() << "no resource '" << name << "' found in table";
179   }
180 
181   const Visibility& visibility = result.value().entry->visibility;
182   if (visibility.level != level) {
183     return ::testing::AssertionFailure() << "expected visibility " << LevelToString(level)
184                                          << " but got " << LevelToString(visibility.level);
185   }
186 
187   if (visibility.comment != comment) {
188     return ::testing::AssertionFailure() << "expected visibility comment '" << comment
189                                          << "' but got '" << visibility.comment << "'";
190   }
191   return ::testing::AssertionSuccess();
192 }
193 
TEST(ResourceTableTest,SetVisibility)194 TEST(ResourceTableTest, SetVisibility) {
195   using Level = Visibility::Level;
196 
197   ResourceTable table;
198   const ResourceName name = test::ParseNameOrDie("android:string/foo");
199 
200   Visibility visibility;
201   visibility.level = Visibility::Level::kPrivate;
202   visibility.comment = "private";
203   ASSERT_TRUE(table.SetVisibility(name, visibility, test::GetDiagnostics()));
204   ASSERT_TRUE(VisibilityOfResource(table, name, Level::kPrivate, "private"));
205 
206   visibility.level = Visibility::Level::kUndefined;
207   visibility.comment = "undefined";
208   ASSERT_TRUE(table.SetVisibility(name, visibility, test::GetDiagnostics()));
209   ASSERT_TRUE(VisibilityOfResource(table, name, Level::kPrivate, "private"));
210 
211   visibility.level = Visibility::Level::kPublic;
212   visibility.comment = "public";
213   ASSERT_TRUE(table.SetVisibility(name, visibility, test::GetDiagnostics()));
214   ASSERT_TRUE(VisibilityOfResource(table, name, Level::kPublic, "public"));
215 
216   visibility.level = Visibility::Level::kPrivate;
217   visibility.comment = "private";
218   ASSERT_TRUE(table.SetVisibility(name, visibility, test::GetDiagnostics()));
219   ASSERT_TRUE(VisibilityOfResource(table, name, Level::kPublic, "public"));
220 }
221 
TEST(ResourceTableTest,SetAllowNew)222 TEST(ResourceTableTest, SetAllowNew) {
223   ResourceTable table;
224   const ResourceName name = test::ParseNameOrDie("android:string/foo");
225 
226   AllowNew allow_new;
227   Maybe<ResourceTable::SearchResult> result;
228 
229   allow_new.comment = "first";
230   ASSERT_TRUE(table.SetAllowNew(name, allow_new, test::GetDiagnostics()));
231   result = table.FindResource(name);
232   ASSERT_TRUE(result);
233   ASSERT_TRUE(result.value().entry->allow_new);
234   ASSERT_THAT(result.value().entry->allow_new.value().comment, StrEq("first"));
235 
236   allow_new.comment = "second";
237   ASSERT_TRUE(table.SetAllowNew(name, allow_new, test::GetDiagnostics()));
238   result = table.FindResource(name);
239   ASSERT_TRUE(result);
240   ASSERT_TRUE(result.value().entry->allow_new);
241   ASSERT_THAT(result.value().entry->allow_new.value().comment, StrEq("second"));
242 }
243 
TEST(ResourceTableTest,SetOverlayable)244 TEST(ResourceTableTest, SetOverlayable) {
245   ResourceTable table;
246   const ResourceName name = test::ParseNameOrDie("android:string/foo");
247 
248   Overlayable overlayable;
249 
250   overlayable.comment = "first";
251   ASSERT_TRUE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
252   Maybe<ResourceTable::SearchResult> result = table.FindResource(name);
253   ASSERT_TRUE(result);
254   ASSERT_TRUE(result.value().entry->overlayable);
255   ASSERT_THAT(result.value().entry->overlayable.value().comment, StrEq("first"));
256 
257   overlayable.comment = "second";
258   ASSERT_FALSE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
259 }
260 
261 }  // namespace aapt
262