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="&quot;" />)");
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