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     buffer.resize(strlen(buffer.c_str()));
74     return buffer;
75 }
76 
substitute(const char * fmt,const std::string & s)77 std::string substitute(const char* fmt, const std::string& s) {
78     return substitute(fmt, s.c_str());
79 }
80 
81 }  // namespace
82 
TEST(ValidateXml,InvalidXml)83 TEST(ValidateXml, InvalidXml) {
84     TemporaryFile xml;
85     ASSERT_TRUE(android::base::WriteStringToFile(INVALID_XML_SOURCE, xml.path)) << strerror(errno);
86     TemporaryFile xsd;
87     ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
88     EXPECT_FALSE(validateXml("xml", "xsd", xml.path, xsd.path));
89 }
90 
TEST(ValidateXml,ValidXml)91 TEST(ValidateXml, ValidXml) {
92     TemporaryFile xml;
93     ASSERT_TRUE(
94             android::base::WriteStringToFile(substitute(VALID_XML_SOURCE, MODULE_SOURCE), xml.path))
95             << strerror(errno);
96     TemporaryFile xsd;
97     ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
98     EXPECT_TRUE(validateXml("xml", "xsd", xml.path, xsd.path));
99 }
100 
TEST(ValidateXml,IncludeAbsolutePath)101 TEST(ValidateXml, IncludeAbsolutePath) {
102     TemporaryFile xmlInclude;
103     ASSERT_TRUE(android::base::WriteStringToFile(substitute(XML_INCLUDED_SOURCE, MODULE_SOURCE),
104                                                  xmlInclude.path))
105             << strerror(errno);
106     TemporaryFile xml;
107     ASSERT_TRUE(android::base::WriteStringToFile(
108             substitute(VALID_XML_SOURCE, substitute(XI_INCLUDE, xmlInclude.path)), xml.path))
109             << strerror(errno);
110     TemporaryFile xsd;
111     ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
112     EXPECT_TRUE(validateXml("xml", "xsd", xml.path, xsd.path));
113 }
114 
TEST(ValidateXml,IncludeSameDirRelativePath)115 TEST(ValidateXml, IncludeSameDirRelativePath) {
116     TemporaryFile xmlInclude;
117     ASSERT_TRUE(android::base::WriteStringToFile(substitute(XML_INCLUDED_SOURCE, MODULE_SOURCE),
118                                                  xmlInclude.path))
119             << strerror(errno);
120     TemporaryFile xml;
121     ASSERT_EQ(android::base::Dirname(xml.path), android::base::Dirname(xmlInclude.path));
122     ASSERT_TRUE(android::base::WriteStringToFile(
123             substitute(VALID_XML_SOURCE,
124                        substitute(XI_INCLUDE, android::base::Basename(xmlInclude.path))),
125             xml.path))
126             << strerror(errno);
127     TemporaryFile xsd;
128     ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
129     EXPECT_TRUE(validateXml("xml", "xsd", xml.path, xsd.path));
130 }
131 
TEST(ValidateXml,IncludeSubdirRelativePath)132 TEST(ValidateXml, IncludeSubdirRelativePath) {
133     TemporaryDir xmlIncludeDir;
134     TemporaryFile xmlInclude(xmlIncludeDir.path);
135     ASSERT_TRUE(android::base::WriteStringToFile(substitute(XML_INCLUDED_SOURCE, MODULE_SOURCE),
136                                                  xmlInclude.path))
137             << strerror(errno);
138     TemporaryFile xml;
139     ASSERT_EQ(android::base::Dirname(xml.path), android::base::Dirname(xmlIncludeDir.path));
140     ASSERT_TRUE(android::base::WriteStringToFile(
141             substitute(VALID_XML_SOURCE,
142                        substitute(XI_INCLUDE, android::base::Basename(xmlIncludeDir.path) + "/" +
143                                                       android::base::Basename(xmlInclude.path))),
144             xml.path))
145             << strerror(errno);
146     TemporaryFile xsd;
147     ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
148     EXPECT_TRUE(validateXml("xml", "xsd", xml.path, xsd.path));
149 }
150 
TEST(ValidateXml,IncludeParentDirRelativePath)151 TEST(ValidateXml, IncludeParentDirRelativePath) {
152     // An XML file from a subdirectory includes a file from the parent directory using '..' syntax.
153     TemporaryFile xmlInclude;
154     ASSERT_TRUE(android::base::WriteStringToFile(substitute(XML_INCLUDED_SOURCE, MODULE_SOURCE),
155                                                  xmlInclude.path))
156             << strerror(errno);
157     TemporaryDir xmlIncludeDir;
158     TemporaryFile xmlParentInclude(xmlIncludeDir.path);
159     ASSERT_TRUE(android::base::WriteStringToFile(
160             substitute(XML_INCLUDED_SOURCE,
161                        substitute(XI_INCLUDE, "../" + android::base::Basename(xmlInclude.path))),
162             xmlParentInclude.path))
163             << strerror(errno);
164     TemporaryFile xml;
165     ASSERT_EQ(android::base::Dirname(xml.path), android::base::Dirname(xmlInclude.path));
166     ASSERT_EQ(android::base::Dirname(xml.path), android::base::Dirname(xmlIncludeDir.path));
167     ASSERT_TRUE(android::base::WriteStringToFile(
168             substitute(
169                     VALID_XML_SOURCE,
170                     substitute(XI_INCLUDE, android::base::Basename(xmlIncludeDir.path) + "/" +
171                                                    android::base::Basename(xmlParentInclude.path))),
172             xml.path))
173             << strerror(errno);
174     TemporaryFile xsd;
175     ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
176     EXPECT_TRUE(validateXml("xml", "xsd", xml.path, xsd.path));
177 }
178