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