1 /*
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 
17 #include "format/proto/ProtoSerialize.h"
18 
19 #include "ResourceUtils.h"
20 #include "format/proto/ProtoDeserialize.h"
21 #include "test/Test.h"
22 
23 using ::android::ConfigDescription;
24 using ::android::StringPiece;
25 using ::testing::Eq;
26 using ::testing::IsEmpty;
27 using ::testing::NotNull;
28 using ::testing::SizeIs;
29 using ::testing::StrEq;
30 
31 using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
32 
33 namespace aapt {
34 
35 class MockFileCollection : public io::IFileCollection {
36  public:
37   MOCK_METHOD1(FindFile, io::IFile*(const StringPiece& path));
38   MOCK_METHOD0(Iterator, std::unique_ptr<io::IFileCollectionIterator>());
39   MOCK_METHOD0(GetDirSeparator, char());
40 };
41 
TEST(ProtoSerializeTest,SerializeSinglePackage)42 TEST(ProtoSerializeTest, SerializeSinglePackage) {
43   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
44   std::unique_ptr<ResourceTable> table =
45       test::ResourceTableBuilder()
46           .SetPackageId("com.app.a", 0x7f)
47           .AddFileReference("com.app.a:layout/main", ResourceId(0x7f020000), "res/layout/main.xml")
48           .AddReference("com.app.a:layout/other", ResourceId(0x7f020001), "com.app.a:layout/main")
49           .AddString("com.app.a:string/text", {}, "hi")
50           .AddValue("com.app.a:id/foo", {}, util::make_unique<Id>())
51           .SetSymbolState("com.app.a:bool/foo", {}, Visibility::Level::kUndefined,
52                           true /*allow_new*/)
53           .Build();
54 
55   Visibility public_symbol;
56   public_symbol.level = Visibility::Level::kPublic;
57   ASSERT_TRUE(table->SetVisibilityWithId(test::ParseNameOrDie("com.app.a:layout/main"),
58                                          public_symbol, ResourceId(0x7f020000),
59                                          context->GetDiagnostics()));
60 
61   Id* id = test::GetValue<Id>(table.get(), "com.app.a:id/foo");
62   ASSERT_THAT(id, NotNull());
63 
64   // Make a plural.
65   std::unique_ptr<Plural> plural = util::make_unique<Plural>();
66   plural->values[Plural::One] = util::make_unique<String>(table->string_pool.MakeRef("one"));
67   ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:plurals/hey"), ConfigDescription{},
68                                  {}, std::move(plural), context->GetDiagnostics()));
69 
70   // Make a styled string.
71   StyleString style_string;
72   style_string.str = "hello";
73   style_string.spans.push_back(Span{"b", 0u, 4u});
74   ASSERT_TRUE(
75       table->AddResource(test::ParseNameOrDie("com.app.a:string/styled"), ConfigDescription{}, {},
76                          util::make_unique<StyledString>(table->string_pool.MakeRef(style_string)),
77                          context->GetDiagnostics()));
78 
79   // Make a resource with different products.
80   ASSERT_TRUE(table->AddResource(
81       test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), {},
82       test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u), context->GetDiagnostics()));
83   ASSERT_TRUE(table->AddResource(
84       test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), "tablet",
85       test::BuildPrimitive(android::Res_value::TYPE_INT_HEX, 321u), context->GetDiagnostics()));
86 
87   // Make a reference with both resource name and resource ID.
88   // The reference should point to a resource outside of this table to test that both name and id
89   // get serialized.
90   Reference expected_ref;
91   expected_ref.name = test::ParseNameOrDie("android:layout/main");
92   expected_ref.id = ResourceId(0x01020000);
93   ASSERT_TRUE(table->AddResource(
94       test::ParseNameOrDie("com.app.a:layout/abc"), ConfigDescription::DefaultConfig(), {},
95       util::make_unique<Reference>(expected_ref), context->GetDiagnostics()));
96 
97   // Make an overlayable resource.
98   OverlayableItem overlayable_item(std::make_shared<Overlayable>(
99       "OverlayableName", "overlay://theme", Source("res/values/overlayable.xml", 40)));
100   overlayable_item.source = Source("res/values/overlayable.xml", 42);
101   ASSERT_TRUE(table->SetOverlayable(test::ParseNameOrDie("com.app.a:integer/overlayable"),
102                                     overlayable_item, test::GetDiagnostics()));
103 
104   pb::ResourceTable pb_table;
105   SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
106 
107   test::TestFile file_a("res/layout/main.xml");
108   MockFileCollection files;
109   EXPECT_CALL(files, FindFile(Eq("res/layout/main.xml")))
110       .WillRepeatedly(::testing::Return(&file_a));
111 
112   ResourceTable new_table;
113   std::string error;
114   ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)) << error;
115   EXPECT_THAT(error, IsEmpty());
116 
117   Id* new_id = test::GetValue<Id>(&new_table, "com.app.a:id/foo");
118   ASSERT_THAT(new_id, NotNull());
119   EXPECT_THAT(new_id->IsWeak(), Eq(id->IsWeak()));
120 
121   Maybe<ResourceTable::SearchResult> result =
122       new_table.FindResource(test::ParseNameOrDie("com.app.a:layout/main"));
123   ASSERT_TRUE(result);
124 
125   EXPECT_THAT(result.value().type->visibility_level, Eq(Visibility::Level::kPublic));
126   EXPECT_THAT(result.value().entry->visibility.level, Eq(Visibility::Level::kPublic));
127 
128   result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
129   ASSERT_TRUE(result);
130   EXPECT_THAT(result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
131   EXPECT_TRUE(result.value().entry->allow_new);
132 
133   // Find the product-dependent values
134   BinaryPrimitive* prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
135       &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "");
136   ASSERT_THAT(prim, NotNull());
137   EXPECT_THAT(prim->value.data, Eq(123u));
138   EXPECT_THAT(prim->value.dataType, Eq(0x10));
139 
140   prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
141       &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet");
142   ASSERT_THAT(prim, NotNull());
143   EXPECT_THAT(prim->value.data, Eq(321u));
144   EXPECT_THAT(prim->value.dataType, Eq(0x11));
145 
146   Reference* actual_ref = test::GetValue<Reference>(&new_table, "com.app.a:layout/abc");
147   ASSERT_THAT(actual_ref, NotNull());
148   ASSERT_TRUE(actual_ref->name);
149   ASSERT_TRUE(actual_ref->id);
150   EXPECT_THAT(*actual_ref, Eq(expected_ref));
151 
152   FileReference* actual_file_ref =
153       test::GetValue<FileReference>(&new_table, "com.app.a:layout/main");
154   ASSERT_THAT(actual_file_ref, NotNull());
155   EXPECT_THAT(actual_file_ref->file, Eq(&file_a));
156 
157   StyledString* actual_styled_str =
158       test::GetValue<StyledString>(&new_table, "com.app.a:string/styled");
159   ASSERT_THAT(actual_styled_str, NotNull());
160   EXPECT_THAT(actual_styled_str->value->value, Eq("hello"));
161   ASSERT_THAT(actual_styled_str->value->spans, SizeIs(1u));
162   EXPECT_THAT(*actual_styled_str->value->spans[0].name, Eq("b"));
163   EXPECT_THAT(actual_styled_str->value->spans[0].first_char, Eq(0u));
164   EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u));
165 
166   Maybe<ResourceTable::SearchResult> search_result =
167       new_table.FindResource(test::ParseNameOrDie("com.app.a:integer/overlayable"));
168   ASSERT_TRUE(search_result);
169   ASSERT_THAT(search_result.value().entry, NotNull());
170   ASSERT_TRUE(search_result.value().entry->overlayable_item);
171   OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
172   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("OverlayableName"));
173   EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
174   EXPECT_THAT(result_overlayable_item.overlayable->source.path, Eq("res/values/overlayable.xml"));
175   EXPECT_THAT(result_overlayable_item.overlayable->source.line, Eq(40));
176   EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::NONE));
177   EXPECT_THAT(result_overlayable_item.source.path, Eq("res/values/overlayable.xml"));
178   EXPECT_THAT(result_overlayable_item.source.line, Eq(42));
179 }
180 
TEST(ProtoSerializeTest,SerializeAndDeserializeXml)181 TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
182   xml::Element element;
183   element.line_number = 22;
184   element.column_number = 23;
185   element.name = "element";
186   element.namespace_uri = "uri://";
187 
188   xml::NamespaceDecl decl;
189   decl.prefix = "android";
190   decl.uri = xml::kSchemaAndroid;
191   decl.line_number = 21;
192   decl.column_number = 24;
193 
194   element.namespace_decls.push_back(decl);
195 
196   xml::Attribute attr;
197   attr.name = "name";
198   attr.namespace_uri = xml::kSchemaAndroid;
199   attr.value = "23dp";
200   attr.compiled_attribute = xml::AaptAttribute(Attribute{}, ResourceId(0x01010000));
201   attr.compiled_value =
202       ResourceUtils::TryParseItemForAttribute(attr.value, android::ResTable_map::TYPE_DIMENSION);
203   attr.compiled_value->SetSource(Source().WithLine(25));
204   element.attributes.push_back(std::move(attr));
205 
206   std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>();
207   text->line_number = 25;
208   text->column_number = 3;
209   text->text = "hey there";
210   element.AppendChild(std::move(text));
211 
212   std::unique_ptr<xml::Element> child = util::make_unique<xml::Element>();
213   child->name = "child";
214 
215   text = util::make_unique<xml::Text>();
216   text->text = "woah there";
217   child->AppendChild(std::move(text));
218 
219   element.AppendChild(std::move(child));
220 
221   pb::XmlNode pb_xml;
222   SerializeXmlToPb(element, &pb_xml);
223 
224   StringPool pool;
225   xml::Element actual_el;
226   std::string error;
227   ASSERT_TRUE(DeserializeXmlFromPb(pb_xml, &actual_el, &pool, &error));
228   ASSERT_THAT(error, IsEmpty());
229 
230   EXPECT_THAT(actual_el.name, StrEq("element"));
231   EXPECT_THAT(actual_el.namespace_uri, StrEq("uri://"));
232   EXPECT_THAT(actual_el.line_number, Eq(22u));
233   EXPECT_THAT(actual_el.column_number, Eq(23u));
234 
235   ASSERT_THAT(actual_el.namespace_decls, SizeIs(1u));
236   const xml::NamespaceDecl& actual_decl = actual_el.namespace_decls[0];
237   EXPECT_THAT(actual_decl.prefix, StrEq("android"));
238   EXPECT_THAT(actual_decl.uri, StrEq(xml::kSchemaAndroid));
239   EXPECT_THAT(actual_decl.line_number, Eq(21u));
240   EXPECT_THAT(actual_decl.column_number, Eq(24u));
241 
242   ASSERT_THAT(actual_el.attributes, SizeIs(1u));
243   const xml::Attribute& actual_attr = actual_el.attributes[0];
244   EXPECT_THAT(actual_attr.name, StrEq("name"));
245   EXPECT_THAT(actual_attr.namespace_uri, StrEq(xml::kSchemaAndroid));
246   EXPECT_THAT(actual_attr.value, StrEq("23dp"));
247 
248   ASSERT_THAT(actual_attr.compiled_value, NotNull());
249   const BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(actual_attr.compiled_value.get());
250   ASSERT_THAT(prim, NotNull());
251   EXPECT_THAT(prim->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
252 
253   ASSERT_TRUE(actual_attr.compiled_attribute);
254   ASSERT_TRUE(actual_attr.compiled_attribute.value().id);
255 
256   ASSERT_THAT(actual_el.children, SizeIs(2u));
257   const xml::Text* child_text = xml::NodeCast<xml::Text>(actual_el.children[0].get());
258   ASSERT_THAT(child_text, NotNull());
259   const xml::Element* child_el = xml::NodeCast<xml::Element>(actual_el.children[1].get());
260   ASSERT_THAT(child_el, NotNull());
261 
262   EXPECT_THAT(child_text->line_number, Eq(25u));
263   EXPECT_THAT(child_text->column_number, Eq(3u));
264   EXPECT_THAT(child_text->text, StrEq("hey there"));
265 
266   EXPECT_THAT(child_el->name, StrEq("child"));
267   ASSERT_THAT(child_el->children, SizeIs(1u));
268 
269   child_text = xml::NodeCast<xml::Text>(child_el->children[0].get());
270   ASSERT_THAT(child_text, NotNull());
271   EXPECT_THAT(child_text->text, StrEq("woah there"));
272 }
273 
TEST(ProtoSerializeTest,SerializeAndDeserializeXmlTrimEmptyWhitepsace)274 TEST(ProtoSerializeTest, SerializeAndDeserializeXmlTrimEmptyWhitepsace) {
275   xml::Element element;
276   element.line_number = 22;
277   element.column_number = 23;
278   element.name = "element";
279 
280   std::unique_ptr<xml::Text> trim_text = util::make_unique<xml::Text>();
281   trim_text->line_number = 25;
282   trim_text->column_number = 3;
283   trim_text->text = "  \n   ";
284   element.AppendChild(std::move(trim_text));
285 
286   std::unique_ptr<xml::Text> keep_text = util::make_unique<xml::Text>();
287   keep_text->line_number = 26;
288   keep_text->column_number = 3;
289   keep_text->text = "  hello   ";
290   element.AppendChild(std::move(keep_text));
291 
292   pb::XmlNode pb_xml;
293   SerializeXmlOptions options;
294   options.remove_empty_text_nodes = true;
295   SerializeXmlToPb(element, &pb_xml, options);
296 
297   StringPool pool;
298   xml::Element actual_el;
299   std::string error;
300   ASSERT_TRUE(DeserializeXmlFromPb(pb_xml, &actual_el, &pool, &error));
301   ASSERT_THAT(error, IsEmpty());
302 
303   // Only the child that does not consist of only whitespace should remain
304   ASSERT_THAT(actual_el.children, SizeIs(1u));
305   const xml::Text* child_text_keep = xml::NodeCast<xml::Text>(actual_el.children[0].get());
306   ASSERT_THAT(child_text_keep, NotNull());
307   EXPECT_THAT(child_text_keep->text, StrEq( "  hello   "));
308 }
309 
TEST(ProtoSerializeTest,SerializeAndDeserializePrimitives)310 TEST(ProtoSerializeTest, SerializeAndDeserializePrimitives) {
311   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
312   std::unique_ptr<ResourceTable> table =
313       test::ResourceTableBuilder()
314           .AddValue("android:bool/boolean_true",
315                     test::BuildPrimitive(android::Res_value::TYPE_INT_BOOLEAN, true))
316           .AddValue("android:bool/boolean_false",
317                     test::BuildPrimitive(android::Res_value::TYPE_INT_BOOLEAN, false))
318           .AddValue("android:color/color_rgb8", ResourceUtils::TryParseColor("#AABBCC"))
319           .AddValue("android:color/color_argb8", ResourceUtils::TryParseColor("#11223344"))
320           .AddValue("android:color/color_rgb4", ResourceUtils::TryParseColor("#DEF"))
321           .AddValue("android:color/color_argb4", ResourceUtils::TryParseColor("#5678"))
322           .AddValue("android:integer/integer_444", ResourceUtils::TryParseInt("444"))
323           .AddValue("android:integer/integer_neg_333", ResourceUtils::TryParseInt("-333"))
324           .AddValue("android:integer/hex_int_abcd", ResourceUtils::TryParseInt("0xABCD"))
325           .AddValue("android:dimen/dimen_1.39mm", ResourceUtils::TryParseFloat("1.39mm"))
326           .AddValue("android:fraction/fraction_27", ResourceUtils::TryParseFloat("27%"))
327           .AddValue("android:dimen/neg_2.3in", ResourceUtils::TryParseFloat("-2.3in"))
328           .AddValue("android:integer/null", ResourceUtils::MakeEmpty())
329           .Build();
330 
331   pb::ResourceTable pb_table;
332   SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
333 
334   test::TestFile file_a("res/layout/main.xml");
335   MockFileCollection files;
336   EXPECT_CALL(files, FindFile(Eq("res/layout/main.xml")))
337       .WillRepeatedly(::testing::Return(&file_a));
338 
339   ResourceTable new_table;
340   std::string error;
341   ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
342   EXPECT_THAT(error, IsEmpty());
343 
344   BinaryPrimitive* bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
345       &new_table, "android:bool/boolean_true", ConfigDescription::DefaultConfig(), "");
346   ASSERT_THAT(bp, NotNull());
347   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_BOOLEAN));
348   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseBool("true")->value.data));
349 
350   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:bool/boolean_false",
351                                                           ConfigDescription::DefaultConfig(), "");
352   ASSERT_THAT(bp, NotNull());
353   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_BOOLEAN));
354   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseBool("false")->value.data));
355 
356   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_rgb8",
357                                                           ConfigDescription::DefaultConfig(), "");
358   ASSERT_THAT(bp, NotNull());
359   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_RGB8));
360   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#AABBCC")->value.data));
361 
362   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_argb8",
363                                                           ConfigDescription::DefaultConfig(), "");
364   ASSERT_THAT(bp, NotNull());
365   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_ARGB8));
366   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#11223344")->value.data));
367 
368   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_rgb4",
369                                                           ConfigDescription::DefaultConfig(), "");
370   ASSERT_THAT(bp, NotNull());
371   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_RGB4));
372   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#DEF")->value.data));
373 
374   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_argb4",
375                                                           ConfigDescription::DefaultConfig(), "");
376   ASSERT_THAT(bp, NotNull());
377   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_ARGB4));
378   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#5678")->value.data));
379 
380   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:integer/integer_444",
381                                                           ConfigDescription::DefaultConfig(), "");
382   ASSERT_THAT(bp, NotNull());
383   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
384   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("444")->value.data));
385 
386   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
387       &new_table, "android:integer/integer_neg_333", ConfigDescription::DefaultConfig(), "");
388   ASSERT_THAT(bp, NotNull());
389   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
390   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("-333")->value.data));
391 
392   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
393       &new_table, "android:integer/hex_int_abcd", ConfigDescription::DefaultConfig(), "");
394   ASSERT_THAT(bp, NotNull());
395   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_HEX));
396   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("0xABCD")->value.data));
397 
398   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:dimen/dimen_1.39mm",
399                                                           ConfigDescription::DefaultConfig(), "");
400   ASSERT_THAT(bp, NotNull());
401   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
402   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseFloat("1.39mm")->value.data));
403 
404   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
405       &new_table, "android:fraction/fraction_27", ConfigDescription::DefaultConfig(), "");
406   ASSERT_THAT(bp, NotNull());
407   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_FRACTION));
408   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseFloat("27%")->value.data));
409 
410   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:dimen/neg_2.3in",
411                                                           ConfigDescription::DefaultConfig(), "");
412   ASSERT_THAT(bp, NotNull());
413   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
414   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseFloat("-2.3in")->value.data));
415 
416   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:integer/null",
417                                                           ConfigDescription::DefaultConfig(), "");
418   ASSERT_THAT(bp, NotNull());
419   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_NULL));
420   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::MakeEmpty()->value.data));
421 }
422 
ExpectConfigSerializes(const StringPiece & config_str)423 static void ExpectConfigSerializes(const StringPiece& config_str) {
424   const ConfigDescription expected_config = test::ParseConfigOrDie(config_str);
425   pb::Configuration pb_config;
426   SerializeConfig(expected_config, &pb_config);
427 
428   ConfigDescription actual_config;
429   std::string error;
430   ASSERT_TRUE(DeserializeConfigFromPb(pb_config, &actual_config, &error));
431   ASSERT_THAT(error, IsEmpty());
432   EXPECT_EQ(expected_config, actual_config);
433 }
434 
TEST(ProtoSerializeTest,SerializeDeserializeConfiguration)435 TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) {
436   ExpectConfigSerializes("");
437 
438   ExpectConfigSerializes("mcc123");
439 
440   ExpectConfigSerializes("mnc123");
441 
442   ExpectConfigSerializes("en");
443   ExpectConfigSerializes("en-rGB");
444   ExpectConfigSerializes("b+en+GB");
445 
446   ExpectConfigSerializes("ldltr");
447   ExpectConfigSerializes("ldrtl");
448 
449   ExpectConfigSerializes("sw3600dp");
450 
451   ExpectConfigSerializes("w300dp");
452 
453   ExpectConfigSerializes("h400dp");
454 
455   ExpectConfigSerializes("small");
456   ExpectConfigSerializes("normal");
457   ExpectConfigSerializes("large");
458   ExpectConfigSerializes("xlarge");
459 
460   ExpectConfigSerializes("long");
461   ExpectConfigSerializes("notlong");
462 
463   ExpectConfigSerializes("round");
464   ExpectConfigSerializes("notround");
465 
466   ExpectConfigSerializes("widecg");
467   ExpectConfigSerializes("nowidecg");
468 
469   ExpectConfigSerializes("highdr");
470   ExpectConfigSerializes("lowdr");
471 
472   ExpectConfigSerializes("port");
473   ExpectConfigSerializes("land");
474   ExpectConfigSerializes("square");
475 
476   ExpectConfigSerializes("desk");
477   ExpectConfigSerializes("car");
478   ExpectConfigSerializes("television");
479   ExpectConfigSerializes("appliance");
480   ExpectConfigSerializes("watch");
481   ExpectConfigSerializes("vrheadset");
482 
483   ExpectConfigSerializes("night");
484   ExpectConfigSerializes("notnight");
485 
486   ExpectConfigSerializes("300dpi");
487   ExpectConfigSerializes("hdpi");
488 
489   ExpectConfigSerializes("notouch");
490   ExpectConfigSerializes("stylus");
491   ExpectConfigSerializes("finger");
492 
493   ExpectConfigSerializes("keysexposed");
494   ExpectConfigSerializes("keyshidden");
495   ExpectConfigSerializes("keyssoft");
496 
497   ExpectConfigSerializes("nokeys");
498   ExpectConfigSerializes("qwerty");
499   ExpectConfigSerializes("12key");
500 
501   ExpectConfigSerializes("navhidden");
502   ExpectConfigSerializes("navexposed");
503 
504   ExpectConfigSerializes("nonav");
505   ExpectConfigSerializes("dpad");
506   ExpectConfigSerializes("trackball");
507   ExpectConfigSerializes("wheel");
508 
509   ExpectConfigSerializes("300x200");
510 
511   ExpectConfigSerializes("v8");
512 
513   ExpectConfigSerializes(
514       "mcc123-mnc456-b+en+GB-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-land-car-"
515       "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
516 }
517 
TEST(ProtoSerializeTest,SerializeAndDeserializeOverlayable)518 TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) {
519   OverlayableItem overlayable_item_foo(std::make_shared<Overlayable>(
520       "CustomizableResources", "overlay://customization"));
521   overlayable_item_foo.policies |= PolicyFlags::SYSTEM_PARTITION;
522   overlayable_item_foo.policies |= PolicyFlags::PRODUCT_PARTITION;
523 
524   OverlayableItem overlayable_item_bar(std::make_shared<Overlayable>(
525       "TaskBar", "overlay://theme"));
526   overlayable_item_bar.policies |= PolicyFlags::PUBLIC;
527   overlayable_item_bar.policies |= PolicyFlags::VENDOR_PARTITION;
528 
529   OverlayableItem overlayable_item_baz(std::make_shared<Overlayable>(
530       "FontPack", "overlay://theme"));
531   overlayable_item_baz.policies |= PolicyFlags::PUBLIC;
532 
533   OverlayableItem overlayable_item_boz(std::make_shared<Overlayable>(
534       "IconPack", "overlay://theme"));
535   overlayable_item_boz.policies |= PolicyFlags::SIGNATURE;
536   overlayable_item_boz.policies |= PolicyFlags::ODM_PARTITION;
537   overlayable_item_boz.policies |= PolicyFlags::OEM_PARTITION;
538 
539   OverlayableItem overlayable_item_actor_config(std::make_shared<Overlayable>(
540       "ActorConfig", "overlay://theme"));
541   overlayable_item_actor_config.policies |= PolicyFlags::SIGNATURE;
542   overlayable_item_actor_config.policies |= PolicyFlags::ACTOR_SIGNATURE;
543 
544   OverlayableItem overlayable_item_biz(std::make_shared<Overlayable>(
545       "Other", "overlay://customization"));
546   overlayable_item_biz.comment ="comment";
547 
548   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
549   std::unique_ptr<ResourceTable> table =
550       test::ResourceTableBuilder()
551           .SetOverlayable("com.app.a:bool/foo", overlayable_item_foo)
552           .SetOverlayable("com.app.a:bool/bar", overlayable_item_bar)
553           .SetOverlayable("com.app.a:bool/baz", overlayable_item_baz)
554           .SetOverlayable("com.app.a:bool/boz", overlayable_item_boz)
555           .SetOverlayable("com.app.a:bool/biz", overlayable_item_biz)
556           .SetOverlayable("com.app.a:bool/actor_config", overlayable_item_actor_config)
557           .AddValue("com.app.a:bool/fiz", ResourceUtils::TryParseBool("true"))
558           .Build();
559 
560   pb::ResourceTable pb_table;
561   SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
562 
563   MockFileCollection files;
564   ResourceTable new_table;
565   std::string error;
566   ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
567   EXPECT_THAT(error, IsEmpty());
568 
569   Maybe<ResourceTable::SearchResult> search_result =
570       new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
571   ASSERT_TRUE(search_result);
572   ASSERT_TRUE(search_result.value().entry->overlayable_item);
573   OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value();
574   EXPECT_THAT(overlayable_item.overlayable->name, Eq("CustomizableResources"));
575   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://customization"));
576   EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SYSTEM_PARTITION
577                                               | PolicyFlags::PRODUCT_PARTITION));
578 
579   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/bar"));
580   ASSERT_TRUE(search_result);
581   ASSERT_TRUE(search_result.value().entry->overlayable_item);
582   overlayable_item = search_result.value().entry->overlayable_item.value();
583   EXPECT_THAT(overlayable_item.overlayable->name, Eq("TaskBar"));
584   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
585   EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::PUBLIC
586                                               | PolicyFlags::VENDOR_PARTITION));
587 
588   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz"));
589   ASSERT_TRUE(search_result);
590   ASSERT_TRUE(search_result.value().entry->overlayable_item);
591   overlayable_item = search_result.value().entry->overlayable_item.value();
592   EXPECT_THAT(overlayable_item.overlayable->name, Eq("FontPack"));
593   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
594   EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::PUBLIC));
595 
596   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/boz"));
597   ASSERT_TRUE(search_result);
598   ASSERT_TRUE(search_result.value().entry->overlayable_item);
599   overlayable_item = search_result.value().entry->overlayable_item.value();
600   EXPECT_THAT(overlayable_item.overlayable->name, Eq("IconPack"));
601   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
602   EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SIGNATURE
603                                             | PolicyFlags::ODM_PARTITION
604                                             | PolicyFlags::OEM_PARTITION));
605 
606   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/actor_config"));
607   ASSERT_TRUE(search_result);
608   ASSERT_TRUE(search_result.value().entry->overlayable_item);
609   overlayable_item = search_result.value().entry->overlayable_item.value();
610   EXPECT_THAT(overlayable_item.overlayable->name, Eq("ActorConfig"));
611   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
612   EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SIGNATURE
613                                             | PolicyFlags::ACTOR_SIGNATURE));
614 
615   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz"));
616   ASSERT_TRUE(search_result);
617   ASSERT_TRUE(search_result.value().entry->overlayable_item);
618   overlayable_item = search_result.value().entry->overlayable_item.value();
619   EXPECT_THAT(overlayable_item.overlayable->name, Eq("Other"));
620   EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::NONE));
621   EXPECT_THAT(overlayable_item.comment, Eq("comment"));
622 
623   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/fiz"));
624   ASSERT_TRUE(search_result);
625   ASSERT_FALSE(search_result.value().entry->overlayable_item);
626 }
627 
TEST(ProtoSerializeTest,SerializeAndDeserializeDynamicReference)628 TEST(ProtoSerializeTest, SerializeAndDeserializeDynamicReference) {
629   Reference ref(ResourceId(0x00010001));
630   ref.is_dynamic = true;
631 
632   pb::Item pb_item;
633   SerializeItemToPb(ref, &pb_item);
634 
635   ASSERT_TRUE(pb_item.has_ref());
636   EXPECT_EQ(pb_item.ref().id(), ref.id.value().id);
637   EXPECT_TRUE(pb_item.ref().is_dynamic().value());
638 
639   std::unique_ptr<Item> item = DeserializeItemFromPb(pb_item, android::ResStringPool(),
640                                                      android::ConfigDescription(), nullptr,
641                                                      nullptr, nullptr);
642   Reference* actual_ref = ValueCast<Reference>(item.get());
643   EXPECT_EQ(actual_ref->id.value().id, ref.id.value().id);
644   EXPECT_TRUE(actual_ref->is_dynamic);
645 }
646 
TEST(ProtoSerializeTest,SerializeAndDeserializeNonDynamicReference)647 TEST(ProtoSerializeTest, SerializeAndDeserializeNonDynamicReference) {
648   Reference ref(ResourceId(0x00010001));
649 
650   pb::Item pb_item;
651   SerializeItemToPb(ref, &pb_item);
652 
653   ASSERT_TRUE(pb_item.has_ref());
654   EXPECT_EQ(pb_item.ref().id(), ref.id.value().id);
655   EXPECT_FALSE(pb_item.ref().has_is_dynamic());
656 
657   std::unique_ptr<Item> item = DeserializeItemFromPb(pb_item, android::ResStringPool(),
658                                                      android::ConfigDescription(), nullptr,
659                                                      nullptr, nullptr);
660   Reference* actual_ref = ValueCast<Reference>(item.get());
661   EXPECT_EQ(actual_ref->id.value().id, ref.id.value().id);
662   EXPECT_FALSE(actual_ref->is_dynamic);
663 }
664 
665 }  // namespace aapt
666