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