XmlFlattener_test.cpp revision 64587af8179affd38ee26543b748f2d63b7f67bb
1/* 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" 19#include "test/Builders.h" 20#include "test/Context.h" 21#include "util/BigBuffer.h" 22#include "util/Util.h" 23 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 .addSymbolSource(test::StaticSymbolSourceBuilder() 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 47 ::testing::AssertionResult flatten(xml::XmlResource* doc, android::ResXMLTree* outTree, 48 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) { 67 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom(R"EOF( 68 <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) { 146 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom(R"EOF( 147 <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) { 171 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom(R"EOF( 172 <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) { 194 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom("<View package=\"android\"/>"); 195 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 209