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::IsNull;
28 using ::testing::NotNull;
29 using ::testing::SizeIs;
30 using ::testing::StrEq;
31 
32 using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
33 
34 namespace aapt {
35 
36 class MockFileCollection : public io::IFileCollection {
37  public:
38   MOCK_METHOD1(FindFile, io::IFile*(StringPiece path));
39   MOCK_METHOD0(Iterator, std::unique_ptr<io::IFileCollectionIterator>());
40   MOCK_METHOD0(GetDirSeparator, char());
41 };
42 
GetEntry(ResourceTable * table,const ResourceNameRef & res_name)43 ResourceEntry* GetEntry(ResourceTable* table, const ResourceNameRef& res_name) {
44   auto result = table->FindResource(res_name);
45   return (result) ? result.value().entry : nullptr;
46 }
47 
GetEntry(ResourceTable * table,const ResourceNameRef & res_name,ResourceId id)48 ResourceEntry* GetEntry(ResourceTable* table, const ResourceNameRef& res_name, ResourceId id) {
49   auto result = table->FindResource(res_name, id);
50   return (result) ? result.value().entry : nullptr;
51 }
52 
TEST(ProtoSerializeTest,SerializeVisibility)53 TEST(ProtoSerializeTest, SerializeVisibility) {
54   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
55   std::unique_ptr<ResourceTable> table =
56       test::ResourceTableBuilder()
57           .Add(NewResourceBuilder("com.app.a:bool/foo")
58                    .SetVisibility({Visibility::Level::kUndefined})
59                    .Build())
60           .Add(NewResourceBuilder("com.app.a:bool/bar")
61                    .SetVisibility({Visibility::Level::kPrivate})
62                    .Build())
63           .Add(NewResourceBuilder("com.app.a:bool/baz")
64                    .SetVisibility({Visibility::Level::kPublic})
65                    .Build())
66           .Add(NewResourceBuilder("com.app.a:bool/fiz")
67                    .SetVisibility({.level = Visibility::Level::kPublic, .staged_api = true})
68                    .Build())
69           .Build();
70 
71   ResourceTable new_table;
72   pb::ResourceTable pb_table;
73   MockFileCollection files;
74   std::string error;
75   SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
76   ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
77   EXPECT_THAT(error, IsEmpty());
78 
79   auto search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
80   ASSERT_TRUE(search_result);
81   EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
82   EXPECT_FALSE(search_result.value().entry->visibility.staged_api);
83 
84   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/bar"));
85   ASSERT_TRUE(search_result);
86   EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kPrivate));
87   EXPECT_FALSE(search_result.value().entry->visibility.staged_api);
88 
89   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz"));
90   ASSERT_TRUE(search_result);
91   EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kPublic));
92   EXPECT_FALSE(search_result.value().entry->visibility.staged_api);
93 
94   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/fiz"));
95   ASSERT_TRUE(search_result);
96   EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kPublic));
97   EXPECT_TRUE(search_result.value().entry->visibility.staged_api);
98 }
99 
TEST(ProtoSerializeTest,SerializeSinglePackage)100 TEST(ProtoSerializeTest, SerializeSinglePackage) {
101   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
102   std::unique_ptr<ResourceTable> table =
103       test::ResourceTableBuilder()
104           .AddFileReference("com.app.a:layout/main", ResourceId(0x7f020000), "res/layout/main.xml")
105           .AddReference("com.app.a:layout/other", ResourceId(0x7f020001), "com.app.a:layout/main")
106           .AddString("com.app.a:string/text", {}, "hi")
107           .AddValue("com.app.a:id/foo", {}, util::make_unique<Id>())
108           .SetSymbolState("com.app.a:bool/foo", {}, Visibility::Level::kUndefined,
109                           true /*allow_new*/)
110           .Build();
111 
112   ASSERT_TRUE(table->AddResource(NewResourceBuilder(test::ParseNameOrDie("com.app.a:layout/main"))
113                                      .SetId(0x7f020000)
114                                      .SetVisibility({Visibility::Level::kPublic})
115                                      .Build(),
116                                  context->GetDiagnostics()));
117 
118   Id* id = test::GetValue<Id>(table.get(), "com.app.a:id/foo");
119   ASSERT_THAT(id, NotNull());
120 
121   // Make a plural.
122   std::unique_ptr<Plural> plural = util::make_unique<Plural>();
123   plural->values[Plural::One] = util::make_unique<String>(table->string_pool.MakeRef("one"));
124   ASSERT_TRUE(table->AddResource(NewResourceBuilder(test::ParseNameOrDie("com.app.a:plurals/hey"))
125                                      .SetValue(std::move(plural))
126                                      .Build(),
127                                  context->GetDiagnostics()));
128 
129   // Make a styled string.
130   android::StyleString style_string;
131   style_string.str = "hello";
132   style_string.spans.push_back(android::Span{"b", 0u, 4u});
133   ASSERT_TRUE(table->AddResource(
134       NewResourceBuilder(test::ParseNameOrDie("com.app.a:string/styled"))
135           .SetValue(util::make_unique<StyledString>(table->string_pool.MakeRef(style_string)))
136           .Build(),
137       context->GetDiagnostics()));
138 
139   // Make a resource with different products.
140   ASSERT_TRUE(
141       table->AddResource(NewResourceBuilder(test::ParseNameOrDie("com.app.a:integer/one"))
142                              .SetValue(test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u),
143                                        test::ParseConfigOrDie("land"))
144                              .Build(),
145                          context->GetDiagnostics()));
146 
147   ASSERT_TRUE(
148       table->AddResource(NewResourceBuilder(test::ParseNameOrDie("com.app.a:integer/one"))
149                              .SetValue(test::BuildPrimitive(android::Res_value::TYPE_INT_HEX, 321u),
150                                        test::ParseConfigOrDie("land"), "tablet")
151                              .Build(),
152                          context->GetDiagnostics()));
153 
154   // Make a reference with both resource name and resource ID.
155   // The reference should point to a resource outside of this table to test that both name and id
156   // get serialized.
157   Reference expected_ref;
158   expected_ref.name = test::ParseNameOrDie("android:layout/main");
159   expected_ref.id = ResourceId(0x01020000);
160   ASSERT_TRUE(table->AddResource(NewResourceBuilder(test::ParseNameOrDie("com.app.a:layout/abc"))
161                                      .SetValue(util::make_unique<Reference>(expected_ref))
162                                      .Build(),
163                                  context->GetDiagnostics()));
164 
165   // Make an overlayable resource.
166   OverlayableItem overlayable_item(std::make_shared<Overlayable>(
167       "OverlayableName", "overlay://theme", android::Source("res/values/overlayable.xml", 40)));
168   overlayable_item.source = android::Source("res/values/overlayable.xml", 42);
169   ASSERT_TRUE(
170       table->AddResource(NewResourceBuilder(test::ParseNameOrDie("com.app.a:integer/overlayable"))
171                              .SetOverlayable(overlayable_item)
172                              .Build(),
173                          context->GetDiagnostics()));
174 
175   pb::ResourceTable pb_table;
176   SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
177 
178   test::TestFile file_a("res/layout/main.xml");
179   MockFileCollection files;
180   EXPECT_CALL(files, FindFile(Eq("res/layout/main.xml")))
181       .WillRepeatedly(::testing::Return(&file_a));
182 
183   ResourceTable new_table;
184   std::string error;
185   ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)) << error;
186   EXPECT_THAT(error, IsEmpty());
187 
188   Id* new_id = test::GetValue<Id>(&new_table, "com.app.a:id/foo");
189   ASSERT_THAT(new_id, NotNull());
190   EXPECT_THAT(new_id->IsWeak(), Eq(id->IsWeak()));
191 
192   std::optional<ResourceTable::SearchResult> result =
193       new_table.FindResource(test::ParseNameOrDie("com.app.a:layout/main"));
194   ASSERT_TRUE(result);
195 
196   EXPECT_THAT(result.value().type->visibility_level, Eq(Visibility::Level::kPublic));
197   EXPECT_THAT(result.value().entry->visibility.level, Eq(Visibility::Level::kPublic));
198 
199   result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
200   ASSERT_TRUE(result);
201   EXPECT_THAT(result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
202   EXPECT_TRUE(result.value().entry->allow_new);
203 
204   // Find the product-dependent values
205   BinaryPrimitive* prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
206       &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "");
207   ASSERT_THAT(prim, NotNull());
208   EXPECT_THAT(prim->value.data, Eq(123u));
209   EXPECT_THAT(prim->value.dataType, Eq(0x10));
210 
211   prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
212       &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet");
213   ASSERT_THAT(prim, NotNull());
214   EXPECT_THAT(prim->value.data, Eq(321u));
215   EXPECT_THAT(prim->value.dataType, Eq(0x11));
216 
217   Reference* actual_ref = test::GetValue<Reference>(&new_table, "com.app.a:layout/abc");
218   ASSERT_THAT(actual_ref, NotNull());
219   ASSERT_TRUE(actual_ref->name);
220   ASSERT_TRUE(actual_ref->id);
221   EXPECT_THAT(*actual_ref, Eq(expected_ref));
222 
223   FileReference* actual_file_ref =
224       test::GetValue<FileReference>(&new_table, "com.app.a:layout/main");
225   ASSERT_THAT(actual_file_ref, NotNull());
226   EXPECT_THAT(actual_file_ref->file, Eq(&file_a));
227 
228   StyledString* actual_styled_str =
229       test::GetValue<StyledString>(&new_table, "com.app.a:string/styled");
230   ASSERT_THAT(actual_styled_str, NotNull());
231   EXPECT_THAT(actual_styled_str->value->value, Eq("hello"));
232   ASSERT_THAT(actual_styled_str->value->spans, SizeIs(1u));
233   EXPECT_THAT(*actual_styled_str->value->spans[0].name, Eq("b"));
234   EXPECT_THAT(actual_styled_str->value->spans[0].first_char, Eq(0u));
235   EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u));
236 
237   std::optional<ResourceTable::SearchResult> search_result =
238       new_table.FindResource(test::ParseNameOrDie("com.app.a:integer/overlayable"));
239   ASSERT_TRUE(search_result);
240   ASSERT_THAT(search_result.value().entry, NotNull());
241   ASSERT_TRUE(search_result.value().entry->overlayable_item);
242   OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
243   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("OverlayableName"));
244   EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
245   EXPECT_THAT(result_overlayable_item.overlayable->source.path, Eq("res/values/overlayable.xml"));
246   EXPECT_THAT(result_overlayable_item.overlayable->source.line, Eq(40));
247   EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::NONE));
248   EXPECT_THAT(result_overlayable_item.source.path, Eq("res/values/overlayable.xml"));
249   EXPECT_THAT(result_overlayable_item.source.line, Eq(42));
250 }
251 
TEST(ProtoSerializeTest,SerializeAndDeserializeXml)252 TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
253   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
254   xml::Element element;
255   element.line_number = 22;
256   element.column_number = 23;
257   element.name = "element";
258   element.namespace_uri = "uri://";
259 
260   xml::NamespaceDecl decl;
261   decl.prefix = "android";
262   decl.uri = xml::kSchemaAndroid;
263   decl.line_number = 21;
264   decl.column_number = 24;
265 
266   element.namespace_decls.push_back(decl);
267 
268   xml::Attribute attr;
269   attr.name = "name";
270   attr.namespace_uri = xml::kSchemaAndroid;
271   attr.value = "23dp";
272   attr.compiled_attribute = xml::AaptAttribute(Attribute{}, ResourceId(0x01010000));
273   attr.compiled_value = ResourceUtils::TryParseItemForAttribute(
274       context->GetDiagnostics(), attr.value, android::ResTable_map::TYPE_DIMENSION);
275   attr.compiled_value->SetSource(android::Source().WithLine(25));
276   element.attributes.push_back(std::move(attr));
277 
278   std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>();
279   text->line_number = 25;
280   text->column_number = 3;
281   text->text = "hey there";
282   element.AppendChild(std::move(text));
283 
284   std::unique_ptr<xml::Element> child = util::make_unique<xml::Element>();
285   child->name = "child";
286 
287   text = util::make_unique<xml::Text>();
288   text->text = "woah there";
289   child->AppendChild(std::move(text));
290 
291   element.AppendChild(std::move(child));
292 
293   pb::XmlNode pb_xml;
294   SerializeXmlToPb(element, &pb_xml);
295 
296   android::StringPool pool;
297   xml::Element actual_el;
298   std::string error;
299   ASSERT_TRUE(DeserializeXmlFromPb(pb_xml, &actual_el, &pool, &error));
300   ASSERT_THAT(error, IsEmpty());
301 
302   EXPECT_THAT(actual_el.name, StrEq("element"));
303   EXPECT_THAT(actual_el.namespace_uri, StrEq("uri://"));
304   EXPECT_THAT(actual_el.line_number, Eq(22u));
305   EXPECT_THAT(actual_el.column_number, Eq(23u));
306 
307   ASSERT_THAT(actual_el.namespace_decls, SizeIs(1u));
308   const xml::NamespaceDecl& actual_decl = actual_el.namespace_decls[0];
309   EXPECT_THAT(actual_decl.prefix, StrEq("android"));
310   EXPECT_THAT(actual_decl.uri, StrEq(xml::kSchemaAndroid));
311   EXPECT_THAT(actual_decl.line_number, Eq(21u));
312   EXPECT_THAT(actual_decl.column_number, Eq(24u));
313 
314   ASSERT_THAT(actual_el.attributes, SizeIs(1u));
315   const xml::Attribute& actual_attr = actual_el.attributes[0];
316   EXPECT_THAT(actual_attr.name, StrEq("name"));
317   EXPECT_THAT(actual_attr.namespace_uri, StrEq(xml::kSchemaAndroid));
318   EXPECT_THAT(actual_attr.value, StrEq("23dp"));
319 
320   ASSERT_THAT(actual_attr.compiled_value, NotNull());
321   const BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(actual_attr.compiled_value.get());
322   ASSERT_THAT(prim, NotNull());
323   EXPECT_THAT(prim->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
324 
325   ASSERT_TRUE(actual_attr.compiled_attribute);
326   ASSERT_TRUE(actual_attr.compiled_attribute.value().id);
327 
328   ASSERT_THAT(actual_el.children, SizeIs(2u));
329   const xml::Text* child_text = xml::NodeCast<xml::Text>(actual_el.children[0].get());
330   ASSERT_THAT(child_text, NotNull());
331   const xml::Element* child_el = xml::NodeCast<xml::Element>(actual_el.children[1].get());
332   ASSERT_THAT(child_el, NotNull());
333 
334   EXPECT_THAT(child_text->line_number, Eq(25u));
335   EXPECT_THAT(child_text->column_number, Eq(3u));
336   EXPECT_THAT(child_text->text, StrEq("hey there"));
337 
338   EXPECT_THAT(child_el->name, StrEq("child"));
339   ASSERT_THAT(child_el->children, SizeIs(1u));
340 
341   child_text = xml::NodeCast<xml::Text>(child_el->children[0].get());
342   ASSERT_THAT(child_text, NotNull());
343   EXPECT_THAT(child_text->text, StrEq("woah there"));
344 }
345 
TEST(ProtoSerializeTest,SerializeAndDeserializeXmlTrimEmptyWhitepsace)346 TEST(ProtoSerializeTest, SerializeAndDeserializeXmlTrimEmptyWhitepsace) {
347   xml::Element element;
348   element.line_number = 22;
349   element.column_number = 23;
350   element.name = "element";
351 
352   std::unique_ptr<xml::Text> trim_text = util::make_unique<xml::Text>();
353   trim_text->line_number = 25;
354   trim_text->column_number = 3;
355   trim_text->text = "  \n   ";
356   element.AppendChild(std::move(trim_text));
357 
358   std::unique_ptr<xml::Text> keep_text = util::make_unique<xml::Text>();
359   keep_text->line_number = 26;
360   keep_text->column_number = 3;
361   keep_text->text = "  hello   ";
362   element.AppendChild(std::move(keep_text));
363 
364   pb::XmlNode pb_xml;
365   SerializeXmlOptions options;
366   options.remove_empty_text_nodes = true;
367   SerializeXmlToPb(element, &pb_xml, options);
368 
369   android::StringPool pool;
370   xml::Element actual_el;
371   std::string error;
372   ASSERT_TRUE(DeserializeXmlFromPb(pb_xml, &actual_el, &pool, &error));
373   ASSERT_THAT(error, IsEmpty());
374 
375   // Only the child that does not consist of only whitespace should remain
376   ASSERT_THAT(actual_el.children, SizeIs(1u));
377   const xml::Text* child_text_keep = xml::NodeCast<xml::Text>(actual_el.children[0].get());
378   ASSERT_THAT(child_text_keep, NotNull());
379   EXPECT_THAT(child_text_keep->text, StrEq( "  hello   "));
380 }
381 
TEST(ProtoSerializeTest,SerializeAndDeserializePrimitives)382 TEST(ProtoSerializeTest, SerializeAndDeserializePrimitives) {
383   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
384   std::unique_ptr<ResourceTable> table =
385       test::ResourceTableBuilder()
386           .AddValue("android:bool/boolean_true",
387                     test::BuildPrimitive(android::Res_value::TYPE_INT_BOOLEAN, true))
388           .AddValue("android:bool/boolean_false",
389                     test::BuildPrimitive(android::Res_value::TYPE_INT_BOOLEAN, false))
390           .AddValue("android:color/color_rgb8", ResourceUtils::TryParseColor("#AABBCC"))
391           .AddValue("android:color/color_argb8", ResourceUtils::TryParseColor("#11223344"))
392           .AddValue("android:color/color_rgb4", ResourceUtils::TryParseColor("#DEF"))
393           .AddValue("android:color/color_argb4", ResourceUtils::TryParseColor("#5678"))
394           .AddValue("android:integer/integer_444", ResourceUtils::TryParseInt("444"))
395           .AddValue("android:integer/integer_neg_333", ResourceUtils::TryParseInt("-333"))
396           .AddValue("android:integer/hex_int_abcd", ResourceUtils::TryParseInt("0xABCD"))
397           .AddValue("android:dimen/dimen_1.39mm", ResourceUtils::TryParseFloat("1.39mm"))
398           .AddValue("android:fraction/fraction_27", ResourceUtils::TryParseFloat("27%"))
399           .AddValue("android:dimen/neg_2.3in", ResourceUtils::TryParseFloat("-2.3in"))
400           .AddValue("android:integer/null", ResourceUtils::MakeEmpty())
401           .Build();
402 
403   pb::ResourceTable pb_table;
404   SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
405 
406   test::TestFile file_a("res/layout/main.xml");
407   MockFileCollection files;
408   EXPECT_CALL(files, FindFile(Eq("res/layout/main.xml")))
409       .WillRepeatedly(::testing::Return(&file_a));
410 
411   ResourceTable new_table;
412   std::string error;
413   ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
414   EXPECT_THAT(error, IsEmpty());
415 
416   BinaryPrimitive* bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
417       &new_table, "android:bool/boolean_true", ConfigDescription::DefaultConfig(), "");
418   ASSERT_THAT(bp, NotNull());
419   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_BOOLEAN));
420   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseBool("true")->value.data));
421 
422   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:bool/boolean_false",
423                                                           ConfigDescription::DefaultConfig(), "");
424   ASSERT_THAT(bp, NotNull());
425   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_BOOLEAN));
426   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseBool("false")->value.data));
427 
428   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_rgb8",
429                                                           ConfigDescription::DefaultConfig(), "");
430   ASSERT_THAT(bp, NotNull());
431   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_RGB8));
432   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#AABBCC")->value.data));
433 
434   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_argb8",
435                                                           ConfigDescription::DefaultConfig(), "");
436   ASSERT_THAT(bp, NotNull());
437   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_ARGB8));
438   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#11223344")->value.data));
439 
440   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_rgb4",
441                                                           ConfigDescription::DefaultConfig(), "");
442   ASSERT_THAT(bp, NotNull());
443   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_RGB4));
444   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#DEF")->value.data));
445 
446   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_argb4",
447                                                           ConfigDescription::DefaultConfig(), "");
448   ASSERT_THAT(bp, NotNull());
449   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_ARGB4));
450   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#5678")->value.data));
451 
452   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:integer/integer_444",
453                                                           ConfigDescription::DefaultConfig(), "");
454   ASSERT_THAT(bp, NotNull());
455   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
456   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("444")->value.data));
457 
458   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
459       &new_table, "android:integer/integer_neg_333", ConfigDescription::DefaultConfig(), "");
460   ASSERT_THAT(bp, NotNull());
461   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
462   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("-333")->value.data));
463 
464   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
465       &new_table, "android:integer/hex_int_abcd", ConfigDescription::DefaultConfig(), "");
466   ASSERT_THAT(bp, NotNull());
467   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_HEX));
468   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("0xABCD")->value.data));
469 
470   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:dimen/dimen_1.39mm",
471                                                           ConfigDescription::DefaultConfig(), "");
472   ASSERT_THAT(bp, NotNull());
473   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
474   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseFloat("1.39mm")->value.data));
475 
476   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
477       &new_table, "android:fraction/fraction_27", ConfigDescription::DefaultConfig(), "");
478   ASSERT_THAT(bp, NotNull());
479   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_FRACTION));
480   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseFloat("27%")->value.data));
481 
482   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:dimen/neg_2.3in",
483                                                           ConfigDescription::DefaultConfig(), "");
484   ASSERT_THAT(bp, NotNull());
485   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
486   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseFloat("-2.3in")->value.data));
487 
488   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:integer/null",
489                                                           ConfigDescription::DefaultConfig(), "");
490   ASSERT_THAT(bp, NotNull());
491   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_NULL));
492   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::MakeEmpty()->value.data));
493 }
494 
ExpectConfigSerializes(StringPiece config_str)495 static void ExpectConfigSerializes(StringPiece config_str) {
496   const ConfigDescription expected_config = test::ParseConfigOrDie(config_str);
497   pb::Configuration pb_config;
498   SerializeConfig(expected_config, &pb_config);
499 
500   ConfigDescription actual_config;
501   std::string error;
502   ASSERT_TRUE(DeserializeConfigFromPb(pb_config, &actual_config, &error));
503   ASSERT_THAT(error, IsEmpty());
504   EXPECT_EQ(expected_config, actual_config);
505 }
506 
TEST(ProtoSerializeTest,SerializeDeserializeConfiguration)507 TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) {
508   ExpectConfigSerializes("");
509 
510   ExpectConfigSerializes("mcc123");
511 
512   ExpectConfigSerializes("mnc123");
513 
514   ExpectConfigSerializes("en");
515   ExpectConfigSerializes("en-rGB");
516   ExpectConfigSerializes("b+en+GB");
517 
518   ExpectConfigSerializes("ldltr");
519   ExpectConfigSerializes("ldrtl");
520 
521   ExpectConfigSerializes("sw3600dp");
522 
523   ExpectConfigSerializes("w300dp");
524 
525   ExpectConfigSerializes("h400dp");
526 
527   ExpectConfigSerializes("small");
528   ExpectConfigSerializes("normal");
529   ExpectConfigSerializes("large");
530   ExpectConfigSerializes("xlarge");
531 
532   ExpectConfigSerializes("long");
533   ExpectConfigSerializes("notlong");
534 
535   ExpectConfigSerializes("round");
536   ExpectConfigSerializes("notround");
537 
538   ExpectConfigSerializes("widecg");
539   ExpectConfigSerializes("nowidecg");
540 
541   ExpectConfigSerializes("highdr");
542   ExpectConfigSerializes("lowdr");
543 
544   ExpectConfigSerializes("port");
545   ExpectConfigSerializes("land");
546   ExpectConfigSerializes("square");
547 
548   ExpectConfigSerializes("desk");
549   ExpectConfigSerializes("car");
550   ExpectConfigSerializes("television");
551   ExpectConfigSerializes("appliance");
552   ExpectConfigSerializes("watch");
553   ExpectConfigSerializes("vrheadset");
554 
555   ExpectConfigSerializes("night");
556   ExpectConfigSerializes("notnight");
557 
558   ExpectConfigSerializes("300dpi");
559   ExpectConfigSerializes("hdpi");
560 
561   ExpectConfigSerializes("notouch");
562   ExpectConfigSerializes("stylus");
563   ExpectConfigSerializes("finger");
564 
565   ExpectConfigSerializes("keysexposed");
566   ExpectConfigSerializes("keyshidden");
567   ExpectConfigSerializes("keyssoft");
568 
569   ExpectConfigSerializes("nokeys");
570   ExpectConfigSerializes("qwerty");
571   ExpectConfigSerializes("12key");
572 
573   ExpectConfigSerializes("navhidden");
574   ExpectConfigSerializes("navexposed");
575 
576   ExpectConfigSerializes("nonav");
577   ExpectConfigSerializes("dpad");
578   ExpectConfigSerializes("trackball");
579   ExpectConfigSerializes("wheel");
580 
581   ExpectConfigSerializes("300x200");
582 
583   ExpectConfigSerializes("v8");
584 
585   ExpectConfigSerializes("en-feminine");
586   ExpectConfigSerializes("en-neuter-v34");
587   ExpectConfigSerializes("feminine-v34");
588 
589   ExpectConfigSerializes(
590       "mcc123-mnc456-b+en+GB-masculine-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-"
591       "land-car-night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
592 }
593 
TEST(ProtoSerializeTest,SerializeAndDeserializeOverlayable)594 TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) {
595   OverlayableItem overlayable_item_foo(std::make_shared<Overlayable>(
596       "CustomizableResources", "overlay://customization"));
597   overlayable_item_foo.policies |= PolicyFlags::SYSTEM_PARTITION;
598   overlayable_item_foo.policies |= PolicyFlags::PRODUCT_PARTITION;
599 
600   OverlayableItem overlayable_item_bar(std::make_shared<Overlayable>(
601       "TaskBar", "overlay://theme"));
602   overlayable_item_bar.policies |= PolicyFlags::PUBLIC;
603   overlayable_item_bar.policies |= PolicyFlags::VENDOR_PARTITION;
604 
605   OverlayableItem overlayable_item_baz(std::make_shared<Overlayable>(
606       "FontPack", "overlay://theme"));
607   overlayable_item_baz.policies |= PolicyFlags::PUBLIC;
608 
609   OverlayableItem overlayable_item_boz(std::make_shared<Overlayable>(
610       "IconPack", "overlay://theme"));
611   overlayable_item_boz.policies |= PolicyFlags::SIGNATURE;
612   overlayable_item_boz.policies |= PolicyFlags::ODM_PARTITION;
613   overlayable_item_boz.policies |= PolicyFlags::OEM_PARTITION;
614 
615   OverlayableItem overlayable_item_actor_config(std::make_shared<Overlayable>(
616       "ActorConfig", "overlay://theme"));
617   overlayable_item_actor_config.policies |= PolicyFlags::SIGNATURE;
618   overlayable_item_actor_config.policies |= PolicyFlags::ACTOR_SIGNATURE;
619 
620   OverlayableItem overlayable_item_biz(std::make_shared<Overlayable>(
621       "Other", "overlay://customization"));
622   overlayable_item_biz.comment ="comment";
623 
624   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
625   std::unique_ptr<ResourceTable> table =
626       test::ResourceTableBuilder()
627           .SetOverlayable("com.app.a:bool/foo", overlayable_item_foo)
628           .SetOverlayable("com.app.a:bool/bar", overlayable_item_bar)
629           .SetOverlayable("com.app.a:bool/baz", overlayable_item_baz)
630           .SetOverlayable("com.app.a:bool/boz", overlayable_item_boz)
631           .SetOverlayable("com.app.a:bool/biz", overlayable_item_biz)
632           .SetOverlayable("com.app.a:bool/actor_config", overlayable_item_actor_config)
633           .AddValue("com.app.a:bool/fiz", ResourceUtils::TryParseBool("true"))
634           .Build();
635 
636   pb::ResourceTable pb_table;
637   SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
638 
639   MockFileCollection files;
640   ResourceTable new_table;
641   std::string error;
642   ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
643   EXPECT_THAT(error, IsEmpty());
644 
645   std::optional<ResourceTable::SearchResult> search_result =
646       new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
647   ASSERT_TRUE(search_result);
648   ASSERT_TRUE(search_result.value().entry->overlayable_item);
649   OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value();
650   EXPECT_THAT(overlayable_item.overlayable->name, Eq("CustomizableResources"));
651   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://customization"));
652   EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SYSTEM_PARTITION
653                                               | PolicyFlags::PRODUCT_PARTITION));
654 
655   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/bar"));
656   ASSERT_TRUE(search_result);
657   ASSERT_TRUE(search_result.value().entry->overlayable_item);
658   overlayable_item = search_result.value().entry->overlayable_item.value();
659   EXPECT_THAT(overlayable_item.overlayable->name, Eq("TaskBar"));
660   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
661   EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::PUBLIC
662                                               | PolicyFlags::VENDOR_PARTITION));
663 
664   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz"));
665   ASSERT_TRUE(search_result);
666   ASSERT_TRUE(search_result.value().entry->overlayable_item);
667   overlayable_item = search_result.value().entry->overlayable_item.value();
668   EXPECT_THAT(overlayable_item.overlayable->name, Eq("FontPack"));
669   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
670   EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::PUBLIC));
671 
672   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/boz"));
673   ASSERT_TRUE(search_result);
674   ASSERT_TRUE(search_result.value().entry->overlayable_item);
675   overlayable_item = search_result.value().entry->overlayable_item.value();
676   EXPECT_THAT(overlayable_item.overlayable->name, Eq("IconPack"));
677   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
678   EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SIGNATURE
679                                             | PolicyFlags::ODM_PARTITION
680                                             | PolicyFlags::OEM_PARTITION));
681 
682   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/actor_config"));
683   ASSERT_TRUE(search_result);
684   ASSERT_TRUE(search_result.value().entry->overlayable_item);
685   overlayable_item = search_result.value().entry->overlayable_item.value();
686   EXPECT_THAT(overlayable_item.overlayable->name, Eq("ActorConfig"));
687   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
688   EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SIGNATURE
689                                             | PolicyFlags::ACTOR_SIGNATURE));
690 
691   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz"));
692   ASSERT_TRUE(search_result);
693   ASSERT_TRUE(search_result.value().entry->overlayable_item);
694   overlayable_item = search_result.value().entry->overlayable_item.value();
695   EXPECT_THAT(overlayable_item.overlayable->name, Eq("Other"));
696   EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::NONE));
697   EXPECT_THAT(overlayable_item.comment, Eq("comment"));
698 
699   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/fiz"));
700   ASSERT_TRUE(search_result);
701   ASSERT_FALSE(search_result.value().entry->overlayable_item);
702 }
703 
TEST(ProtoSerializeTest,SerializeAndDeserializeDynamicReference)704 TEST(ProtoSerializeTest, SerializeAndDeserializeDynamicReference) {
705   Reference ref(ResourceId(0x00010001));
706   ref.is_dynamic = true;
707 
708   pb::Item pb_item;
709   SerializeItemToPb(ref, &pb_item);
710 
711   ASSERT_TRUE(pb_item.has_ref());
712   EXPECT_EQ(pb_item.ref().id(), ref.id.value().id);
713   EXPECT_TRUE(pb_item.ref().is_dynamic().value());
714 
715   std::unique_ptr<Item> item = DeserializeItemFromPb(pb_item, android::ResStringPool(),
716                                                      android::ConfigDescription(), nullptr,
717                                                      nullptr, nullptr);
718   Reference* actual_ref = ValueCast<Reference>(item.get());
719   EXPECT_EQ(actual_ref->id.value().id, ref.id.value().id);
720   EXPECT_TRUE(actual_ref->is_dynamic);
721 }
722 
TEST(ProtoSerializeTest,SerializeAndDeserializeNonDynamicReference)723 TEST(ProtoSerializeTest, SerializeAndDeserializeNonDynamicReference) {
724   Reference ref(ResourceId(0x00010001));
725 
726   pb::Item pb_item;
727   SerializeItemToPb(ref, &pb_item);
728 
729   ASSERT_TRUE(pb_item.has_ref());
730   EXPECT_EQ(pb_item.ref().id(), ref.id.value().id);
731   EXPECT_FALSE(pb_item.ref().has_is_dynamic());
732 
733   std::unique_ptr<Item> item = DeserializeItemFromPb(pb_item, android::ResStringPool(),
734                                                      android::ConfigDescription(), nullptr,
735                                                      nullptr, nullptr);
736   Reference* actual_ref = ValueCast<Reference>(item.get());
737   EXPECT_EQ(actual_ref->id.value().id, ref.id.value().id);
738   EXPECT_FALSE(actual_ref->is_dynamic);
739 }
740 
TEST(ProtoSerializeTest,CollapsingResourceNamesNoNameCollapseExemptionsSucceeds)741 TEST(ProtoSerializeTest, CollapsingResourceNamesNoNameCollapseExemptionsSucceeds) {
742   const uint32_t id_one_id = 0x7f020000;
743   const uint32_t id_two_id = 0x7f020001;
744   const uint32_t id_three_id = 0x7f020002;
745   const uint32_t integer_three_id = 0x7f030000;
746   const uint32_t string_test_id = 0x7f040000;
747   const uint32_t layout_bar_id = 0x7f050000;
748   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
749   std::unique_ptr<ResourceTable> table =
750       test::ResourceTableBuilder()
751           .AddSimple("com.app.test:id/one", ResourceId(id_one_id))
752           .AddSimple("com.app.test:id/two", ResourceId(id_two_id))
753           .AddValue("com.app.test:id/three", ResourceId(id_three_id),
754                     test::BuildReference("com.app.test:id/one", ResourceId(id_one_id)))
755           .AddValue("com.app.test:integer/one", ResourceId(integer_three_id),
756                     util::make_unique<BinaryPrimitive>(
757                         uint8_t(android::Res_value::TYPE_INT_DEC), 1u))
758           .AddValue("com.app.test:integer/one", test::ParseConfigOrDie("v1"),
759                     ResourceId(integer_three_id),
760                     util::make_unique<BinaryPrimitive>(
761                         uint8_t(android::Res_value::TYPE_INT_DEC), 2u))
762           .AddString("com.app.test:string/test", ResourceId(string_test_id), "foo")
763           .AddFileReference("com.app.test:layout/bar", ResourceId(layout_bar_id),
764                             "res/layout/bar.xml")
765           .Build();
766 
767   SerializeTableOptions options;
768   options.collapse_key_stringpool = true;
769 
770   pb::ResourceTable pb_table;
771 
772   SerializeTableToPb(*table, &pb_table, context->GetDiagnostics(), options);
773   test::TestFile file_a("res/layout/bar.xml");
774   MockFileCollection files;
775   EXPECT_CALL(files, FindFile(Eq("res/layout/bar.xml")))
776       .WillRepeatedly(::testing::Return(&file_a));
777   ResourceTable new_table;
778   std::string error;
779   ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)) << error;
780   EXPECT_THAT(error, IsEmpty());
781 
782   ResourceName real_id_resource(
783       "com.app.test", ResourceType::kId, "one");
784   EXPECT_THAT(GetEntry(&new_table, real_id_resource), IsNull());
785 
786   ResourceName obfuscated_id_resource(
787       "com.app.test", ResourceType::kId, "0_resource_name_obfuscated");
788 
789   EXPECT_THAT(GetEntry(&new_table, obfuscated_id_resource,
790                   id_one_id), NotNull());
791   EXPECT_THAT(GetEntry(&new_table, obfuscated_id_resource,
792                   id_two_id), NotNull());
793   ResourceEntry* entry = GetEntry(&new_table, obfuscated_id_resource, id_three_id);
794   EXPECT_THAT(entry, NotNull());
795   ResourceConfigValue* config_value = entry->FindValue({});
796   Reference* ref = ValueCast<Reference>(config_value->value.get());
797   EXPECT_THAT(ref->id.value(), Eq(id_one_id));
798 
799   ResourceName obfuscated_integer_resource(
800       "com.app.test", ResourceType::kInteger, "0_resource_name_obfuscated");
801   entry = GetEntry(&new_table, obfuscated_integer_resource, integer_three_id);
802   EXPECT_THAT(entry, NotNull());
803   config_value = entry->FindValue({});
804   BinaryPrimitive* bp = ValueCast<BinaryPrimitive>(config_value->value.get());
805   EXPECT_THAT(bp->value.data, Eq(1u));
806 
807   config_value = entry->FindValue(test::ParseConfigOrDie("v1"));
808   bp = ValueCast<BinaryPrimitive>(config_value->value.get());
809   EXPECT_THAT(bp->value.data, Eq(2u));
810 
811   ResourceName obfuscated_string_resource(
812       "com.app.test", ResourceType::kString, "0_resource_name_obfuscated");
813   entry = GetEntry(&new_table, obfuscated_string_resource, string_test_id);
814   EXPECT_THAT(entry, NotNull());
815   config_value = entry->FindValue({});
816   String* s = ValueCast<String>(config_value->value.get());
817   EXPECT_THAT(*(s->value), Eq("foo"));
818 
819   ResourceName obfuscated_layout_resource(
820       "com.app.test", ResourceType::kLayout, "0_resource_name_obfuscated");
821   entry = GetEntry(&new_table, obfuscated_layout_resource, layout_bar_id);
822   EXPECT_THAT(entry, NotNull());
823   config_value = entry->FindValue({});
824   FileReference* f = ValueCast<FileReference>(config_value->value.get());
825   EXPECT_THAT(*(f->path), Eq("res/layout/bar.xml"));
826 }
827 
TEST(ProtoSerializeTest,ObfuscatingResourceNamesWithNameCollapseExemptionsSucceeds)828 TEST(ProtoSerializeTest, ObfuscatingResourceNamesWithNameCollapseExemptionsSucceeds) {
829   const uint32_t id_one_id = 0x7f020000;
830   const uint32_t id_two_id = 0x7f020001;
831   const uint32_t id_three_id = 0x7f020002;
832   const uint32_t integer_three_id = 0x7f030000;
833   const uint32_t string_test_id = 0x7f040000;
834   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
835   std::unique_ptr<ResourceTable> table =
836       test::ResourceTableBuilder()
837           .AddSimple("com.app.test:id/one", ResourceId(id_one_id))
838           .AddSimple("com.app.test:id/two", ResourceId(id_two_id))
839           .AddValue("com.app.test:id/three", ResourceId(id_three_id),
840                     test::BuildReference("com.app.test:id/one", ResourceId(id_one_id)))
841           .AddValue("com.app.test:integer/one", ResourceId(integer_three_id),
842                     util::make_unique<BinaryPrimitive>(
843                         uint8_t(android::Res_value::TYPE_INT_DEC), 1u))
844           .AddValue("com.app.test:integer/one", test::ParseConfigOrDie("v1"),
845                     ResourceId(integer_three_id),
846                     util::make_unique<BinaryPrimitive>(
847                         uint8_t(android::Res_value::TYPE_INT_DEC), 2u))
848           .AddString("com.app.test:string/test", ResourceId(string_test_id), "foo")
849           .Build();
850 
851   SerializeTableOptions options;
852   options.collapse_key_stringpool = true;
853   options.name_collapse_exemptions.insert(ResourceName({}, ResourceType::kId, "one"));
854   options.name_collapse_exemptions.insert(ResourceName({}, ResourceType::kString, "test"));
855   pb::ResourceTable pb_table;
856 
857   SerializeTableToPb(*table, &pb_table, context->GetDiagnostics(), options);
858   MockFileCollection files;
859   ResourceTable new_table;
860   std::string error;
861   ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)) << error;
862   EXPECT_THAT(error, IsEmpty());
863 
864   EXPECT_THAT(GetEntry(&new_table, ResourceName("com.app.test", ResourceType::kId, "one"),
865                        id_one_id), NotNull());
866   ResourceName obfuscated_id_resource(
867       "com.app.test", ResourceType::kId, "0_resource_name_obfuscated");
868   EXPECT_THAT(GetEntry(&new_table, obfuscated_id_resource, id_one_id), IsNull());
869 
870   ResourceName real_id_resource(
871       "com.app.test", ResourceType::kId, "two");
872   EXPECT_THAT(GetEntry(&new_table, real_id_resource, id_two_id), IsNull());
873   EXPECT_THAT(GetEntry(&new_table, obfuscated_id_resource, id_two_id), NotNull());
874 
875   ResourceEntry* entry = GetEntry(&new_table, obfuscated_id_resource, id_three_id);
876   EXPECT_THAT(entry, NotNull());
877   ResourceConfigValue* config_value = entry->FindValue({});
878   Reference* ref = ValueCast<Reference>(config_value->value.get());
879   EXPECT_THAT(ref->id.value(), Eq(id_one_id));
880 
881   // Note that this resource is also named "one", but it's a different type, so gets obfuscated.
882   ResourceName obfuscated_integer_resource(
883       "com.app.test", ResourceType::kInteger, "0_resource_name_obfuscated");
884   entry = GetEntry(&new_table, obfuscated_integer_resource, integer_three_id);
885   EXPECT_THAT(entry, NotNull());
886   config_value = entry->FindValue({});
887   BinaryPrimitive* bp = ValueCast<BinaryPrimitive>(config_value->value.get());
888   EXPECT_THAT(bp->value.data, Eq(1u));
889 
890   config_value = entry->FindValue(test::ParseConfigOrDie("v1"));
891   bp = ValueCast<BinaryPrimitive>(config_value->value.get());
892   EXPECT_THAT(bp->value.data, Eq(2u));
893 
894   entry = GetEntry(&new_table, ResourceName("com.app.test", ResourceType::kString, "test"),
895                    string_test_id);
896   EXPECT_THAT(entry, NotNull());
897   config_value = entry->FindValue({});
898   String* s = ValueCast<String>(config_value->value.get());
899   EXPECT_THAT(*(s->value), Eq("foo"));
900 }
901 
TEST(ProtoSerializeTest,SerializeMacro)902 TEST(ProtoSerializeTest, SerializeMacro) {
903   auto original = std::make_unique<Macro>();
904   original->raw_value = "\nThis being human is a guest house.";
905   original->style_string.str = " This being human is a guest house.";
906   original->style_string.spans.emplace_back(
907       android::Span{.name = "b", .first_char = 12, .last_char = 16});
908   original->untranslatable_sections.emplace_back(UntranslatableSection{.start = 12, .end = 17});
909   original->alias_namespaces.emplace_back(
910       Macro::Namespace{.alias = "prefix", .package_name = "package.name", .is_private = true});
911 
912   CloningValueTransformer cloner(nullptr);
913   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
914   std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
915                                              .Add(NewResourceBuilder("com.app.a:macro/foo")
916                                                       .SetValue(original->Transform(cloner))
917                                                       .Build())
918                                              .Build();
919 
920   ResourceTable new_table;
921   pb::ResourceTable pb_table;
922   MockFileCollection files;
923   std::string error;
924   SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
925   ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
926   EXPECT_THAT(error, IsEmpty());
927 
928   Macro* deserialized = test::GetValue<Macro>(&new_table, "com.app.a:macro/foo");
929   ASSERT_THAT(deserialized, NotNull());
930   EXPECT_THAT(deserialized->raw_value, Eq(original->raw_value));
931   EXPECT_THAT(deserialized->style_string.str, Eq(original->style_string.str));
932   EXPECT_THAT(deserialized->style_string.spans, Eq(original->style_string.spans));
933   EXPECT_THAT(deserialized->untranslatable_sections, Eq(original->untranslatable_sections));
934   EXPECT_THAT(deserialized->alias_namespaces, Eq(original->alias_namespaces));
935 }
936 
TEST(ProtoSerializeTest,StagedId)937 TEST(ProtoSerializeTest, StagedId) {
938   CloningValueTransformer cloner(nullptr);
939   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
940   std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
941                                              .Add(NewResourceBuilder("com.app.a:string/foo")
942                                                       .SetStagedId(StagedId{.id = 0x01ff0001})
943                                                       .Build())
944                                              .Build();
945 
946   ResourceTable new_table;
947   pb::ResourceTable pb_table;
948   MockFileCollection files;
949   std::string error;
950   SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
951   ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
952   EXPECT_THAT(error, IsEmpty());
953 
954   auto result = new_table.FindResource(test::ParseNameOrDie("com.app.a:string/foo"));
955   ASSERT_TRUE(result);
956   ASSERT_TRUE(result.value().entry->staged_id);
957   EXPECT_THAT(result.value().entry->staged_id.value().id, Eq(ResourceId(0x01ff0001)));
958 }
959 
TEST(ProtoSerializeTest,CustomResourceTypes)960 TEST(ProtoSerializeTest, CustomResourceTypes) {
961   const uint32_t id_one_id = 0x7f020000;
962   const uint32_t id_2_two_id = 0x7f030000;
963   const uint32_t integer_three_id = 0x7f030000;
964   const uint32_t integer_1_four_id = 0x7f030000;
965   const uint32_t layout_bar_id = 0x7f050000;
966   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
967   std::unique_ptr<ResourceTable> table =
968       test::ResourceTableBuilder()
969           .AddSimple("com.app.test:id/one", ResourceId(id_one_id))
970           .AddSimple("com.app.test:id.2/two", ResourceId(id_2_two_id))
971           .AddValue(
972               "com.app.test:integer/one", ResourceId(integer_three_id),
973               util::make_unique<BinaryPrimitive>(uint8_t(android::Res_value::TYPE_INT_DEC), 10u))
974           .AddValue(
975               "com.app.test:integer.1/one", ResourceId(integer_1_four_id),
976               util::make_unique<BinaryPrimitive>(uint8_t(android::Res_value::TYPE_INT_DEC), 1u))
977           .AddValue(
978               "com.app.test:integer.1/one", test::ParseConfigOrDie("v1"),
979               ResourceId(integer_1_four_id),
980               util::make_unique<BinaryPrimitive>(uint8_t(android::Res_value::TYPE_INT_DEC), 2u))
981           .AddFileReference("com.app.test:layout.custom/bar", ResourceId(layout_bar_id),
982                             "res/layout/bar.xml")
983           .Build();
984 
985   test::TestFile file_a("res/layout/bar.xml");
986   MockFileCollection files;
987   EXPECT_CALL(files, FindFile(Eq("res/layout/bar.xml"))).WillRepeatedly(::testing::Return(&file_a));
988 
989   ResourceTable new_table;
990   pb::ResourceTable pb_table;
991   std::string error;
992   SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
993   DeserializeTableFromPb(pb_table, &files, &new_table, &error);
994   ASSERT_THAT(error, IsEmpty());
995 
996   auto bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
997       &new_table, "com.app.test:integer.1/one", ConfigDescription::DefaultConfig(), "");
998   ASSERT_THAT(bp, NotNull());
999   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
1000   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("1")->value.data));
1001 
1002   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "com.app.test:integer.1/one",
1003                                                           test::ParseConfigOrDie("v1"), "");
1004   ASSERT_THAT(bp, NotNull());
1005   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
1006   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("2")->value.data));
1007 
1008   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "com.app.test:integer/one",
1009                                                           ConfigDescription::DefaultConfig(), "");
1010   ASSERT_THAT(bp, NotNull());
1011   EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
1012   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("10")->value.data));
1013 
1014   bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "com.app.test:integer/one",
1015                                                           test::ParseConfigOrDie("v1"), "");
1016   ASSERT_THAT(bp, IsNull());
1017 
1018   auto id = test::GetValueForConfigAndProduct<Id>(&new_table, "com.app.test:id/one",
1019                                                   ConfigDescription::DefaultConfig(), "");
1020   ASSERT_THAT(id, NotNull());
1021 
1022   id = test::GetValueForConfigAndProduct<Id>(&new_table, "com.app.test:id.2/two",
1023                                              ConfigDescription::DefaultConfig(), "");
1024   ASSERT_THAT(id, NotNull());
1025 
1026   auto custom_layout = test::GetValueForConfigAndProduct<FileReference>(
1027       &new_table, "com.app.test:layout.custom/bar", ConfigDescription::DefaultConfig(), "");
1028   ASSERT_THAT(custom_layout, NotNull());
1029   EXPECT_THAT(*(custom_layout->path), Eq("res/layout/bar.xml"));
1030 }
1031 
TEST(ProtoSerializeTest,SerializeDynamicRef)1032 TEST(ProtoSerializeTest, SerializeDynamicRef) {
1033   std::unique_ptr<IAaptContext> context =
1034       test::ContextBuilder().SetCompilationPackage("app").SetPackageId(0x7f).Build();
1035   std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder().Build();
1036   table->included_packages_.insert({20, "foobar"});
1037   table->included_packages_.insert({30, "barfoo"});
1038 
1039   ResourceTable new_table;
1040   pb::ResourceTable pb_table;
1041   MockFileCollection files;
1042   std::string error;
1043   SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
1044   ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
1045   EXPECT_THAT(error, IsEmpty());
1046 
1047   int result = new_table.included_packages_.size();
1048   EXPECT_THAT(result, Eq(2));
1049   auto it = new_table.included_packages_.begin();
1050   EXPECT_THAT(it->first, Eq(20));
1051   EXPECT_THAT(it->second, Eq("foobar"));
1052   it++;
1053   EXPECT_THAT(it->first, Eq(30));
1054   EXPECT_THAT(it->second, Eq("barfoo"));
1055 }
1056 }  // namespace aapt
1057