AAPT2: Move format related files under same directory
Test: make aapt2_tests
Change-Id: Id72cdfc12ba3add294048e60c55f2461344464bf
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
new file mode 100644
index 0000000..2154d5a
--- /dev/null
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "format/proto/ProtoSerialize.h"
+
+#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
+
+#include "ResourceUtils.h"
+#include "format/proto/ProtoDeserialize.h"
+#include "test/Test.h"
+
+using ::android::StringPiece;
+using ::google::protobuf::io::StringOutputStream;
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using ::testing::NotNull;
+using ::testing::SizeIs;
+using ::testing::StrEq;
+
+namespace aapt {
+
+TEST(ProtoSerializeTest, SerializeSinglePackage) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddFileReference("com.app.a:layout/main", ResourceId(0x7f020000), "res/layout/main.xml")
+ .AddReference("com.app.a:layout/other", ResourceId(0x7f020001), "com.app.a:layout/main")
+ .AddString("com.app.a:string/text", {}, "hi")
+ .AddValue("com.app.a:id/foo", {}, util::make_unique<Id>())
+ .SetSymbolState("com.app.a:bool/foo", {}, SymbolState::kUndefined, true /*allow_new*/)
+ .Build();
+
+ Symbol public_symbol;
+ public_symbol.state = SymbolState::kPublic;
+ ASSERT_TRUE(table->SetSymbolState(test::ParseNameOrDie("com.app.a:layout/main"),
+ ResourceId(0x7f020000), public_symbol,
+ context->GetDiagnostics()));
+
+ Id* id = test::GetValue<Id>(table.get(), "com.app.a:id/foo");
+ ASSERT_THAT(id, NotNull());
+
+ // Make a plural.
+ std::unique_ptr<Plural> plural = util::make_unique<Plural>();
+ plural->values[Plural::One] = util::make_unique<String>(table->string_pool.MakeRef("one"));
+ ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:plurals/hey"), ConfigDescription{},
+ {}, std::move(plural), context->GetDiagnostics()));
+
+ // Make a styled string.
+ StyleString style_string;
+ style_string.str = "hello";
+ style_string.spans.push_back(Span{"b", 0u, 4u});
+ ASSERT_TRUE(
+ table->AddResource(test::ParseNameOrDie("com.app.a:string/styled"), ConfigDescription{}, {},
+ util::make_unique<StyledString>(table->string_pool.MakeRef(style_string)),
+ context->GetDiagnostics()));
+
+ // Make a resource with different products.
+ ASSERT_TRUE(table->AddResource(
+ test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), {},
+ test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u), context->GetDiagnostics()));
+ ASSERT_TRUE(table->AddResource(
+ test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), "tablet",
+ test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u), context->GetDiagnostics()));
+
+ // Make a reference with both resource name and resource ID.
+ // The reference should point to a resource outside of this table to test that both name and id
+ // get serialized.
+ Reference expected_ref;
+ expected_ref.name = test::ParseNameOrDie("android:layout/main");
+ expected_ref.id = ResourceId(0x01020000);
+ ASSERT_TRUE(table->AddResource(
+ test::ParseNameOrDie("com.app.a:layout/abc"), ConfigDescription::DefaultConfig(), {},
+ util::make_unique<Reference>(expected_ref), context->GetDiagnostics()));
+
+ pb::ResourceTable pb_table;
+ SerializeTableToPb(*table, &pb_table);
+
+ ResourceTable new_table;
+ std::string error;
+ ASSERT_TRUE(DeserializeTableFromPb(pb_table, &new_table, &error));
+ EXPECT_THAT(error, IsEmpty());
+
+ Id* new_id = test::GetValue<Id>(&new_table, "com.app.a:id/foo");
+ ASSERT_THAT(new_id, NotNull());
+ EXPECT_THAT(new_id->IsWeak(), Eq(id->IsWeak()));
+
+ Maybe<ResourceTable::SearchResult> result =
+ new_table.FindResource(test::ParseNameOrDie("com.app.a:layout/main"));
+ ASSERT_TRUE(result);
+
+ EXPECT_THAT(result.value().type->symbol_status.state, Eq(SymbolState::kPublic));
+ EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kPublic));
+
+ result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
+ ASSERT_TRUE(result);
+ EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kUndefined));
+ EXPECT_TRUE(result.value().entry->symbol_status.allow_new);
+
+ // Find the product-dependent values
+ BinaryPrimitive* prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
+ &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "");
+ ASSERT_THAT(prim, NotNull());
+ EXPECT_THAT(prim->value.data, Eq(123u));
+
+ prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
+ &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet");
+ ASSERT_THAT(prim, NotNull());
+ EXPECT_THAT(prim->value.data, Eq(321u));
+
+ Reference* actual_ref = test::GetValue<Reference>(&new_table, "com.app.a:layout/abc");
+ ASSERT_THAT(actual_ref, NotNull());
+ ASSERT_TRUE(actual_ref->name);
+ ASSERT_TRUE(actual_ref->id);
+ EXPECT_THAT(*actual_ref, Eq(expected_ref));
+
+ StyledString* actual_styled_str =
+ test::GetValue<StyledString>(&new_table, "com.app.a:string/styled");
+ ASSERT_THAT(actual_styled_str, NotNull());
+ EXPECT_THAT(actual_styled_str->value->value, Eq("hello"));
+ ASSERT_THAT(actual_styled_str->value->spans, SizeIs(1u));
+ EXPECT_THAT(*actual_styled_str->value->spans[0].name, Eq("b"));
+ EXPECT_THAT(actual_styled_str->value->spans[0].first_char, Eq(0u));
+ EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u));
+}
+
+TEST(ProtoSerializeTest, SerializeFileHeader) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+ ResourceFile f;
+ f.config = test::ParseConfigOrDie("hdpi-v9");
+ f.name = test::ParseNameOrDie("com.app.a:layout/main");
+ f.source.path = "res/layout-hdpi-v9/main.xml";
+ f.exported_symbols.push_back(SourcedResourceName{test::ParseNameOrDie("id/unchecked"), 23u});
+
+ const std::string expected_data1 = "123";
+ const std::string expected_data2 = "1234";
+
+ std::string output_str;
+ {
+ pb::internal::CompiledFile pb_f1, pb_f2;
+ SerializeCompiledFileToPb(f, &pb_f1);
+
+ f.name.entry = "__" + f.name.entry + "$0";
+ SerializeCompiledFileToPb(f, &pb_f2);
+
+ StringOutputStream out_stream(&output_str);
+ CompiledFileOutputStream out_file_stream(&out_stream);
+ out_file_stream.WriteLittleEndian32(2);
+ out_file_stream.WriteCompiledFile(pb_f1);
+ out_file_stream.WriteData(expected_data1.data(), expected_data1.size());
+ out_file_stream.WriteCompiledFile(pb_f2);
+ out_file_stream.WriteData(expected_data2.data(), expected_data2.size());
+ ASSERT_FALSE(out_file_stream.HadError());
+ }
+
+ CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
+ uint32_t num_files = 0;
+ ASSERT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
+ ASSERT_EQ(2u, num_files);
+
+ // Read the first compiled file.
+
+ pb::internal::CompiledFile new_pb_f1;
+ ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_f1));
+
+ ResourceFile new_f1;
+ std::string error;
+ ASSERT_TRUE(DeserializeCompiledFileFromPb(new_pb_f1, &new_f1, &error));
+ EXPECT_THAT(error, IsEmpty());
+
+ uint64_t offset, len;
+ ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
+
+ std::string actual_data(output_str.data() + offset, len);
+ EXPECT_EQ(expected_data1, actual_data);
+
+ // Expect the data to be aligned.
+ EXPECT_EQ(0u, offset & 0x03);
+
+ ASSERT_EQ(1u, new_f1.exported_symbols.size());
+ EXPECT_EQ(test::ParseNameOrDie("id/unchecked"), new_f1.exported_symbols[0].name);
+
+ // Read the second compiled file.
+
+ pb::internal::CompiledFile new_pb_f2;
+ ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_f2));
+
+ ResourceFile new_f2;
+ ASSERT_TRUE(DeserializeCompiledFileFromPb(new_pb_f2, &new_f2, &error));
+ EXPECT_THAT(error, IsEmpty());
+
+ ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
+
+ actual_data = std::string(output_str.data() + offset, len);
+ EXPECT_EQ(expected_data2, actual_data);
+
+ // Expect the data to be aligned.
+ EXPECT_EQ(0u, offset & 0x03);
+}
+
+TEST(ProtoSerializeTest, DeserializeCorruptHeaderSafely) {
+ ResourceFile f;
+ pb::internal::CompiledFile pb_file;
+ SerializeCompiledFileToPb(f, &pb_file);
+
+ const std::string expected_data = "1234";
+
+ std::string output_str;
+ {
+ StringOutputStream out_stream(&output_str);
+ CompiledFileOutputStream out_file_stream(&out_stream);
+ out_file_stream.WriteLittleEndian32(1);
+ out_file_stream.WriteCompiledFile(pb_file);
+ out_file_stream.WriteData(expected_data.data(), expected_data.size());
+ ASSERT_FALSE(out_file_stream.HadError());
+ }
+
+ output_str[4] = 0xff;
+
+ CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
+
+ uint32_t num_files = 0;
+ EXPECT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
+ EXPECT_EQ(1u, num_files);
+
+ pb::internal::CompiledFile new_pb_file;
+ EXPECT_FALSE(in_file_stream.ReadCompiledFile(&new_pb_file));
+
+ uint64_t offset, len;
+ EXPECT_FALSE(in_file_stream.ReadDataMetaData(&offset, &len));
+}
+
+TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
+ xml::Element element;
+ element.line_number = 22;
+ element.column_number = 23;
+ element.name = "element";
+ element.namespace_uri = "uri://";
+
+ xml::NamespaceDecl decl;
+ decl.prefix = "android";
+ decl.uri = xml::kSchemaAndroid;
+ decl.line_number = 21;
+ decl.column_number = 24;
+
+ element.namespace_decls.push_back(decl);
+
+ xml::Attribute attr;
+ attr.name = "name";
+ attr.namespace_uri = xml::kSchemaAndroid;
+ attr.value = "23dp";
+ attr.compiled_attribute = xml::AaptAttribute({}, ResourceId(0x01010000));
+ attr.compiled_value =
+ ResourceUtils::TryParseItemForAttribute(attr.value, android::ResTable_map::TYPE_DIMENSION);
+ attr.compiled_value->SetSource(Source().WithLine(25));
+ element.attributes.push_back(std::move(attr));
+
+ std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>();
+ text->line_number = 25;
+ text->column_number = 3;
+ text->text = "hey there";
+ element.AppendChild(std::move(text));
+
+ std::unique_ptr<xml::Element> child = util::make_unique<xml::Element>();
+ child->name = "child";
+
+ text = util::make_unique<xml::Text>();
+ text->text = "woah there";
+ child->AppendChild(std::move(text));
+
+ element.AppendChild(std::move(child));
+
+ pb::XmlNode pb_xml;
+ SerializeXmlToPb(element, &pb_xml);
+
+ StringPool pool;
+ xml::Element actual_el;
+ std::string error;
+ ASSERT_TRUE(DeserializeXmlFromPb(pb_xml, &actual_el, &pool, &error));
+ ASSERT_THAT(error, IsEmpty());
+
+ EXPECT_THAT(actual_el.name, StrEq("element"));
+ EXPECT_THAT(actual_el.namespace_uri, StrEq("uri://"));
+ EXPECT_THAT(actual_el.line_number, Eq(22u));
+ EXPECT_THAT(actual_el.column_number, Eq(23u));
+
+ ASSERT_THAT(actual_el.namespace_decls, SizeIs(1u));
+ const xml::NamespaceDecl& actual_decl = actual_el.namespace_decls[0];
+ EXPECT_THAT(actual_decl.prefix, StrEq("android"));
+ EXPECT_THAT(actual_decl.uri, StrEq(xml::kSchemaAndroid));
+ EXPECT_THAT(actual_decl.line_number, Eq(21u));
+ EXPECT_THAT(actual_decl.column_number, Eq(24u));
+
+ ASSERT_THAT(actual_el.attributes, SizeIs(1u));
+ const xml::Attribute& actual_attr = actual_el.attributes[0];
+ EXPECT_THAT(actual_attr.name, StrEq("name"));
+ EXPECT_THAT(actual_attr.namespace_uri, StrEq(xml::kSchemaAndroid));
+ EXPECT_THAT(actual_attr.value, StrEq("23dp"));
+
+ ASSERT_THAT(actual_attr.compiled_value, NotNull());
+ const BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(actual_attr.compiled_value.get());
+ ASSERT_THAT(prim, NotNull());
+ EXPECT_THAT(prim->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
+
+ ASSERT_TRUE(actual_attr.compiled_attribute);
+ ASSERT_TRUE(actual_attr.compiled_attribute.value().id);
+
+ ASSERT_THAT(actual_el.children, SizeIs(2u));
+ const xml::Text* child_text = xml::NodeCast<xml::Text>(actual_el.children[0].get());
+ ASSERT_THAT(child_text, NotNull());
+ const xml::Element* child_el = xml::NodeCast<xml::Element>(actual_el.children[1].get());
+ ASSERT_THAT(child_el, NotNull());
+
+ EXPECT_THAT(child_text->line_number, Eq(25u));
+ EXPECT_THAT(child_text->column_number, Eq(3u));
+ EXPECT_THAT(child_text->text, StrEq("hey there"));
+
+ EXPECT_THAT(child_el->name, StrEq("child"));
+ ASSERT_THAT(child_el->children, SizeIs(1u));
+
+ child_text = xml::NodeCast<xml::Text>(child_el->children[0].get());
+ ASSERT_THAT(child_text, NotNull());
+ EXPECT_THAT(child_text->text, StrEq("woah there"));
+}
+
+static void ExpectConfigSerializes(const StringPiece& config_str) {
+ const ConfigDescription expected_config = test::ParseConfigOrDie(config_str);
+ pb::Configuration pb_config;
+ SerializeConfig(expected_config, &pb_config);
+
+ ConfigDescription actual_config;
+ std::string error;
+ ASSERT_TRUE(DeserializeConfigFromPb(pb_config, &actual_config, &error));
+ ASSERT_THAT(error, IsEmpty());
+ EXPECT_EQ(expected_config, actual_config);
+}
+
+TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) {
+ ExpectConfigSerializes("");
+
+ ExpectConfigSerializes("mcc123");
+
+ ExpectConfigSerializes("mnc123");
+
+ ExpectConfigSerializes("en");
+ ExpectConfigSerializes("en-rGB");
+ ExpectConfigSerializes("b+en+GB");
+
+ ExpectConfigSerializes("ldltr");
+ ExpectConfigSerializes("ldrtl");
+
+ ExpectConfigSerializes("sw3600dp");
+
+ ExpectConfigSerializes("w300dp");
+
+ ExpectConfigSerializes("h400dp");
+
+ ExpectConfigSerializes("small");
+ ExpectConfigSerializes("normal");
+ ExpectConfigSerializes("large");
+ ExpectConfigSerializes("xlarge");
+
+ ExpectConfigSerializes("long");
+ ExpectConfigSerializes("notlong");
+
+ ExpectConfigSerializes("round");
+ ExpectConfigSerializes("notround");
+
+ ExpectConfigSerializes("widecg");
+ ExpectConfigSerializes("nowidecg");
+
+ ExpectConfigSerializes("highdr");
+ ExpectConfigSerializes("lowdr");
+
+ ExpectConfigSerializes("port");
+ ExpectConfigSerializes("land");
+ ExpectConfigSerializes("square");
+
+ ExpectConfigSerializes("desk");
+ ExpectConfigSerializes("car");
+ ExpectConfigSerializes("television");
+ ExpectConfigSerializes("appliance");
+ ExpectConfigSerializes("watch");
+ ExpectConfigSerializes("vrheadset");
+
+ ExpectConfigSerializes("night");
+ ExpectConfigSerializes("notnight");
+
+ ExpectConfigSerializes("300dpi");
+ ExpectConfigSerializes("hdpi");
+
+ ExpectConfigSerializes("notouch");
+ ExpectConfigSerializes("stylus");
+ ExpectConfigSerializes("finger");
+
+ ExpectConfigSerializes("keysexposed");
+ ExpectConfigSerializes("keyshidden");
+ ExpectConfigSerializes("keyssoft");
+
+ ExpectConfigSerializes("nokeys");
+ ExpectConfigSerializes("qwerty");
+ ExpectConfigSerializes("12key");
+
+ ExpectConfigSerializes("navhidden");
+ ExpectConfigSerializes("navexposed");
+
+ ExpectConfigSerializes("nonav");
+ ExpectConfigSerializes("dpad");
+ ExpectConfigSerializes("trackball");
+ ExpectConfigSerializes("wheel");
+
+ ExpectConfigSerializes("300x200");
+
+ ExpectConfigSerializes("v8");
+
+ ExpectConfigSerializes(
+ "mcc123-mnc456-b+en+GB-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-land-car-"
+ "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
+}
+
+} // namespace aapt