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
21namespace aapt {
22
23TEST(InlineXmlFormatParserTest, PassThrough) {
24  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
25  std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"EOF(
26      <View xmlns:android="http://schemas.android.com/apk/res/android">
27        <View android:text="hey">
28          <View android:id="hi" />
29        </View>
30      </View>)EOF");
31
32  InlineXmlFormatParser parser;
33  ASSERT_TRUE(parser.Consume(context.get(), doc.get()));
34  EXPECT_EQ(0u, parser.GetExtractedInlineXmlDocuments().size());
35}
36
37TEST(InlineXmlFormatParserTest, ExtractOneXmlResource) {
38  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
39  std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"EOF(
40      <View1 xmlns:android="http://schemas.android.com/apk/res/android"
41            xmlns:aapt="http://schemas.android.com/aapt">
42        <aapt:attr name="android:text">
43          <View2 android:text="hey">
44            <View3 android:id="hi" />
45          </View2>
46        </aapt:attr>
47      </View1>)EOF");
48
49  doc->file.name = test::ParseNameOrDie("layout/main");
50
51  InlineXmlFormatParser parser;
52  ASSERT_TRUE(parser.Consume(context.get(), doc.get()));
53
54  // One XML resource should have been extracted.
55  EXPECT_EQ(1u, parser.GetExtractedInlineXmlDocuments().size());
56
57  xml::Element* el = xml::FindRootElement(doc.get());
58  ASSERT_NE(nullptr, el);
59
60  EXPECT_EQ("View1", el->name);
61
62  // The <aapt:attr> tag should be extracted.
63  EXPECT_EQ(nullptr, el->FindChild(xml::kSchemaAapt, "attr"));
64
65  // The 'android:text' attribute should be set with a reference.
66  xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "text");
67  ASSERT_NE(nullptr, attr);
68
69  ResourceNameRef name_ref;
70  ASSERT_TRUE(ResourceUtils::ParseReference(attr->value, &name_ref));
71
72  xml::XmlResource* extracted_doc =
73      parser.GetExtractedInlineXmlDocuments()[0].get();
74  ASSERT_NE(nullptr, extracted_doc);
75
76  // Make sure the generated reference is correct.
77  EXPECT_EQ(name_ref.package, extracted_doc->file.name.package);
78  EXPECT_EQ(name_ref.type, extracted_doc->file.name.type);
79  EXPECT_EQ(name_ref.entry, extracted_doc->file.name.entry);
80
81  // Verify the structure of the extracted XML.
82  el = xml::FindRootElement(extracted_doc);
83  ASSERT_NE(nullptr, el);
84  EXPECT_EQ("View2", el->name);
85  EXPECT_NE(nullptr, el->FindChild({}, "View3"));
86}
87
88TEST(InlineXmlFormatParserTest, ExtractTwoXmlResources) {
89  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
90  std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"EOF(
91      <View1 xmlns:android="http://schemas.android.com/apk/res/android"
92            xmlns:aapt="http://schemas.android.com/aapt">
93        <aapt:attr name="android:text">
94          <View2 android:text="hey">
95            <View3 android:id="hi" />
96          </View2>
97        </aapt:attr>
98
99        <aapt:attr name="android:drawable">
100          <vector />
101        </aapt:attr>
102      </View1>)EOF");
103
104  doc->file.name = test::ParseNameOrDie("layout/main");
105
106  InlineXmlFormatParser parser;
107  ASSERT_TRUE(parser.Consume(context.get(), doc.get()));
108  ASSERT_EQ(2u, parser.GetExtractedInlineXmlDocuments().size());
109
110  xml::Element* el = xml::FindRootElement(doc.get());
111  ASSERT_NE(nullptr, el);
112
113  EXPECT_EQ("View1", el->name);
114
115  xml::Attribute* attr_text = el->FindAttribute(xml::kSchemaAndroid, "text");
116  ASSERT_NE(nullptr, attr_text);
117
118  xml::Attribute* attr_drawable =
119      el->FindAttribute(xml::kSchemaAndroid, "drawable");
120  ASSERT_NE(nullptr, attr_drawable);
121
122  // The two extracted resources should have different names.
123  EXPECT_NE(attr_text->value, attr_drawable->value);
124
125  // The child <aapt:attr> elements should be gone.
126  EXPECT_EQ(nullptr, el->FindChild(xml::kSchemaAapt, "attr"));
127
128  xml::XmlResource* extracted_doc_text =
129      parser.GetExtractedInlineXmlDocuments()[0].get();
130  ASSERT_NE(nullptr, extracted_doc_text);
131  el = xml::FindRootElement(extracted_doc_text);
132  ASSERT_NE(nullptr, el);
133  EXPECT_EQ("View2", el->name);
134
135  xml::XmlResource* extracted_doc_drawable =
136      parser.GetExtractedInlineXmlDocuments()[1].get();
137  ASSERT_NE(nullptr, extracted_doc_drawable);
138  el = xml::FindRootElement(extracted_doc_drawable);
139  ASSERT_NE(nullptr, el);
140  EXPECT_EQ("vector", el->name);
141}
142
143}  // namespace aapt
144