blob: a9f1f789f8473969b0f59dd7e503c152a086af6e [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
Michael Wachenschwanzd06f1f32018-01-11 18:36:22 -0800246TEST(ProtoSerializeTest, SerializeAndDeserializePrimitives) {
247 std::unique_ptr<ResourceTable> table =
248 test::ResourceTableBuilder()
249 .AddValue("android:bool/boolean_true",
250 test::BuildPrimitive(android::Res_value::TYPE_INT_BOOLEAN, true))
251 .AddValue("android:bool/boolean_false",
252 test::BuildPrimitive(android::Res_value::TYPE_INT_BOOLEAN, false))
253 .AddValue("android:color/color_rgb8", ResourceUtils::TryParseColor("#AABBCC"))
254 .AddValue("android:color/color_argb8", ResourceUtils::TryParseColor("#11223344"))
255 .AddValue("android:color/color_rgb4", ResourceUtils::TryParseColor("#DEF"))
256 .AddValue("android:color/color_argb4", ResourceUtils::TryParseColor("#5678"))
257 .AddValue("android:integer/integer_444", ResourceUtils::TryParseInt("444"))
258 .AddValue("android:integer/integer_neg_333", ResourceUtils::TryParseInt("-333"))
259 .AddValue("android:integer/hex_int_abcd", ResourceUtils::TryParseInt("0xABCD"))
260 .AddValue("android:dimen/dimen_1.39mm", ResourceUtils::TryParseFloat("1.39mm"))
261 .AddValue("android:fraction/fraction_27", ResourceUtils::TryParseFloat("27%"))
262 .AddValue("android:integer/null", ResourceUtils::MakeEmpty())
263 .Build();
264
265 pb::ResourceTable pb_table;
266 SerializeTableToPb(*table, &pb_table);
267
268 test::TestFile file_a("res/layout/main.xml");
269 MockFileCollection files;
270 EXPECT_CALL(files, FindFile(Eq("res/layout/main.xml")))
271 .WillRepeatedly(::testing::Return(&file_a));
272
273 ResourceTable new_table;
274 std::string error;
275 ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
276 EXPECT_THAT(error, IsEmpty());
277
278 BinaryPrimitive* bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
279 &new_table, "android:bool/boolean_true", ConfigDescription::DefaultConfig(), "");
280 ASSERT_THAT(bp, NotNull());
281 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_BOOLEAN));
282 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseBool("true")->value.data));
283
284 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:bool/boolean_false",
285 ConfigDescription::DefaultConfig(), "");
286 ASSERT_THAT(bp, NotNull());
287 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_BOOLEAN));
288 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseBool("false")->value.data));
289
290 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_rgb8",
291 ConfigDescription::DefaultConfig(), "");
292 ASSERT_THAT(bp, NotNull());
293 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_RGB8));
294 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#AABBCC")->value.data));
295
296 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_argb8",
297 ConfigDescription::DefaultConfig(), "");
298 ASSERT_THAT(bp, NotNull());
299 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_ARGB8));
300 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#11223344")->value.data));
301
302 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_rgb4",
303 ConfigDescription::DefaultConfig(), "");
304 ASSERT_THAT(bp, NotNull());
305 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_RGB4));
306 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#DEF")->value.data));
307
308 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_argb4",
309 ConfigDescription::DefaultConfig(), "");
310 ASSERT_THAT(bp, NotNull());
311 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_ARGB4));
312 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#5678")->value.data));
313
314 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:integer/integer_444",
315 ConfigDescription::DefaultConfig(), "");
316 ASSERT_THAT(bp, NotNull());
317 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
318 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("444")->value.data));
319
320 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
321 &new_table, "android:integer/integer_neg_333", ConfigDescription::DefaultConfig(), "");
322 ASSERT_THAT(bp, NotNull());
323 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
324 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("-333")->value.data));
325
326 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
327 &new_table, "android:integer/hex_int_abcd", ConfigDescription::DefaultConfig(), "");
328 ASSERT_THAT(bp, NotNull());
329 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_HEX));
330 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("0xABCD")->value.data));
331
332 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:dimen/dimen_1.39mm",
333 ConfigDescription::DefaultConfig(), "");
334 ASSERT_THAT(bp, NotNull());
335 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
336 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseFloat("1.39mm")->value.data));
337
338 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
339 &new_table, "android:fraction/fraction_27", ConfigDescription::DefaultConfig(), "");
340 ASSERT_THAT(bp, NotNull());
341 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_FRACTION));
342 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseFloat("27%")->value.data));
343
344 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:integer/null",
345 ConfigDescription::DefaultConfig(), "");
346 ASSERT_THAT(bp, NotNull());
347 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_NULL));
348 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::MakeEmpty()->value.data));
349}
350
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700351static void ExpectConfigSerializes(const StringPiece& config_str) {
352 const ConfigDescription expected_config = test::ParseConfigOrDie(config_str);
353 pb::Configuration pb_config;
354 SerializeConfig(expected_config, &pb_config);
355
356 ConfigDescription actual_config;
357 std::string error;
358 ASSERT_TRUE(DeserializeConfigFromPb(pb_config, &actual_config, &error));
359 ASSERT_THAT(error, IsEmpty());
360 EXPECT_EQ(expected_config, actual_config);
361}
362
363TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) {
364 ExpectConfigSerializes("");
365
366 ExpectConfigSerializes("mcc123");
367
368 ExpectConfigSerializes("mnc123");
369
370 ExpectConfigSerializes("en");
371 ExpectConfigSerializes("en-rGB");
372 ExpectConfigSerializes("b+en+GB");
373
374 ExpectConfigSerializes("ldltr");
375 ExpectConfigSerializes("ldrtl");
376
377 ExpectConfigSerializes("sw3600dp");
378
379 ExpectConfigSerializes("w300dp");
380
381 ExpectConfigSerializes("h400dp");
382
383 ExpectConfigSerializes("small");
384 ExpectConfigSerializes("normal");
385 ExpectConfigSerializes("large");
386 ExpectConfigSerializes("xlarge");
387
388 ExpectConfigSerializes("long");
389 ExpectConfigSerializes("notlong");
390
391 ExpectConfigSerializes("round");
392 ExpectConfigSerializes("notround");
393
394 ExpectConfigSerializes("widecg");
395 ExpectConfigSerializes("nowidecg");
396
397 ExpectConfigSerializes("highdr");
398 ExpectConfigSerializes("lowdr");
399
400 ExpectConfigSerializes("port");
401 ExpectConfigSerializes("land");
402 ExpectConfigSerializes("square");
403
404 ExpectConfigSerializes("desk");
405 ExpectConfigSerializes("car");
406 ExpectConfigSerializes("television");
407 ExpectConfigSerializes("appliance");
408 ExpectConfigSerializes("watch");
409 ExpectConfigSerializes("vrheadset");
410
411 ExpectConfigSerializes("night");
412 ExpectConfigSerializes("notnight");
413
414 ExpectConfigSerializes("300dpi");
415 ExpectConfigSerializes("hdpi");
416
417 ExpectConfigSerializes("notouch");
418 ExpectConfigSerializes("stylus");
419 ExpectConfigSerializes("finger");
420
421 ExpectConfigSerializes("keysexposed");
422 ExpectConfigSerializes("keyshidden");
423 ExpectConfigSerializes("keyssoft");
424
425 ExpectConfigSerializes("nokeys");
426 ExpectConfigSerializes("qwerty");
427 ExpectConfigSerializes("12key");
428
429 ExpectConfigSerializes("navhidden");
430 ExpectConfigSerializes("navexposed");
431
432 ExpectConfigSerializes("nonav");
433 ExpectConfigSerializes("dpad");
434 ExpectConfigSerializes("trackball");
435 ExpectConfigSerializes("wheel");
436
437 ExpectConfigSerializes("300x200");
438
439 ExpectConfigSerializes("v8");
440
441 ExpectConfigSerializes(
442 "mcc123-mnc456-b+en+GB-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-land-car-"
443 "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
444}
445
446} // namespace aapt