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 "SourceXmlPullParser.h"
18 #include "BindingXmlPullParser.h"
19 
20 #include <gtest/gtest.h>
21 #include <sstream>
22 #include <string>
23 
24 namespace aapt {
25 
26 constexpr const char16_t* kAndroidNamespaceUri = u"http://schemas.android.com/apk/res/android";
27 
TEST(BindingXmlPullParserTest,SubstituteBindingExpressionsWithTag)28 TEST(BindingXmlPullParserTest, SubstituteBindingExpressionsWithTag) {
29     std::stringstream input;
30     input << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
31           << "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
32           << "              xmlns:bind=\"http://schemas.android.com/apk/binding\"\n"
33           << "              android:id=\"@+id/content\">\n"
34           << "  <variable name=\"user\" type=\"com.android.test.User\"/>\n"
35           << "  <TextView android:text=\"@{user.name}\" android:layout_width=\"wrap_content\"\n"
36           << "            android:layout_height=\"wrap_content\"/>\n"
37           << "</LinearLayout>\n";
38     std::shared_ptr<XmlPullParser> sourceParser = std::make_shared<SourceXmlPullParser>(input);
39     BindingXmlPullParser parser(sourceParser);
40 
41     ASSERT_EQ(XmlPullParser::Event::kStartNamespace, parser.next());
42     EXPECT_EQ(std::u16string(u"http://schemas.android.com/apk/res/android"),
43               parser.getNamespaceUri());
44 
45     ASSERT_EQ(XmlPullParser::Event::kStartElement, parser.next());
46     EXPECT_EQ(std::u16string(u"LinearLayout"), parser.getElementName());
47 
48     while (parser.next() == XmlPullParser::Event::kText) {}
49 
50     ASSERT_EQ(XmlPullParser::Event::kStartElement, parser.getEvent());
51     EXPECT_EQ(std::u16string(u"TextView"), parser.getElementName());
52 
53     ASSERT_EQ(3u, parser.getAttributeCount());
54     const auto endAttr = parser.endAttributes();
55     EXPECT_NE(endAttr, parser.findAttribute(kAndroidNamespaceUri, u"layout_width"));
56     EXPECT_NE(endAttr, parser.findAttribute(kAndroidNamespaceUri, u"layout_height"));
57     EXPECT_NE(endAttr, parser.findAttribute(kAndroidNamespaceUri, u"tag"));
58 
59     while (parser.next() == XmlPullParser::Event::kText) {}
60 
61     ASSERT_EQ(XmlPullParser::Event::kEndElement, parser.getEvent());
62 
63     while (parser.next() == XmlPullParser::Event::kText) {}
64 
65     ASSERT_EQ(XmlPullParser::Event::kEndElement, parser.getEvent());
66     ASSERT_EQ(XmlPullParser::Event::kEndNamespace, parser.next());
67 }
68 
TEST(BindingXmlPullParserTest,GenerateVariableDeclarations)69 TEST(BindingXmlPullParserTest, GenerateVariableDeclarations) {
70     std::stringstream input;
71     input << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
72           << "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
73           << "              xmlns:bind=\"http://schemas.android.com/apk/binding\"\n"
74           << "              android:id=\"@+id/content\">\n"
75           << "  <variable name=\"user\" type=\"com.android.test.User\"/>\n"
76           << "</LinearLayout>\n";
77     std::shared_ptr<XmlPullParser> sourceParser = std::make_shared<SourceXmlPullParser>(input);
78     BindingXmlPullParser parser(sourceParser);
79 
80     while (XmlPullParser::isGoodEvent(parser.next())) {
81         ASSERT_NE(XmlPullParser::Event::kBadDocument, parser.getEvent());
82     }
83 
84     std::stringstream output;
85     ASSERT_TRUE(parser.writeToFile(output));
86 
87     std::string result = output.str();
88     EXPECT_NE(std::string::npos,
89               result.find("<entries name=\"user\" type=\"com.android.test.User\"/>"));
90 }
91 
TEST(BindingXmlPullParserTest,FailOnMissingNameOrTypeInVariableDeclaration)92 TEST(BindingXmlPullParserTest, FailOnMissingNameOrTypeInVariableDeclaration) {
93     std::stringstream input;
94     input << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
95           << "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
96           << "              xmlns:bind=\"http://schemas.android.com/apk/binding\"\n"
97           << "              android:id=\"@+id/content\">\n"
98           << "  <variable name=\"user\"/>\n"
99           << "</LinearLayout>\n";
100     std::shared_ptr<XmlPullParser> sourceParser = std::make_shared<SourceXmlPullParser>(input);
101     BindingXmlPullParser parser(sourceParser);
102 
103     while (XmlPullParser::isGoodEvent(parser.next())) {}
104 
105     EXPECT_EQ(XmlPullParser::Event::kBadDocument, parser.getEvent());
106     EXPECT_FALSE(parser.getLastError().empty());
107 }
108 
109 
110 } // namespace aapt
111