175f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski/* 275f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski * Copyright (C) 2015 The Android Open Source Project 375f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski * 475f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 575f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski * you may not use this file except in compliance with the License. 675f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski * You may obtain a copy of the License at 775f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski * 875f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 975f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski * 1075f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski * Unless required by applicable law or agreed to in writing, software 1175f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 1275f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1375f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski * See the License for the specific language governing permissions and 1475f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski * limitations under the License. 1575f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski */ 1675f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski 17467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski#include "xml/XmlDom.h" 1875f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski 1975f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski#include <string> 2075f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski 214670805ea441edb8b280f9312571e7799f1284cfAdam Lesinski#include "format/binary/XmlFlattener.h" 22004511660671511ae88e0e837a6f92db28eadaefAdam Lesinski#include "io/StringStream.h" 23ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "test/Test.h" 24ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 25efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinskiusing ::aapt::io::StringInputStream; 26bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinskiusing ::aapt::test::ValueEq; 27fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinskiusing ::testing::Eq; 28a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinskiusing ::testing::NotNull; 29bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinskiusing ::testing::Pointee; 30fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinskiusing ::testing::SizeIs; 316b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinskiusing ::testing::StrEq; 32a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski 3375f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinskinamespace aapt { 346b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinskinamespace xml { 3575f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski 3675f3a55cc569a9b61f540a85d9828e91bdca5047Adam LesinskiTEST(XmlDomTest, Inflate) { 37efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinski std::string input = R"(<?xml version="1.0" encoding="utf-8"?> 38fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski <Layout xmlns:android="http://schemas.android.com/apk/res/android" 39fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski android:layout_width="match_parent" 40fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski android:layout_height="wrap_content"> 41fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski <TextView android:id="@+id/id" 42fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski android:layout_width="wrap_content" 43fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski android:layout_height="wrap_content" /> 44fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski </Layout>)"; 45fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski 46ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StdErrDiagnostics diag; 47efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinski StringInputStream in(input); 486b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski std::unique_ptr<XmlResource> doc = Inflate(&in, &diag, Source("test.xml")); 49a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski ASSERT_THAT(doc, NotNull()); 5075f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski 516b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski Element* el = doc->root.get(); 526b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski EXPECT_THAT(el->namespace_decls, SizeIs(1u)); 536b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski EXPECT_THAT(el->namespace_decls[0].uri, StrEq(xml::kSchemaAndroid)); 546b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski EXPECT_THAT(el->namespace_decls[0].prefix, StrEq("android")); 5575f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski} 5675f3a55cc569a9b61f540a85d9828e91bdca5047Adam Lesinski 570da683bd8da55a0cfa46dfe8076b729b945d6650Adam LesinskiTEST(XmlDomTest, BinaryInflate) { 580da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 590da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski std::unique_ptr<XmlResource> doc = util::make_unique<XmlResource>(); 600da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski doc->root = util::make_unique<Element>(); 610da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski doc->root->name = "Layout"; 620da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski doc->root->line_number = 2u; 630da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski 64bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski xml::Attribute attr; 65bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski attr.name = "text"; 66bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski attr.namespace_uri = kSchemaAndroid; 67bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski attr.compiled_attribute = AaptAttribute( 68bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski aapt::Attribute(android::ResTable_map::TYPE_REFERENCE | android::ResTable_map::TYPE_STRING), 69bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski ResourceId(0x01010001u)); 70bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski attr.value = "@string/foo"; 71bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski attr.compiled_value = test::BuildReference("string/foo", ResourceId(0x7f010000u)); 72bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski doc->root->attributes.push_back(std::move(attr)); 73bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski 740da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski NamespaceDecl decl; 750da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski decl.uri = kSchemaAndroid; 760da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski decl.prefix = "android"; 770da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski decl.line_number = 2u; 780da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski doc->root->namespace_decls.push_back(decl); 790da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski 800da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski BigBuffer buffer(4096); 81bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski XmlFlattenerOptions options; 82bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski options.keep_raw_values = true; 83bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski XmlFlattener flattener(&buffer, options); 840da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski ASSERT_TRUE(flattener.Consume(context.get(), doc.get())); 850da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski 860da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski auto block = util::Copy(buffer); 878780eb6e4918ae24fb1ae74d631042c32e41dc3dAdam Lesinski std::unique_ptr<XmlResource> new_doc = Inflate(block.get(), buffer.size(), nullptr); 880da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski ASSERT_THAT(new_doc, NotNull()); 890da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski 900da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski EXPECT_THAT(new_doc->root->name, StrEq("Layout")); 910da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski EXPECT_THAT(new_doc->root->line_number, Eq(2u)); 92bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski 93bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski ASSERT_THAT(new_doc->root->attributes, SizeIs(1u)); 94bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski EXPECT_THAT(new_doc->root->attributes[0].name, StrEq("text")); 95bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski EXPECT_THAT(new_doc->root->attributes[0].namespace_uri, StrEq(kSchemaAndroid)); 96bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski 97bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski // We only check that the resource ID was preserved. There is no where to encode the types that 98bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski // the Attribute accepts (eg: string|reference). 99bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski ASSERT_TRUE(new_doc->root->attributes[0].compiled_attribute); 100bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski EXPECT_THAT(new_doc->root->attributes[0].compiled_attribute.value().id, 101bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski Eq(make_value(ResourceId(0x01010001u)))); 102bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski 103bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski EXPECT_THAT(new_doc->root->attributes[0].value, StrEq("@string/foo")); 104bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski EXPECT_THAT(new_doc->root->attributes[0].compiled_value, 105bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski Pointee(ValueEq(Reference(ResourceId(0x7f010000u))))); 106bbf429795d0558797e7ac8d1024fa5c16552e96cAdam Lesinski 1070da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski ASSERT_THAT(new_doc->root->namespace_decls, SizeIs(1u)); 1080da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski EXPECT_THAT(new_doc->root->namespace_decls[0].uri, StrEq(kSchemaAndroid)); 1090da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski EXPECT_THAT(new_doc->root->namespace_decls[0].prefix, StrEq("android")); 1100da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski EXPECT_THAT(new_doc->root->namespace_decls[0].line_number, Eq(2u)); 1110da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski} 1120da683bd8da55a0cfa46dfe8076b729b945d6650Adam Lesinski 11348448e8a310e72eb2846ad0f86672ce4f0b47e47Adam Lesinski// Escaping is handled after parsing of the values for resource-specific values. 11448448e8a310e72eb2846ad0f86672ce4f0b47e47Adam LesinskiTEST(XmlDomTest, ForwardEscapes) { 1156b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski std::unique_ptr<XmlResource> doc = test::BuildXmlDom(R"( 116fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski <element value="\?hello" pattern="\\d{5}">\\d{5}</element>)"); 117ac6edc501b61e14e3b70ccbbd4d8ed112d92b96cAdam Lesinski 1186b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski Element* el = doc->root.get(); 119ac6edc501b61e14e3b70ccbbd4d8ed112d92b96cAdam Lesinski 1206b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski Attribute* attr = el->FindAttribute({}, "pattern"); 121a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski ASSERT_THAT(attr, NotNull()); 122fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski EXPECT_THAT(attr->value, Eq("\\\\d{5}")); 123ac6edc501b61e14e3b70ccbbd4d8ed112d92b96cAdam Lesinski 12448448e8a310e72eb2846ad0f86672ce4f0b47e47Adam Lesinski attr = el->FindAttribute({}, "value"); 125a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski ASSERT_THAT(attr, NotNull()); 126fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski EXPECT_THAT(attr->value, Eq("\\?hello")); 127fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski 128fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski ASSERT_THAT(el->children, SizeIs(1u)); 129ac6edc501b61e14e3b70ccbbd4d8ed112d92b96cAdam Lesinski 1306b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski Text* text = xml::NodeCast<xml::Text>(el->children[0].get()); 131a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski ASSERT_THAT(text, NotNull()); 132fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski EXPECT_THAT(text->text, Eq("\\\\d{5}")); 133fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski} 134fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski 135fba0cf2950a91726e475fb180090cc25bcb11a7aAdam LesinskiTEST(XmlDomTest, XmlEscapeSequencesAreParsed) { 1366b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski std::unique_ptr<XmlResource> doc = test::BuildXmlDom(R"(<element value=""" />)"); 1376b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski Attribute* attr = doc->root->FindAttribute({}, "value"); 138fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski ASSERT_THAT(attr, NotNull()); 139fba0cf2950a91726e475fb180090cc25bcb11a7aAdam Lesinski EXPECT_THAT(attr->value, Eq("\"")); 140ac6edc501b61e14e3b70ccbbd4d8ed112d92b96cAdam Lesinski} 141ac6edc501b61e14e3b70ccbbd4d8ed112d92b96cAdam Lesinski 1426b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinskiclass TestVisitor : public PackageAwareVisitor { 1436b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski public: 1446b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski using PackageAwareVisitor::Visit; 1456b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski 1466b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski void Visit(Element* el) override { 1476b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski if (el->name == "View1") { 1481ef0fa9d7242b1926543bc49e35905d1be02a781Adam Lesinski EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false}))); 1496b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski } else if (el->name == "View2") { 1501ef0fa9d7242b1926543bc49e35905d1be02a781Adam Lesinski EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false}))); 1511ef0fa9d7242b1926543bc49e35905d1be02a781Adam Lesinski EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false}))); 1526b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski } else if (el->name == "View3") { 1531ef0fa9d7242b1926543bc49e35905d1be02a781Adam Lesinski EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false}))); 1541ef0fa9d7242b1926543bc49e35905d1be02a781Adam Lesinski EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false}))); 1551ef0fa9d7242b1926543bc49e35905d1be02a781Adam Lesinski EXPECT_THAT(TransformPackageAlias("three"), 1566b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski Eq(make_value(ExtractedPackage{"com.three", false}))); 157c9a2926e661df75ba2517da166bf3b561fd678ecAdam Lesinski } else if (el->name == "View4") { 158c9a2926e661df75ba2517da166bf3b561fd678ecAdam Lesinski EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false}))); 159c9a2926e661df75ba2517da166bf3b561fd678ecAdam Lesinski EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false}))); 160c9a2926e661df75ba2517da166bf3b561fd678ecAdam Lesinski EXPECT_THAT(TransformPackageAlias("three"), 161c9a2926e661df75ba2517da166bf3b561fd678ecAdam Lesinski Eq(make_value(ExtractedPackage{"com.three", false}))); 162c9a2926e661df75ba2517da166bf3b561fd678ecAdam Lesinski EXPECT_THAT(TransformPackageAlias("four"), Eq(make_value(ExtractedPackage{"", true}))); 1636b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski } 1646b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski } 1656b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski}; 1666b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski 1676b372991296c9f2bd6f8f8847dcd23d50970d06dAdam LesinskiTEST(XmlDomTest, PackageAwareXmlVisitor) { 1686b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski std::unique_ptr<XmlResource> doc = test::BuildXmlDom(R"( 1696b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski <View1 xmlns:one="http://schemas.android.com/apk/res/com.one"> 1706b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski <View2 xmlns:two="http://schemas.android.com/apk/res/com.two"> 171c9a2926e661df75ba2517da166bf3b561fd678ecAdam Lesinski <View3 xmlns:three="http://schemas.android.com/apk/res/com.three"> 172c9a2926e661df75ba2517da166bf3b561fd678ecAdam Lesinski <View4 xmlns:four="http://schemas.android.com/apk/res-auto" /> 173c9a2926e661df75ba2517da166bf3b561fd678ecAdam Lesinski </View3> 1746b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski </View2> 1756b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski </View1>)"); 1766b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski 1776b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski TestVisitor visitor; 1786b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski doc->root->Accept(&visitor); 1796b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski} 1806b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski 1816b372991296c9f2bd6f8f8847dcd23d50970d06dAdam Lesinski} // namespace xml 182ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski} // namespace aapt 183