/* * Copyright (C) 2015 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 "xml/XmlDom.h" #include #include "format/binary/XmlFlattener.h" #include "io/StringStream.h" #include "test/Test.h" using ::aapt::io::StringInputStream; using ::aapt::test::ValueEq; using ::testing::Eq; using ::testing::NotNull; using ::testing::Pointee; using ::testing::SizeIs; using ::testing::StrEq; namespace aapt { namespace xml { TEST(XmlDomTest, Inflate) { std::string input = R"( )"; StdErrDiagnostics diag; StringInputStream in(input); std::unique_ptr doc = Inflate(&in, &diag, Source("test.xml")); ASSERT_THAT(doc, NotNull()); Element* el = doc->root.get(); EXPECT_THAT(el->namespace_decls, SizeIs(1u)); EXPECT_THAT(el->namespace_decls[0].uri, StrEq(xml::kSchemaAndroid)); EXPECT_THAT(el->namespace_decls[0].prefix, StrEq("android")); } TEST(XmlDomTest, BinaryInflate) { std::unique_ptr context = test::ContextBuilder().Build(); std::unique_ptr doc = util::make_unique(); doc->root = util::make_unique(); doc->root->name = "Layout"; doc->root->line_number = 2u; xml::Attribute attr; attr.name = "text"; attr.namespace_uri = kSchemaAndroid; attr.compiled_attribute = AaptAttribute( aapt::Attribute(android::ResTable_map::TYPE_REFERENCE | android::ResTable_map::TYPE_STRING), ResourceId(0x01010001u)); attr.value = "@string/foo"; attr.compiled_value = test::BuildReference("string/foo", ResourceId(0x7f010000u)); doc->root->attributes.push_back(std::move(attr)); NamespaceDecl decl; decl.uri = kSchemaAndroid; decl.prefix = "android"; decl.line_number = 2u; doc->root->namespace_decls.push_back(decl); BigBuffer buffer(4096); XmlFlattenerOptions options; options.keep_raw_values = true; XmlFlattener flattener(&buffer, options); ASSERT_TRUE(flattener.Consume(context.get(), doc.get())); auto block = util::Copy(buffer); std::unique_ptr new_doc = Inflate(block.get(), buffer.size(), nullptr); ASSERT_THAT(new_doc, NotNull()); EXPECT_THAT(new_doc->root->name, StrEq("Layout")); EXPECT_THAT(new_doc->root->line_number, Eq(2u)); ASSERT_THAT(new_doc->root->attributes, SizeIs(1u)); EXPECT_THAT(new_doc->root->attributes[0].name, StrEq("text")); EXPECT_THAT(new_doc->root->attributes[0].namespace_uri, StrEq(kSchemaAndroid)); // We only check that the resource ID was preserved. There is no where to encode the types that // the Attribute accepts (eg: string|reference). ASSERT_TRUE(new_doc->root->attributes[0].compiled_attribute); EXPECT_THAT(new_doc->root->attributes[0].compiled_attribute.value().id, Eq(make_value(ResourceId(0x01010001u)))); EXPECT_THAT(new_doc->root->attributes[0].value, StrEq("@string/foo")); EXPECT_THAT(new_doc->root->attributes[0].compiled_value, Pointee(ValueEq(Reference(ResourceId(0x7f010000u))))); ASSERT_THAT(new_doc->root->namespace_decls, SizeIs(1u)); EXPECT_THAT(new_doc->root->namespace_decls[0].uri, StrEq(kSchemaAndroid)); EXPECT_THAT(new_doc->root->namespace_decls[0].prefix, StrEq("android")); EXPECT_THAT(new_doc->root->namespace_decls[0].line_number, Eq(2u)); } // Escaping is handled after parsing of the values for resource-specific values. TEST(XmlDomTest, ForwardEscapes) { std::unique_ptr doc = test::BuildXmlDom(R"( \\d{5})"); Element* el = doc->root.get(); Attribute* attr = el->FindAttribute({}, "pattern"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, Eq("\\\\d{5}")); attr = el->FindAttribute({}, "value"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, Eq("\\?hello")); ASSERT_THAT(el->children, SizeIs(1u)); Text* text = xml::NodeCast(el->children[0].get()); ASSERT_THAT(text, NotNull()); EXPECT_THAT(text->text, Eq("\\\\d{5}")); } TEST(XmlDomTest, XmlEscapeSequencesAreParsed) { std::unique_ptr doc = test::BuildXmlDom(R"()"); Attribute* attr = doc->root->FindAttribute({}, "value"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, Eq("\"")); } class TestVisitor : public PackageAwareVisitor { public: using PackageAwareVisitor::Visit; void Visit(Element* el) override { if (el->name == "View1") { EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false}))); } else if (el->name == "View2") { EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false}))); EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false}))); } else if (el->name == "View3") { EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false}))); EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false}))); EXPECT_THAT(TransformPackageAlias("three"), Eq(make_value(ExtractedPackage{"com.three", false}))); } else if (el->name == "View4") { EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false}))); EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false}))); EXPECT_THAT(TransformPackageAlias("three"), Eq(make_value(ExtractedPackage{"com.three", false}))); EXPECT_THAT(TransformPackageAlias("four"), Eq(make_value(ExtractedPackage{"", true}))); } } }; TEST(XmlDomTest, PackageAwareXmlVisitor) { std::unique_ptr doc = test::BuildXmlDom(R"( )"); TestVisitor visitor; doc->root->Accept(&visitor); } } // namespace xml } // namespace aapt