1 /* 2 * Copyright (C) 2016 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 "compile/InlineXmlFormatParser.h" 18 19 #include "test/Test.h" 20 21 using ::testing::Eq; 22 using ::testing::IsNull; 23 using ::testing::Not; 24 using ::testing::NotNull; 25 using ::testing::SizeIs; 26 using ::testing::StrEq; 27 28 namespace aapt { 29 30 TEST(InlineXmlFormatParserTest, PassThrough) { 31 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 32 std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"( 33 <View xmlns:android="http://schemas.android.com/apk/res/android"> 34 <View android:text="hey"> 35 <View android:id="hi" /> 36 </View> 37 </View>)"); 38 39 InlineXmlFormatParser parser; 40 ASSERT_TRUE(parser.Consume(context.get(), doc.get())); 41 EXPECT_THAT(parser.GetExtractedInlineXmlDocuments(), SizeIs(0u)); 42 } 43 44 TEST(InlineXmlFormatParserTest, ExtractOneXmlResource) { 45 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 46 std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"( 47 <View1 xmlns:android="http://schemas.android.com/apk/res/android" 48 xmlns:aapt="http://schemas.android.com/aapt"> 49 <aapt:attr name="android:text"> 50 <View2 android:text="hey"> 51 <View3 android:id="hi" /> 52 </View2> 53 </aapt:attr> 54 </View1>)"); 55 56 doc->file.name = test::ParseNameOrDie("layout/main"); 57 58 InlineXmlFormatParser parser; 59 ASSERT_TRUE(parser.Consume(context.get(), doc.get())); 60 61 // One XML resource should have been extracted. 62 EXPECT_THAT(parser.GetExtractedInlineXmlDocuments(), SizeIs(1u)); 63 64 xml::Element* el = doc->root.get(); 65 ASSERT_THAT(el, NotNull()); 66 EXPECT_THAT(el->name, StrEq("View1")); 67 68 // The <aapt:attr> tag should be extracted. 69 EXPECT_THAT(el->FindChild(xml::kSchemaAapt, "attr"), IsNull()); 70 71 // The 'android:text' attribute should be set with a reference. 72 xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "text"); 73 ASSERT_THAT(attr, NotNull()); 74 75 ResourceNameRef name_ref; 76 ASSERT_TRUE(ResourceUtils::ParseReference(attr->value, &name_ref)); 77 78 xml::XmlResource* extracted_doc = parser.GetExtractedInlineXmlDocuments()[0].get(); 79 ASSERT_THAT(extracted_doc, NotNull()); 80 81 // Make sure the generated reference is correct. 82 EXPECT_THAT(extracted_doc->file.name, Eq(name_ref)); 83 84 // Verify the structure of the extracted XML. 85 el = extracted_doc->root.get(); 86 ASSERT_THAT(el, NotNull()); 87 EXPECT_THAT(el->name, StrEq("View2")); 88 EXPECT_THAT(el->FindChild({}, "View3"), NotNull()); 89 } 90 91 TEST(InlineXmlFormatParserTest, ExtractTwoXmlResources) { 92 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 93 std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"( 94 <View1 xmlns:android="http://schemas.android.com/apk/res/android" 95 xmlns:aapt="http://schemas.android.com/aapt"> 96 <aapt:attr name="android:text"> 97 <View2 android:text="hey"> 98 <View3 android:id="hi" /> 99 </View2> 100 </aapt:attr> 101 102 <aapt:attr name="android:drawable"> 103 <vector /> 104 </aapt:attr> 105 </View1>)"); 106 107 doc->file.name = test::ParseNameOrDie("layout/main"); 108 109 InlineXmlFormatParser parser; 110 ASSERT_TRUE(parser.Consume(context.get(), doc.get())); 111 ASSERT_THAT(parser.GetExtractedInlineXmlDocuments(), SizeIs(2u)); 112 113 xml::Element* el = doc->root.get(); 114 ASSERT_THAT(el, NotNull()); 115 EXPECT_THAT(el->name, StrEq("View1")); 116 117 xml::Attribute* attr_text = el->FindAttribute(xml::kSchemaAndroid, "text"); 118 ASSERT_THAT(attr_text, NotNull()); 119 120 xml::Attribute* attr_drawable = el->FindAttribute(xml::kSchemaAndroid, "drawable"); 121 ASSERT_THAT(attr_drawable, NotNull()); 122 123 // The two extracted resources should have different names. 124 EXPECT_THAT(attr_text->value, Not(Eq(attr_drawable->value))); 125 126 // The child <aapt:attr> elements should be gone. 127 EXPECT_THAT(el->FindChild(xml::kSchemaAapt, "attr"), IsNull()); 128 129 xml::XmlResource* extracted_doc_text = parser.GetExtractedInlineXmlDocuments()[0].get(); 130 ASSERT_THAT(extracted_doc_text, NotNull()); 131 ASSERT_THAT(extracted_doc_text->root, NotNull()); 132 EXPECT_THAT(extracted_doc_text->root->name, StrEq("View2")); 133 134 xml::XmlResource* extracted_doc_drawable = parser.GetExtractedInlineXmlDocuments()[1].get(); 135 ASSERT_THAT(extracted_doc_drawable, NotNull()); 136 ASSERT_THAT(extracted_doc_drawable->root, NotNull()); 137 EXPECT_THAT(extracted_doc_drawable->root->name, StrEq("vector")); 138 } 139 140 TEST(InlineXmlFormatParserTest, ExtractNestedXmlResources) { 141 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 142 std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"( 143 <base_root xmlns:android="http://schemas.android.com/apk/res/android" 144 xmlns:aapt="http://schemas.android.com/aapt"> 145 <aapt:attr name="inline_xml"> 146 <inline_root> 147 <aapt:attr name="nested_inline_xml"> 148 <nested_inline_root/> 149 </aapt:attr> 150 <aapt:attr name="another_nested_inline_xml"> 151 <root/> 152 </aapt:attr> 153 </inline_root> 154 </aapt:attr> 155 <aapt:attr name="turtles"> 156 <root1> 157 <aapt:attr name="all"> 158 <root2> 159 <aapt:attr name="the"> 160 <root3> 161 <aapt:attr name="way"> 162 <root4> 163 <aapt:attr name="down"> 164 <root5/> 165 </aapt:attr> 166 </root4> 167 </aapt:attr> 168 </root3> 169 </aapt:attr> 170 </root2> 171 </aapt:attr> 172 </root1> 173 </aapt:attr> 174 </base_root>)"); 175 176 doc->file.name = test::ParseNameOrDie("layout/main"); 177 178 InlineXmlFormatParser parser; 179 ASSERT_TRUE(parser.Consume(context.get(), doc.get())); 180 // Confirm that all of the nested inline xmls are parsed out. 181 ASSERT_THAT(parser.GetExtractedInlineXmlDocuments(), SizeIs(8u)); 182 } 183 } // namespace aapt 184