1 /*
2  * Copyright (C) 2021 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 <android-base/file.h>
18 #include <gtest/gtest.h>
19 
20 #include <ValidateXml.h>
21 
22 using ::android::hardware::audio::common::test::utility::validateXml;
23 
24 const char* XSD_SOURCE =
25         "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
26         "<xs:schema version=\"2.0\""
27         "           elementFormDefault=\"qualified\""
28         "           attributeFormDefault=\"unqualified\""
29         "           xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
30         "  <xs:element name=\"audioPolicyConfiguration\">"
31         "    <xs:complexType>"
32         "      <xs:sequence>"
33         "        <xs:element name=\"modules\">"
34         "          <xs:complexType>"
35         "            <xs:sequence>"
36         "              <xs:element name=\"module\" maxOccurs=\"unbounded\">"
37         "                <xs:complexType>"
38         "                  <xs:attribute name=\"name\" type=\"xs:string\" use=\"required\"/>"
39         "                </xs:complexType>"
40         "              </xs:element>"
41         "            </xs:sequence>"
42         "          </xs:complexType>"
43         "        </xs:element>"
44         "      </xs:sequence>"
45         "    </xs:complexType>"
46         "  </xs:element>"
47         "</xs:schema>";
48 
49 const char* INVALID_XML_SOURCE =
50         "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
51         "<audioPolicyKonfiguration />";
52 
53 const char* VALID_XML_SOURCE =
54         "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
55         "<audioPolicyConfiguration>"
56         "  <modules>"
57         "    <module name=\"aaa\" />"
58         "    %s"
59         "  </modules>"
60         "</audioPolicyConfiguration>";
61 
62 const char* MODULE_SOURCE = "<module name=\"bbb\" />";
63 
64 const char* XI_INCLUDE = "<xi:include xmlns:xi=\"http://www.w3.org/2001/XInclude\" href=\"%s\" />";
65 
66 const char* XML_INCLUDED_SOURCE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>%s";
67 
68 namespace {
69 
substitute(const char * fmt,const char * param)70 std::string substitute(const char* fmt, const char* param) {
71     std::string buffer(static_cast<size_t>(strlen(fmt) + strlen(param)), '\0');
72     snprintf(buffer.data(), buffer.size(), fmt, param);
73     return buffer;
74 }
75 
substitute(const char * fmt,const std::string & s)76 std::string substitute(const char* fmt, const std::string& s) {
77     return substitute(fmt, s.c_str());
78 }
79 
80 }  // namespace
81 
TEST(ValidateXml,InvalidXml)82 TEST(ValidateXml, InvalidXml) {
83     TemporaryFile xml;
84     ASSERT_TRUE(android::base::WriteStringToFile(INVALID_XML_SOURCE, xml.path)) << strerror(errno);
85     TemporaryFile xsd;
86     ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
87     EXPECT_FALSE(validateXml("xml", "xsd", xml.path, xsd.path));
88 }
89 
TEST(ValidateXml,ValidXml)90 TEST(ValidateXml, ValidXml) {
91     TemporaryFile xml;
92     ASSERT_TRUE(
93             android::base::WriteStringToFile(substitute(VALID_XML_SOURCE, MODULE_SOURCE), xml.path))
94             << strerror(errno);
95     TemporaryFile xsd;
96     ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
97     EXPECT_TRUE(validateXml("xml", "xsd", xml.path, xsd.path));
98 }
99 
TEST(ValidateXml,IncludeAbsolutePath)100 TEST(ValidateXml, IncludeAbsolutePath) {
101     TemporaryFile xmlInclude;
102     ASSERT_TRUE(android::base::WriteStringToFile(substitute(XML_INCLUDED_SOURCE, MODULE_SOURCE),
103                                                  xmlInclude.path))
104             << strerror(errno);
105     TemporaryFile xml;
106     ASSERT_TRUE(android::base::WriteStringToFile(
107             substitute(VALID_XML_SOURCE, substitute(XI_INCLUDE, xmlInclude.path)), xml.path))
108             << strerror(errno);
109     TemporaryFile xsd;
110     ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
111     EXPECT_TRUE(validateXml("xml", "xsd", xml.path, xsd.path));
112 }
113 
TEST(ValidateXml,IncludeSameDirRelativePath)114 TEST(ValidateXml, IncludeSameDirRelativePath) {
115     TemporaryFile xmlInclude;
116     ASSERT_TRUE(android::base::WriteStringToFile(substitute(XML_INCLUDED_SOURCE, MODULE_SOURCE),
117                                                  xmlInclude.path))
118             << strerror(errno);
119     TemporaryFile xml;
120     ASSERT_EQ(android::base::Dirname(xml.path), android::base::Dirname(xmlInclude.path));
121     ASSERT_TRUE(android::base::WriteStringToFile(
122             substitute(VALID_XML_SOURCE,
123                        substitute(XI_INCLUDE, android::base::Basename(xmlInclude.path))),
124             xml.path))
125             << strerror(errno);
126     TemporaryFile xsd;
127     ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
128     EXPECT_TRUE(validateXml("xml", "xsd", xml.path, xsd.path));
129 }
130 
TEST(ValidateXml,IncludeSubdirRelativePath)131 TEST(ValidateXml, IncludeSubdirRelativePath) {
132     TemporaryDir xmlIncludeDir;
133     TemporaryFile xmlInclude(xmlIncludeDir.path);
134     ASSERT_TRUE(android::base::WriteStringToFile(substitute(XML_INCLUDED_SOURCE, MODULE_SOURCE),
135                                                  xmlInclude.path))
136             << strerror(errno);
137     TemporaryFile xml;
138     ASSERT_EQ(android::base::Dirname(xml.path), android::base::Dirname(xmlIncludeDir.path));
139     ASSERT_TRUE(android::base::WriteStringToFile(
140             substitute(VALID_XML_SOURCE,
141                        substitute(XI_INCLUDE, android::base::Basename(xmlIncludeDir.path) + "/" +
142                                                       android::base::Basename(xmlInclude.path))),
143             xml.path))
144             << strerror(errno);
145     TemporaryFile xsd;
146     ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
147     EXPECT_TRUE(validateXml("xml", "xsd", xml.path, xsd.path));
148 }
149 
TEST(ValidateXml,IncludeParentDirRelativePath)150 TEST(ValidateXml, IncludeParentDirRelativePath) {
151     // An XML file from a subdirectory includes a file from the parent directory using '..' syntax.
152     TemporaryFile xmlInclude;
153     ASSERT_TRUE(android::base::WriteStringToFile(substitute(XML_INCLUDED_SOURCE, MODULE_SOURCE),
154                                                  xmlInclude.path))
155             << strerror(errno);
156     TemporaryDir xmlIncludeDir;
157     TemporaryFile xmlParentInclude(xmlIncludeDir.path);
158     ASSERT_TRUE(android::base::WriteStringToFile(
159             substitute(XML_INCLUDED_SOURCE,
160                        substitute(XI_INCLUDE, "../" + android::base::Basename(xmlInclude.path))),
161             xmlParentInclude.path))
162             << strerror(errno);
163     TemporaryFile xml;
164     ASSERT_EQ(android::base::Dirname(xml.path), android::base::Dirname(xmlInclude.path));
165     ASSERT_EQ(android::base::Dirname(xml.path), android::base::Dirname(xmlIncludeDir.path));
166     ASSERT_TRUE(android::base::WriteStringToFile(
167             substitute(
168                     VALID_XML_SOURCE,
169                     substitute(XI_INCLUDE, android::base::Basename(xmlIncludeDir.path) + "/" +
170                                                    android::base::Basename(xmlParentInclude.path))),
171             xml.path))
172             << strerror(errno);
173     TemporaryFile xsd;
174     ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
175     EXPECT_TRUE(validateXml("xml", "xsd", xml.path, xsd.path));
176 }
177