blob: 9649a4de2fe418aa84b266a40141ee06f05057a5 [file] [log] [blame]
Adam Lesinski8cdca1b2017-09-28 15:50:03 -07001/*
2 * Copyright (C) 2016 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
Adam Lesinski46708052017-09-29 14:49:15 -070017#include "format/proto/ProtoSerialize.h"
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070018
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070019#include "ResourceUtils.h"
Adam Lesinski46708052017-09-29 14:49:15 -070020#include "format/proto/ProtoDeserialize.h"
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070021#include "test/Test.h"
22
23using ::android::StringPiece;
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070024using ::testing::Eq;
25using ::testing::IsEmpty;
26using ::testing::NotNull;
27using ::testing::SizeIs;
28using ::testing::StrEq;
29
30namespace aapt {
31
Adam Lesinski8780eb62017-10-31 17:44:39 -070032class MockFileCollection : public io::IFileCollection {
33 public:
34 MOCK_METHOD1(FindFile, io::IFile*(const StringPiece& path));
35 MOCK_METHOD0(Iterator, std::unique_ptr<io::IFileCollectionIterator>());
36};
37
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070038TEST(ProtoSerializeTest, SerializeSinglePackage) {
39 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
40 std::unique_ptr<ResourceTable> table =
41 test::ResourceTableBuilder()
42 .SetPackageId("com.app.a", 0x7f)
43 .AddFileReference("com.app.a:layout/main", ResourceId(0x7f020000), "res/layout/main.xml")
44 .AddReference("com.app.a:layout/other", ResourceId(0x7f020001), "com.app.a:layout/main")
45 .AddString("com.app.a:string/text", {}, "hi")
46 .AddValue("com.app.a:id/foo", {}, util::make_unique<Id>())
47 .SetSymbolState("com.app.a:bool/foo", {}, SymbolState::kUndefined, true /*allow_new*/)
48 .Build();
49
50 Symbol public_symbol;
51 public_symbol.state = SymbolState::kPublic;
52 ASSERT_TRUE(table->SetSymbolState(test::ParseNameOrDie("com.app.a:layout/main"),
53 ResourceId(0x7f020000), public_symbol,
54 context->GetDiagnostics()));
55
56 Id* id = test::GetValue<Id>(table.get(), "com.app.a:id/foo");
57 ASSERT_THAT(id, NotNull());
58
59 // Make a plural.
60 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
61 plural->values[Plural::One] = util::make_unique<String>(table->string_pool.MakeRef("one"));
62 ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:plurals/hey"), ConfigDescription{},
63 {}, std::move(plural), context->GetDiagnostics()));
64
65 // Make a styled string.
66 StyleString style_string;
67 style_string.str = "hello";
68 style_string.spans.push_back(Span{"b", 0u, 4u});
69 ASSERT_TRUE(
70 table->AddResource(test::ParseNameOrDie("com.app.a:string/styled"), ConfigDescription{}, {},
71 util::make_unique<StyledString>(table->string_pool.MakeRef(style_string)),
72 context->GetDiagnostics()));
73
74 // Make a resource with different products.
75 ASSERT_TRUE(table->AddResource(
76 test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), {},
77 test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u), context->GetDiagnostics()));
78 ASSERT_TRUE(table->AddResource(
79 test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), "tablet",
80 test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u), context->GetDiagnostics()));
81
82 // Make a reference with both resource name and resource ID.
83 // The reference should point to a resource outside of this table to test that both name and id
84 // get serialized.
85 Reference expected_ref;
86 expected_ref.name = test::ParseNameOrDie("android:layout/main");
87 expected_ref.id = ResourceId(0x01020000);
88 ASSERT_TRUE(table->AddResource(
89 test::ParseNameOrDie("com.app.a:layout/abc"), ConfigDescription::DefaultConfig(), {},
90 util::make_unique<Reference>(expected_ref), context->GetDiagnostics()));
91
92 pb::ResourceTable pb_table;
93 SerializeTableToPb(*table, &pb_table);
94
Adam Lesinski8780eb62017-10-31 17:44:39 -070095 test::TestFile file_a("res/layout/main.xml");
96 MockFileCollection files;
97 EXPECT_CALL(files, FindFile(Eq("res/layout/main.xml")))
98 .WillRepeatedly(::testing::Return(&file_a));
99
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700100 ResourceTable new_table;
101 std::string error;
Adam Lesinski8780eb62017-10-31 17:44:39 -0700102 ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700103 EXPECT_THAT(error, IsEmpty());
104
105 Id* new_id = test::GetValue<Id>(&new_table, "com.app.a:id/foo");
106 ASSERT_THAT(new_id, NotNull());
107 EXPECT_THAT(new_id->IsWeak(), Eq(id->IsWeak()));
108
109 Maybe<ResourceTable::SearchResult> result =
110 new_table.FindResource(test::ParseNameOrDie("com.app.a:layout/main"));
111 ASSERT_TRUE(result);
112
113 EXPECT_THAT(result.value().type->symbol_status.state, Eq(SymbolState::kPublic));
114 EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kPublic));
115
116 result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
117 ASSERT_TRUE(result);
118 EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kUndefined));
119 EXPECT_TRUE(result.value().entry->symbol_status.allow_new);
120
121 // Find the product-dependent values
122 BinaryPrimitive* prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
123 &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "");
124 ASSERT_THAT(prim, NotNull());
125 EXPECT_THAT(prim->value.data, Eq(123u));
126
127 prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
128 &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet");
129 ASSERT_THAT(prim, NotNull());
130 EXPECT_THAT(prim->value.data, Eq(321u));
131
132 Reference* actual_ref = test::GetValue<Reference>(&new_table, "com.app.a:layout/abc");
133 ASSERT_THAT(actual_ref, NotNull());
134 ASSERT_TRUE(actual_ref->name);
135 ASSERT_TRUE(actual_ref->id);
136 EXPECT_THAT(*actual_ref, Eq(expected_ref));
137
Adam Lesinski8780eb62017-10-31 17:44:39 -0700138 FileReference* actual_file_ref =
139 test::GetValue<FileReference>(&new_table, "com.app.a:layout/main");
140 ASSERT_THAT(actual_file_ref, NotNull());
141 EXPECT_THAT(actual_file_ref->file, Eq(&file_a));
142
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700143 StyledString* actual_styled_str =
144 test::GetValue<StyledString>(&new_table, "com.app.a:string/styled");
145 ASSERT_THAT(actual_styled_str, NotNull());
146 EXPECT_THAT(actual_styled_str->value->value, Eq("hello"));
147 ASSERT_THAT(actual_styled_str->value->spans, SizeIs(1u));
148 EXPECT_THAT(*actual_styled_str->value->spans[0].name, Eq("b"));
149 EXPECT_THAT(actual_styled_str->value->spans[0].first_char, Eq(0u));
150 EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u));
151}
152
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700153TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
154 xml::Element element;
155 element.line_number = 22;
156 element.column_number = 23;
157 element.name = "element";
158 element.namespace_uri = "uri://";
159
160 xml::NamespaceDecl decl;
161 decl.prefix = "android";
162 decl.uri = xml::kSchemaAndroid;
163 decl.line_number = 21;
164 decl.column_number = 24;
165
166 element.namespace_decls.push_back(decl);
167
168 xml::Attribute attr;
169 attr.name = "name";
170 attr.namespace_uri = xml::kSchemaAndroid;
171 attr.value = "23dp";
172 attr.compiled_attribute = xml::AaptAttribute({}, ResourceId(0x01010000));
173 attr.compiled_value =
174 ResourceUtils::TryParseItemForAttribute(attr.value, android::ResTable_map::TYPE_DIMENSION);
175 attr.compiled_value->SetSource(Source().WithLine(25));
176 element.attributes.push_back(std::move(attr));
177
178 std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>();
179 text->line_number = 25;
180 text->column_number = 3;
181 text->text = "hey there";
182 element.AppendChild(std::move(text));
183
184 std::unique_ptr<xml::Element> child = util::make_unique<xml::Element>();
185 child->name = "child";
186
187 text = util::make_unique<xml::Text>();
188 text->text = "woah there";
189 child->AppendChild(std::move(text));
190
191 element.AppendChild(std::move(child));
192
193 pb::XmlNode pb_xml;
194 SerializeXmlToPb(element, &pb_xml);
195
196 StringPool pool;
197 xml::Element actual_el;
198 std::string error;
199 ASSERT_TRUE(DeserializeXmlFromPb(pb_xml, &actual_el, &pool, &error));
200 ASSERT_THAT(error, IsEmpty());
201
202 EXPECT_THAT(actual_el.name, StrEq("element"));
203 EXPECT_THAT(actual_el.namespace_uri, StrEq("uri://"));
204 EXPECT_THAT(actual_el.line_number, Eq(22u));
205 EXPECT_THAT(actual_el.column_number, Eq(23u));
206
207 ASSERT_THAT(actual_el.namespace_decls, SizeIs(1u));
208 const xml::NamespaceDecl& actual_decl = actual_el.namespace_decls[0];
209 EXPECT_THAT(actual_decl.prefix, StrEq("android"));
210 EXPECT_THAT(actual_decl.uri, StrEq(xml::kSchemaAndroid));
211 EXPECT_THAT(actual_decl.line_number, Eq(21u));
212 EXPECT_THAT(actual_decl.column_number, Eq(24u));
213
214 ASSERT_THAT(actual_el.attributes, SizeIs(1u));
215 const xml::Attribute& actual_attr = actual_el.attributes[0];
216 EXPECT_THAT(actual_attr.name, StrEq("name"));
217 EXPECT_THAT(actual_attr.namespace_uri, StrEq(xml::kSchemaAndroid));
218 EXPECT_THAT(actual_attr.value, StrEq("23dp"));
219
220 ASSERT_THAT(actual_attr.compiled_value, NotNull());
221 const BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(actual_attr.compiled_value.get());
222 ASSERT_THAT(prim, NotNull());
223 EXPECT_THAT(prim->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
224
225 ASSERT_TRUE(actual_attr.compiled_attribute);
226 ASSERT_TRUE(actual_attr.compiled_attribute.value().id);
227
228 ASSERT_THAT(actual_el.children, SizeIs(2u));
229 const xml::Text* child_text = xml::NodeCast<xml::Text>(actual_el.children[0].get());
230 ASSERT_THAT(child_text, NotNull());
231 const xml::Element* child_el = xml::NodeCast<xml::Element>(actual_el.children[1].get());
232 ASSERT_THAT(child_el, NotNull());
233
234 EXPECT_THAT(child_text->line_number, Eq(25u));
235 EXPECT_THAT(child_text->column_number, Eq(3u));
236 EXPECT_THAT(child_text->text, StrEq("hey there"));
237
238 EXPECT_THAT(child_el->name, StrEq("child"));
239 ASSERT_THAT(child_el->children, SizeIs(1u));
240
241 child_text = xml::NodeCast<xml::Text>(child_el->children[0].get());
242 ASSERT_THAT(child_text, NotNull());
243 EXPECT_THAT(child_text->text, StrEq("woah there"));
244}
245
246static void ExpectConfigSerializes(const StringPiece& config_str) {
247 const ConfigDescription expected_config = test::ParseConfigOrDie(config_str);
248 pb::Configuration pb_config;
249 SerializeConfig(expected_config, &pb_config);
250
251 ConfigDescription actual_config;
252 std::string error;
253 ASSERT_TRUE(DeserializeConfigFromPb(pb_config, &actual_config, &error));
254 ASSERT_THAT(error, IsEmpty());
255 EXPECT_EQ(expected_config, actual_config);
256}
257
258TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) {
259 ExpectConfigSerializes("");
260
261 ExpectConfigSerializes("mcc123");
262
263 ExpectConfigSerializes("mnc123");
264
265 ExpectConfigSerializes("en");
266 ExpectConfigSerializes("en-rGB");
267 ExpectConfigSerializes("b+en+GB");
268
269 ExpectConfigSerializes("ldltr");
270 ExpectConfigSerializes("ldrtl");
271
272 ExpectConfigSerializes("sw3600dp");
273
274 ExpectConfigSerializes("w300dp");
275
276 ExpectConfigSerializes("h400dp");
277
278 ExpectConfigSerializes("small");
279 ExpectConfigSerializes("normal");
280 ExpectConfigSerializes("large");
281 ExpectConfigSerializes("xlarge");
282
283 ExpectConfigSerializes("long");
284 ExpectConfigSerializes("notlong");
285
286 ExpectConfigSerializes("round");
287 ExpectConfigSerializes("notround");
288
289 ExpectConfigSerializes("widecg");
290 ExpectConfigSerializes("nowidecg");
291
292 ExpectConfigSerializes("highdr");
293 ExpectConfigSerializes("lowdr");
294
295 ExpectConfigSerializes("port");
296 ExpectConfigSerializes("land");
297 ExpectConfigSerializes("square");
298
299 ExpectConfigSerializes("desk");
300 ExpectConfigSerializes("car");
301 ExpectConfigSerializes("television");
302 ExpectConfigSerializes("appliance");
303 ExpectConfigSerializes("watch");
304 ExpectConfigSerializes("vrheadset");
305
306 ExpectConfigSerializes("night");
307 ExpectConfigSerializes("notnight");
308
309 ExpectConfigSerializes("300dpi");
310 ExpectConfigSerializes("hdpi");
311
312 ExpectConfigSerializes("notouch");
313 ExpectConfigSerializes("stylus");
314 ExpectConfigSerializes("finger");
315
316 ExpectConfigSerializes("keysexposed");
317 ExpectConfigSerializes("keyshidden");
318 ExpectConfigSerializes("keyssoft");
319
320 ExpectConfigSerializes("nokeys");
321 ExpectConfigSerializes("qwerty");
322 ExpectConfigSerializes("12key");
323
324 ExpectConfigSerializes("navhidden");
325 ExpectConfigSerializes("navexposed");
326
327 ExpectConfigSerializes("nonav");
328 ExpectConfigSerializes("dpad");
329 ExpectConfigSerializes("trackball");
330 ExpectConfigSerializes("wheel");
331
332 ExpectConfigSerializes("300x200");
333
334 ExpectConfigSerializes("v8");
335
336 ExpectConfigSerializes(
337 "mcc123-mnc456-b+en+GB-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-land-car-"
338 "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
339}
340
341} // namespace aapt