blob: 2154d5a9ab2c3f30806ea02a442720e45646897e [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
19#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
20
21#include "ResourceUtils.h"
Adam Lesinski46708052017-09-29 14:49:15 -070022#include "format/proto/ProtoDeserialize.h"
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070023#include "test/Test.h"
24
25using ::android::StringPiece;
26using ::google::protobuf::io::StringOutputStream;
27using ::testing::Eq;
28using ::testing::IsEmpty;
29using ::testing::NotNull;
30using ::testing::SizeIs;
31using ::testing::StrEq;
32
33namespace aapt {
34
35TEST(ProtoSerializeTest, SerializeSinglePackage) {
36 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
37 std::unique_ptr<ResourceTable> table =
38 test::ResourceTableBuilder()
39 .SetPackageId("com.app.a", 0x7f)
40 .AddFileReference("com.app.a:layout/main", ResourceId(0x7f020000), "res/layout/main.xml")
41 .AddReference("com.app.a:layout/other", ResourceId(0x7f020001), "com.app.a:layout/main")
42 .AddString("com.app.a:string/text", {}, "hi")
43 .AddValue("com.app.a:id/foo", {}, util::make_unique<Id>())
44 .SetSymbolState("com.app.a:bool/foo", {}, SymbolState::kUndefined, true /*allow_new*/)
45 .Build();
46
47 Symbol public_symbol;
48 public_symbol.state = SymbolState::kPublic;
49 ASSERT_TRUE(table->SetSymbolState(test::ParseNameOrDie("com.app.a:layout/main"),
50 ResourceId(0x7f020000), public_symbol,
51 context->GetDiagnostics()));
52
53 Id* id = test::GetValue<Id>(table.get(), "com.app.a:id/foo");
54 ASSERT_THAT(id, NotNull());
55
56 // Make a plural.
57 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
58 plural->values[Plural::One] = util::make_unique<String>(table->string_pool.MakeRef("one"));
59 ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:plurals/hey"), ConfigDescription{},
60 {}, std::move(plural), context->GetDiagnostics()));
61
62 // Make a styled string.
63 StyleString style_string;
64 style_string.str = "hello";
65 style_string.spans.push_back(Span{"b", 0u, 4u});
66 ASSERT_TRUE(
67 table->AddResource(test::ParseNameOrDie("com.app.a:string/styled"), ConfigDescription{}, {},
68 util::make_unique<StyledString>(table->string_pool.MakeRef(style_string)),
69 context->GetDiagnostics()));
70
71 // Make a resource with different products.
72 ASSERT_TRUE(table->AddResource(
73 test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), {},
74 test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u), context->GetDiagnostics()));
75 ASSERT_TRUE(table->AddResource(
76 test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), "tablet",
77 test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u), context->GetDiagnostics()));
78
79 // Make a reference with both resource name and resource ID.
80 // The reference should point to a resource outside of this table to test that both name and id
81 // get serialized.
82 Reference expected_ref;
83 expected_ref.name = test::ParseNameOrDie("android:layout/main");
84 expected_ref.id = ResourceId(0x01020000);
85 ASSERT_TRUE(table->AddResource(
86 test::ParseNameOrDie("com.app.a:layout/abc"), ConfigDescription::DefaultConfig(), {},
87 util::make_unique<Reference>(expected_ref), context->GetDiagnostics()));
88
89 pb::ResourceTable pb_table;
90 SerializeTableToPb(*table, &pb_table);
91
92 ResourceTable new_table;
93 std::string error;
94 ASSERT_TRUE(DeserializeTableFromPb(pb_table, &new_table, &error));
95 EXPECT_THAT(error, IsEmpty());
96
97 Id* new_id = test::GetValue<Id>(&new_table, "com.app.a:id/foo");
98 ASSERT_THAT(new_id, NotNull());
99 EXPECT_THAT(new_id->IsWeak(), Eq(id->IsWeak()));
100
101 Maybe<ResourceTable::SearchResult> result =
102 new_table.FindResource(test::ParseNameOrDie("com.app.a:layout/main"));
103 ASSERT_TRUE(result);
104
105 EXPECT_THAT(result.value().type->symbol_status.state, Eq(SymbolState::kPublic));
106 EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kPublic));
107
108 result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
109 ASSERT_TRUE(result);
110 EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kUndefined));
111 EXPECT_TRUE(result.value().entry->symbol_status.allow_new);
112
113 // Find the product-dependent values
114 BinaryPrimitive* prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
115 &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "");
116 ASSERT_THAT(prim, NotNull());
117 EXPECT_THAT(prim->value.data, Eq(123u));
118
119 prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
120 &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet");
121 ASSERT_THAT(prim, NotNull());
122 EXPECT_THAT(prim->value.data, Eq(321u));
123
124 Reference* actual_ref = test::GetValue<Reference>(&new_table, "com.app.a:layout/abc");
125 ASSERT_THAT(actual_ref, NotNull());
126 ASSERT_TRUE(actual_ref->name);
127 ASSERT_TRUE(actual_ref->id);
128 EXPECT_THAT(*actual_ref, Eq(expected_ref));
129
130 StyledString* actual_styled_str =
131 test::GetValue<StyledString>(&new_table, "com.app.a:string/styled");
132 ASSERT_THAT(actual_styled_str, NotNull());
133 EXPECT_THAT(actual_styled_str->value->value, Eq("hello"));
134 ASSERT_THAT(actual_styled_str->value->spans, SizeIs(1u));
135 EXPECT_THAT(*actual_styled_str->value->spans[0].name, Eq("b"));
136 EXPECT_THAT(actual_styled_str->value->spans[0].first_char, Eq(0u));
137 EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u));
138}
139
140TEST(ProtoSerializeTest, SerializeFileHeader) {
141 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
142
143 ResourceFile f;
144 f.config = test::ParseConfigOrDie("hdpi-v9");
145 f.name = test::ParseNameOrDie("com.app.a:layout/main");
146 f.source.path = "res/layout-hdpi-v9/main.xml";
147 f.exported_symbols.push_back(SourcedResourceName{test::ParseNameOrDie("id/unchecked"), 23u});
148
149 const std::string expected_data1 = "123";
150 const std::string expected_data2 = "1234";
151
152 std::string output_str;
153 {
154 pb::internal::CompiledFile pb_f1, pb_f2;
155 SerializeCompiledFileToPb(f, &pb_f1);
156
157 f.name.entry = "__" + f.name.entry + "$0";
158 SerializeCompiledFileToPb(f, &pb_f2);
159
160 StringOutputStream out_stream(&output_str);
161 CompiledFileOutputStream out_file_stream(&out_stream);
162 out_file_stream.WriteLittleEndian32(2);
163 out_file_stream.WriteCompiledFile(pb_f1);
164 out_file_stream.WriteData(expected_data1.data(), expected_data1.size());
165 out_file_stream.WriteCompiledFile(pb_f2);
166 out_file_stream.WriteData(expected_data2.data(), expected_data2.size());
167 ASSERT_FALSE(out_file_stream.HadError());
168 }
169
170 CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
171 uint32_t num_files = 0;
172 ASSERT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
173 ASSERT_EQ(2u, num_files);
174
175 // Read the first compiled file.
176
177 pb::internal::CompiledFile new_pb_f1;
178 ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_f1));
179
180 ResourceFile new_f1;
181 std::string error;
182 ASSERT_TRUE(DeserializeCompiledFileFromPb(new_pb_f1, &new_f1, &error));
183 EXPECT_THAT(error, IsEmpty());
184
185 uint64_t offset, len;
186 ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
187
188 std::string actual_data(output_str.data() + offset, len);
189 EXPECT_EQ(expected_data1, actual_data);
190
191 // Expect the data to be aligned.
192 EXPECT_EQ(0u, offset & 0x03);
193
194 ASSERT_EQ(1u, new_f1.exported_symbols.size());
195 EXPECT_EQ(test::ParseNameOrDie("id/unchecked"), new_f1.exported_symbols[0].name);
196
197 // Read the second compiled file.
198
199 pb::internal::CompiledFile new_pb_f2;
200 ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_f2));
201
202 ResourceFile new_f2;
203 ASSERT_TRUE(DeserializeCompiledFileFromPb(new_pb_f2, &new_f2, &error));
204 EXPECT_THAT(error, IsEmpty());
205
206 ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
207
208 actual_data = std::string(output_str.data() + offset, len);
209 EXPECT_EQ(expected_data2, actual_data);
210
211 // Expect the data to be aligned.
212 EXPECT_EQ(0u, offset & 0x03);
213}
214
215TEST(ProtoSerializeTest, DeserializeCorruptHeaderSafely) {
216 ResourceFile f;
217 pb::internal::CompiledFile pb_file;
218 SerializeCompiledFileToPb(f, &pb_file);
219
220 const std::string expected_data = "1234";
221
222 std::string output_str;
223 {
224 StringOutputStream out_stream(&output_str);
225 CompiledFileOutputStream out_file_stream(&out_stream);
226 out_file_stream.WriteLittleEndian32(1);
227 out_file_stream.WriteCompiledFile(pb_file);
228 out_file_stream.WriteData(expected_data.data(), expected_data.size());
229 ASSERT_FALSE(out_file_stream.HadError());
230 }
231
232 output_str[4] = 0xff;
233
234 CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
235
236 uint32_t num_files = 0;
237 EXPECT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
238 EXPECT_EQ(1u, num_files);
239
240 pb::internal::CompiledFile new_pb_file;
241 EXPECT_FALSE(in_file_stream.ReadCompiledFile(&new_pb_file));
242
243 uint64_t offset, len;
244 EXPECT_FALSE(in_file_stream.ReadDataMetaData(&offset, &len));
245}
246
247TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
248 xml::Element element;
249 element.line_number = 22;
250 element.column_number = 23;
251 element.name = "element";
252 element.namespace_uri = "uri://";
253
254 xml::NamespaceDecl decl;
255 decl.prefix = "android";
256 decl.uri = xml::kSchemaAndroid;
257 decl.line_number = 21;
258 decl.column_number = 24;
259
260 element.namespace_decls.push_back(decl);
261
262 xml::Attribute attr;
263 attr.name = "name";
264 attr.namespace_uri = xml::kSchemaAndroid;
265 attr.value = "23dp";
266 attr.compiled_attribute = xml::AaptAttribute({}, ResourceId(0x01010000));
267 attr.compiled_value =
268 ResourceUtils::TryParseItemForAttribute(attr.value, android::ResTable_map::TYPE_DIMENSION);
269 attr.compiled_value->SetSource(Source().WithLine(25));
270 element.attributes.push_back(std::move(attr));
271
272 std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>();
273 text->line_number = 25;
274 text->column_number = 3;
275 text->text = "hey there";
276 element.AppendChild(std::move(text));
277
278 std::unique_ptr<xml::Element> child = util::make_unique<xml::Element>();
279 child->name = "child";
280
281 text = util::make_unique<xml::Text>();
282 text->text = "woah there";
283 child->AppendChild(std::move(text));
284
285 element.AppendChild(std::move(child));
286
287 pb::XmlNode pb_xml;
288 SerializeXmlToPb(element, &pb_xml);
289
290 StringPool pool;
291 xml::Element actual_el;
292 std::string error;
293 ASSERT_TRUE(DeserializeXmlFromPb(pb_xml, &actual_el, &pool, &error));
294 ASSERT_THAT(error, IsEmpty());
295
296 EXPECT_THAT(actual_el.name, StrEq("element"));
297 EXPECT_THAT(actual_el.namespace_uri, StrEq("uri://"));
298 EXPECT_THAT(actual_el.line_number, Eq(22u));
299 EXPECT_THAT(actual_el.column_number, Eq(23u));
300
301 ASSERT_THAT(actual_el.namespace_decls, SizeIs(1u));
302 const xml::NamespaceDecl& actual_decl = actual_el.namespace_decls[0];
303 EXPECT_THAT(actual_decl.prefix, StrEq("android"));
304 EXPECT_THAT(actual_decl.uri, StrEq(xml::kSchemaAndroid));
305 EXPECT_THAT(actual_decl.line_number, Eq(21u));
306 EXPECT_THAT(actual_decl.column_number, Eq(24u));
307
308 ASSERT_THAT(actual_el.attributes, SizeIs(1u));
309 const xml::Attribute& actual_attr = actual_el.attributes[0];
310 EXPECT_THAT(actual_attr.name, StrEq("name"));
311 EXPECT_THAT(actual_attr.namespace_uri, StrEq(xml::kSchemaAndroid));
312 EXPECT_THAT(actual_attr.value, StrEq("23dp"));
313
314 ASSERT_THAT(actual_attr.compiled_value, NotNull());
315 const BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(actual_attr.compiled_value.get());
316 ASSERT_THAT(prim, NotNull());
317 EXPECT_THAT(prim->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
318
319 ASSERT_TRUE(actual_attr.compiled_attribute);
320 ASSERT_TRUE(actual_attr.compiled_attribute.value().id);
321
322 ASSERT_THAT(actual_el.children, SizeIs(2u));
323 const xml::Text* child_text = xml::NodeCast<xml::Text>(actual_el.children[0].get());
324 ASSERT_THAT(child_text, NotNull());
325 const xml::Element* child_el = xml::NodeCast<xml::Element>(actual_el.children[1].get());
326 ASSERT_THAT(child_el, NotNull());
327
328 EXPECT_THAT(child_text->line_number, Eq(25u));
329 EXPECT_THAT(child_text->column_number, Eq(3u));
330 EXPECT_THAT(child_text->text, StrEq("hey there"));
331
332 EXPECT_THAT(child_el->name, StrEq("child"));
333 ASSERT_THAT(child_el->children, SizeIs(1u));
334
335 child_text = xml::NodeCast<xml::Text>(child_el->children[0].get());
336 ASSERT_THAT(child_text, NotNull());
337 EXPECT_THAT(child_text->text, StrEq("woah there"));
338}
339
340static void ExpectConfigSerializes(const StringPiece& config_str) {
341 const ConfigDescription expected_config = test::ParseConfigOrDie(config_str);
342 pb::Configuration pb_config;
343 SerializeConfig(expected_config, &pb_config);
344
345 ConfigDescription actual_config;
346 std::string error;
347 ASSERT_TRUE(DeserializeConfigFromPb(pb_config, &actual_config, &error));
348 ASSERT_THAT(error, IsEmpty());
349 EXPECT_EQ(expected_config, actual_config);
350}
351
352TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) {
353 ExpectConfigSerializes("");
354
355 ExpectConfigSerializes("mcc123");
356
357 ExpectConfigSerializes("mnc123");
358
359 ExpectConfigSerializes("en");
360 ExpectConfigSerializes("en-rGB");
361 ExpectConfigSerializes("b+en+GB");
362
363 ExpectConfigSerializes("ldltr");
364 ExpectConfigSerializes("ldrtl");
365
366 ExpectConfigSerializes("sw3600dp");
367
368 ExpectConfigSerializes("w300dp");
369
370 ExpectConfigSerializes("h400dp");
371
372 ExpectConfigSerializes("small");
373 ExpectConfigSerializes("normal");
374 ExpectConfigSerializes("large");
375 ExpectConfigSerializes("xlarge");
376
377 ExpectConfigSerializes("long");
378 ExpectConfigSerializes("notlong");
379
380 ExpectConfigSerializes("round");
381 ExpectConfigSerializes("notround");
382
383 ExpectConfigSerializes("widecg");
384 ExpectConfigSerializes("nowidecg");
385
386 ExpectConfigSerializes("highdr");
387 ExpectConfigSerializes("lowdr");
388
389 ExpectConfigSerializes("port");
390 ExpectConfigSerializes("land");
391 ExpectConfigSerializes("square");
392
393 ExpectConfigSerializes("desk");
394 ExpectConfigSerializes("car");
395 ExpectConfigSerializes("television");
396 ExpectConfigSerializes("appliance");
397 ExpectConfigSerializes("watch");
398 ExpectConfigSerializes("vrheadset");
399
400 ExpectConfigSerializes("night");
401 ExpectConfigSerializes("notnight");
402
403 ExpectConfigSerializes("300dpi");
404 ExpectConfigSerializes("hdpi");
405
406 ExpectConfigSerializes("notouch");
407 ExpectConfigSerializes("stylus");
408 ExpectConfigSerializes("finger");
409
410 ExpectConfigSerializes("keysexposed");
411 ExpectConfigSerializes("keyshidden");
412 ExpectConfigSerializes("keyssoft");
413
414 ExpectConfigSerializes("nokeys");
415 ExpectConfigSerializes("qwerty");
416 ExpectConfigSerializes("12key");
417
418 ExpectConfigSerializes("navhidden");
419 ExpectConfigSerializes("navexposed");
420
421 ExpectConfigSerializes("nonav");
422 ExpectConfigSerializes("dpad");
423 ExpectConfigSerializes("trackball");
424 ExpectConfigSerializes("wheel");
425
426 ExpectConfigSerializes("300x200");
427
428 ExpectConfigSerializes("v8");
429
430 ExpectConfigSerializes(
431 "mcc123-mnc456-b+en+GB-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-land-car-"
432 "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
433}
434
435} // namespace aapt