XmlReferenceLinker_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 <test/Context.h> 18#include "link/Linkers.h" 19#include "test/Test.h" 20 21namespace aapt { 22 23class XmlReferenceLinkerTest : public ::testing::Test { 24public: 25 void SetUp() override { 26 mContext = test::ContextBuilder() 27 .setCompilationPackage(u"com.app.test") 28 .setNameManglerPolicy( 29 NameManglerPolicy{ u"com.app.test", { u"com.android.support" } }) 30 .addSymbolSource(test::StaticSymbolSourceBuilder() 31 .addPublicSymbol(u"@android:attr/layout_width", ResourceId(0x01010000), 32 test::AttributeBuilder() 33 .setTypeMask(android::ResTable_map::TYPE_ENUM | 34 android::ResTable_map::TYPE_DIMENSION) 35 .addItem(u"match_parent", 0xffffffff) 36 .build()) 37 .addPublicSymbol(u"@android:attr/background", ResourceId(0x01010001), 38 test::AttributeBuilder() 39 .setTypeMask(android::ResTable_map::TYPE_COLOR).build()) 40 .addPublicSymbol(u"@android:attr/attr", ResourceId(0x01010002), 41 test::AttributeBuilder().build()) 42 .addPublicSymbol(u"@android:attr/text", ResourceId(0x01010003), 43 test::AttributeBuilder() 44 .setTypeMask(android::ResTable_map::TYPE_STRING) 45 .build()) 46 47 // Add one real symbol that was introduces in v21 48 .addPublicSymbol(u"@android:attr/colorAccent", ResourceId(0x01010435), 49 test::AttributeBuilder().build()) 50 51 // Private symbol. 52 .addSymbol(u"@android:color/hidden", ResourceId(0x01020001)) 53 54 .addPublicSymbol(u"@android:id/id", ResourceId(0x01030000)) 55 .addSymbol(u"@com.app.test:id/id", ResourceId(0x7f030000)) 56 .addSymbol(u"@com.app.test:color/green", ResourceId(0x7f020000)) 57 .addSymbol(u"@com.app.test:color/red", ResourceId(0x7f020001)) 58 .addSymbol(u"@com.app.test:attr/colorAccent", ResourceId(0x7f010000), 59 test::AttributeBuilder() 60 .setTypeMask(android::ResTable_map::TYPE_COLOR).build()) 61 .addPublicSymbol(u"@com.app.test:attr/com.android.support$colorAccent", 62 ResourceId(0x7f010001), test::AttributeBuilder() 63 .setTypeMask(android::ResTable_map::TYPE_COLOR).build()) 64 .addPublicSymbol(u"@com.app.test:attr/attr", ResourceId(0x7f010002), 65 test::AttributeBuilder().build()) 66 .build()) 67 .build(); 68 } 69 70protected: 71 std::unique_ptr<IAaptContext> mContext; 72}; 73 74TEST_F(XmlReferenceLinkerTest, LinkBasicAttributes) { 75 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF( 76 <View xmlns:android="http://schemas.android.com/apk/res/android" 77 android:layout_width="match_parent" 78 android:background="@color/green" 79 android:text="hello" 80 class="hello" />)EOF"); 81 82 XmlReferenceLinker linker; 83 ASSERT_TRUE(linker.consume(mContext.get(), doc.get())); 84 85 xml::Element* viewEl = xml::findRootElement(doc.get()); 86 ASSERT_NE(viewEl, nullptr); 87 88 xml::Attribute* xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/android", 89 u"layout_width"); 90 ASSERT_NE(xmlAttr, nullptr); 91 AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute); 92 AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id); 93 EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x01010000)); 94 ASSERT_NE(xmlAttr->compiledValue, nullptr); 95 ASSERT_NE(valueCast<BinaryPrimitive>(xmlAttr->compiledValue.get()), nullptr); 96 97 xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/android", u"background"); 98 ASSERT_NE(xmlAttr, nullptr); 99 AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute); 100 AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id); 101 EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x01010001)); 102 ASSERT_NE(xmlAttr->compiledValue, nullptr); 103 Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get()); 104 ASSERT_NE(ref, nullptr); 105 AAPT_ASSERT_TRUE(ref->name); 106 EXPECT_EQ(ref->name.value(), test::parseNameOrDie(u"@color/green")); // Make sure the name 107 // didn't change. 108 AAPT_ASSERT_TRUE(ref->id); 109 EXPECT_EQ(ref->id.value(), ResourceId(0x7f020000)); 110 111 xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/android", u"text"); 112 ASSERT_NE(xmlAttr, nullptr); 113 AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute); 114 ASSERT_FALSE(xmlAttr->compiledValue); // Strings don't get compiled for memory sake. 115 116 xmlAttr = viewEl->findAttribute(u"", u"class"); 117 ASSERT_NE(xmlAttr, nullptr); 118 AAPT_ASSERT_FALSE(xmlAttr->compiledAttribute); 119 ASSERT_EQ(xmlAttr->compiledValue, nullptr); 120} 121 122TEST_F(XmlReferenceLinkerTest, PrivateSymbolsAreNotLinked) { 123 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF( 124 <View xmlns:android="http://schemas.android.com/apk/res/android" 125 android:colorAccent="@android:color/hidden" />)EOF"); 126 127 XmlReferenceLinker linker; 128 ASSERT_FALSE(linker.consume(mContext.get(), doc.get())); 129} 130 131TEST_F(XmlReferenceLinkerTest, PrivateSymbolsAreLinkedWhenReferenceHasStarPrefix) { 132 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF( 133 <View xmlns:android="http://schemas.android.com/apk/res/android" 134 android:colorAccent="@*android:color/hidden" />)EOF"); 135 136 XmlReferenceLinker linker; 137 ASSERT_TRUE(linker.consume(mContext.get(), doc.get())); 138} 139 140TEST_F(XmlReferenceLinkerTest, SdkLevelsAreRecorded) { 141 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF( 142 <View xmlns:android="http://schemas.android.com/apk/res/android" 143 android:colorAccent="#ffffff" />)EOF"); 144 145 XmlReferenceLinker linker; 146 ASSERT_TRUE(linker.consume(mContext.get(), doc.get())); 147 EXPECT_TRUE(linker.getSdkLevels().count(21) == 1); 148} 149 150TEST_F(XmlReferenceLinkerTest, LinkMangledAttributes) { 151 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF( 152 <View xmlns:support="http://schemas.android.com/apk/res/com.android.support" 153 support:colorAccent="#ff0000" />)EOF"); 154 155 XmlReferenceLinker linker; 156 ASSERT_TRUE(linker.consume(mContext.get(), doc.get())); 157 158 xml::Element* viewEl = xml::findRootElement(doc.get()); 159 ASSERT_NE(viewEl, nullptr); 160 161 xml::Attribute* xmlAttr = viewEl->findAttribute( 162 u"http://schemas.android.com/apk/res/com.android.support", u"colorAccent"); 163 ASSERT_NE(xmlAttr, nullptr); 164 AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute); 165 AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id); 166 EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010001)); 167 ASSERT_NE(valueCast<BinaryPrimitive>(xmlAttr->compiledValue.get()), nullptr); 168} 169 170TEST_F(XmlReferenceLinkerTest, LinkAutoResReference) { 171 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF( 172 <View xmlns:app="http://schemas.android.com/apk/res-auto" 173 app:colorAccent="@app:color/red" />)EOF"); 174 175 XmlReferenceLinker linker; 176 ASSERT_TRUE(linker.consume(mContext.get(), doc.get())); 177 178 xml::Element* viewEl = xml::findRootElement(doc.get()); 179 ASSERT_NE(viewEl, nullptr); 180 181 xml::Attribute* xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res-auto", 182 u"colorAccent"); 183 ASSERT_NE(xmlAttr, nullptr); 184 AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute); 185 AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id); 186 EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010000)); 187 Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get()); 188 ASSERT_NE(ref, nullptr); 189 AAPT_ASSERT_TRUE(ref->name); 190 AAPT_ASSERT_TRUE(ref->id); 191 EXPECT_EQ(ref->id.value(), ResourceId(0x7f020001)); 192} 193 194TEST_F(XmlReferenceLinkerTest, LinkViewWithShadowedPackageAlias) { 195 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF( 196 <View xmlns:app="http://schemas.android.com/apk/res/android" 197 app:attr="@app:id/id"> 198 <View xmlns:app="http://schemas.android.com/apk/res/com.app.test" 199 app:attr="@app:id/id"/> 200 </View>)EOF"); 201 202 XmlReferenceLinker linker; 203 ASSERT_TRUE(linker.consume(mContext.get(), doc.get())); 204 205 xml::Element* viewEl = xml::findRootElement(doc.get()); 206 ASSERT_NE(viewEl, nullptr); 207 208 // All attributes and references in this element should be referring to "android" (0x01). 209 xml::Attribute* xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/android", 210 u"attr"); 211 ASSERT_NE(xmlAttr, nullptr); 212 AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute); 213 AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id); 214 EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x01010002)); 215 Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get()); 216 ASSERT_NE(ref, nullptr); 217 AAPT_ASSERT_TRUE(ref->id); 218 EXPECT_EQ(ref->id.value(), ResourceId(0x01030000)); 219 220 ASSERT_FALSE(viewEl->getChildElements().empty()); 221 viewEl = viewEl->getChildElements().front(); 222 ASSERT_NE(viewEl, nullptr); 223 224 // All attributes and references in this element should be referring to "com.app.test" (0x7f). 225 xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/com.app.test", u"attr"); 226 ASSERT_NE(xmlAttr, nullptr); 227 AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute); 228 AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id); 229 EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010002)); 230 ref = valueCast<Reference>(xmlAttr->compiledValue.get()); 231 ASSERT_NE(ref, nullptr); 232 AAPT_ASSERT_TRUE(ref->id); 233 EXPECT_EQ(ref->id.value(), ResourceId(0x7f030000)); 234} 235 236TEST_F(XmlReferenceLinkerTest, LinkViewWithLocalPackageAndAliasOfTheSameName) { 237 std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF( 238 <View xmlns:android="http://schemas.android.com/apk/res/com.app.test" 239 android:attr="@id/id"/>)EOF"); 240 241 XmlReferenceLinker linker; 242 ASSERT_TRUE(linker.consume(mContext.get(), doc.get())); 243 244 xml::Element* viewEl = xml::findRootElement(doc.get()); 245 ASSERT_NE(viewEl, nullptr); 246 247 // All attributes and references in this element should be referring to "com.app.test" (0x7f). 248 xml::Attribute* xmlAttr = viewEl->findAttribute( 249 u"http://schemas.android.com/apk/res/com.app.test", u"attr"); 250 ASSERT_NE(xmlAttr, nullptr); 251 AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute); 252 AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id); 253 EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010002)); 254 Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get()); 255 ASSERT_NE(ref, nullptr); 256 AAPT_ASSERT_TRUE(ref->id); 257 EXPECT_EQ(ref->id.value(), ResourceId(0x7f030000)); 258} 259 260} // namespace aapt 261