blob: 86488792732885cb2c96b946b86aca10048aefde [file] [log] [blame]
Adam Lesinski1ab598f2015-08-14 14:26:04 -07001/*
2 * Copyright (C) 2015 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 "flatten/XmlFlattener.h"
18#include "link/Linkers.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070019#include "test/Builders.h"
20#include "test/Context.h"
Adam Lesinski467f1712015-11-16 17:35:44 -080021#include "util/BigBuffer.h"
22#include "util/Util.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070023
24#include <androidfw/ResourceTypes.h>
25#include <gtest/gtest.h>
26
27namespace aapt {
28
29class XmlFlattenerTest : public ::testing::Test {
30public:
31 void SetUp() override {
32 mContext = test::ContextBuilder()
33 .setCompilationPackage(u"com.app.test")
34 .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
35 .setSymbolTable(test::StaticSymbolTableBuilder()
36 .addSymbol(u"@android:attr/id", ResourceId(0x010100d0),
37 test::AttributeBuilder().build())
38 .addSymbol(u"@com.app.test:id/id", ResourceId(0x7f020000))
39 .addSymbol(u"@android:attr/paddingStart", ResourceId(0x010103b3),
40 test::AttributeBuilder().build())
41 .addSymbol(u"@android:attr/colorAccent", ResourceId(0x01010435),
42 test::AttributeBuilder().build())
43 .build())
44 .build();
45 }
46
Adam Lesinski467f1712015-11-16 17:35:44 -080047 ::testing::AssertionResult flatten(xml::XmlResource* doc, android::ResXMLTree* outTree,
Adam Lesinski1ab598f2015-08-14 14:26:04 -070048 XmlFlattenerOptions options = {}) {
49 BigBuffer buffer(1024);
50 XmlFlattener flattener(&buffer, options);
51 if (!flattener.consume(mContext.get(), doc)) {
52 return ::testing::AssertionFailure() << "failed to flatten XML Tree";
53 }
54
55 std::unique_ptr<uint8_t[]> data = util::copy(buffer);
56 if (outTree->setTo(data.get(), buffer.size(), true) != android::NO_ERROR) {
57 return ::testing::AssertionFailure() << "flattened XML is corrupt";
58 }
59 return ::testing::AssertionSuccess();
60 }
61
62protected:
63 std::unique_ptr<IAaptContext> mContext;
64};
65
66TEST_F(XmlFlattenerTest, FlattenXmlWithNoCompiledAttributes) {
Adam Lesinski467f1712015-11-16 17:35:44 -080067 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom(R"EOF(
Adam Lesinski1ab598f2015-08-14 14:26:04 -070068 <View xmlns:test="http://com.test"
69 attr="hey">
70 <Layout test:hello="hi" />
71 <Layout>Some text</Layout>
72 </View>)EOF");
73
74
75 android::ResXMLTree tree;
76 ASSERT_TRUE(flatten(doc.get(), &tree));
77
78 ASSERT_EQ(tree.next(), android::ResXMLTree::START_NAMESPACE);
79
80 size_t len;
81 const char16_t* namespacePrefix = tree.getNamespacePrefix(&len);
82 EXPECT_EQ(StringPiece16(namespacePrefix, len), u"test");
83
84 const char16_t* namespaceUri = tree.getNamespaceUri(&len);
85 ASSERT_EQ(StringPiece16(namespaceUri, len), u"http://com.test");
86
87 ASSERT_EQ(tree.next(), android::ResXMLTree::START_TAG);
88
89 ASSERT_EQ(tree.getElementNamespace(&len), nullptr);
90 const char16_t* tagName = tree.getElementName(&len);
91 EXPECT_EQ(StringPiece16(tagName, len), u"View");
92
93 ASSERT_EQ(1u, tree.getAttributeCount());
94 ASSERT_EQ(tree.getAttributeNamespace(0, &len), nullptr);
95 const char16_t* attrName = tree.getAttributeName(0, &len);
96 EXPECT_EQ(StringPiece16(attrName, len), u"attr");
97
98 EXPECT_EQ(0, tree.indexOfAttribute(nullptr, 0, u"attr", StringPiece16(u"attr").size()));
99
100 ASSERT_EQ(tree.next(), android::ResXMLTree::START_TAG);
101
102 ASSERT_EQ(tree.getElementNamespace(&len), nullptr);
103 tagName = tree.getElementName(&len);
104 EXPECT_EQ(StringPiece16(tagName, len), u"Layout");
105
106 ASSERT_EQ(1u, tree.getAttributeCount());
107 const char16_t* attrNamespace = tree.getAttributeNamespace(0, &len);
108 EXPECT_EQ(StringPiece16(attrNamespace, len), u"http://com.test");
109
110 attrName = tree.getAttributeName(0, &len);
111 EXPECT_EQ(StringPiece16(attrName, len), u"hello");
112
113 ASSERT_EQ(tree.next(), android::ResXMLTree::END_TAG);
114 ASSERT_EQ(tree.next(), android::ResXMLTree::START_TAG);
115
116 ASSERT_EQ(tree.getElementNamespace(&len), nullptr);
117 tagName = tree.getElementName(&len);
118 EXPECT_EQ(StringPiece16(tagName, len), u"Layout");
119 ASSERT_EQ(0u, tree.getAttributeCount());
120
121 ASSERT_EQ(tree.next(), android::ResXMLTree::TEXT);
122 const char16_t* text = tree.getText(&len);
123 EXPECT_EQ(StringPiece16(text, len), u"Some text");
124
125 ASSERT_EQ(tree.next(), android::ResXMLTree::END_TAG);
126 ASSERT_EQ(tree.getElementNamespace(&len), nullptr);
127 tagName = tree.getElementName(&len);
128 EXPECT_EQ(StringPiece16(tagName, len), u"Layout");
129
130 ASSERT_EQ(tree.next(), android::ResXMLTree::END_TAG);
131 ASSERT_EQ(tree.getElementNamespace(&len), nullptr);
132 tagName = tree.getElementName(&len);
133 EXPECT_EQ(StringPiece16(tagName, len), u"View");
134
135 ASSERT_EQ(tree.next(), android::ResXMLTree::END_NAMESPACE);
136 namespacePrefix = tree.getNamespacePrefix(&len);
137 EXPECT_EQ(StringPiece16(namespacePrefix, len), u"test");
138
139 namespaceUri = tree.getNamespaceUri(&len);
140 ASSERT_EQ(StringPiece16(namespaceUri, len), u"http://com.test");
141
142 ASSERT_EQ(tree.next(), android::ResXMLTree::END_DOCUMENT);
143}
144
145TEST_F(XmlFlattenerTest, FlattenCompiledXmlAndStripSdk21) {
Adam Lesinski467f1712015-11-16 17:35:44 -0800146 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom(R"EOF(
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700147 <View xmlns:android="http://schemas.android.com/apk/res/android"
148 android:paddingStart="1dp"
149 android:colorAccent="#ffffff"/>)EOF");
150
151 XmlReferenceLinker linker;
152 ASSERT_TRUE(linker.consume(mContext.get(), doc.get()));
153 ASSERT_TRUE(linker.getSdkLevels().count(17) == 1);
154 ASSERT_TRUE(linker.getSdkLevels().count(21) == 1);
155
156 android::ResXMLTree tree;
157 XmlFlattenerOptions options;
158 options.maxSdkLevel = 17;
159 ASSERT_TRUE(flatten(doc.get(), &tree, options));
160
161 while (tree.next() != android::ResXMLTree::START_TAG) {
162 ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT);
163 ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT);
164 }
165
166 ASSERT_EQ(1u, tree.getAttributeCount());
167 EXPECT_EQ(uint32_t(0x010103b3), tree.getAttributeNameResID(0));
168}
169
170TEST_F(XmlFlattenerTest, AssignSpecialAttributeIndices) {
Adam Lesinski467f1712015-11-16 17:35:44 -0800171 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom(R"EOF(
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700172 <View xmlns:android="http://schemas.android.com/apk/res/android"
173 android:id="@id/id"
174 class="str"
175 style="@id/id"/>)EOF");
176
177 android::ResXMLTree tree;
178 ASSERT_TRUE(flatten(doc.get(), &tree));
179
180 while (tree.next() != android::ResXMLTree::START_TAG) {
181 ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT);
182 ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT);
183 }
184
185 EXPECT_EQ(tree.indexOfClass(), 0);
186 EXPECT_EQ(tree.indexOfStyle(), 1);
187}
188
189/*
190 * The device ResXMLParser in libandroidfw differentiates between empty namespace and null
191 * namespace.
192 */
193TEST_F(XmlFlattenerTest, NoNamespaceIsNotTheSameAsEmptyNamespace) {
Adam Lesinski467f1712015-11-16 17:35:44 -0800194 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom("<View package=\"android\"/>");
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700195
196 android::ResXMLTree tree;
197 ASSERT_TRUE(flatten(doc.get(), &tree));
198
199 while (tree.next() != android::ResXMLTree::START_TAG) {
200 ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT);
201 ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT);
202 }
203
204 const StringPiece16 kPackage = u"package";
205 EXPECT_GE(tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()), 0);
206}
207
208} // namespace aapt