1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
3 * ----------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Test hierarchy utilities.
22 *//*--------------------------------------------------------------------*/
23
24 #include "tcuTestHierarchyUtil.hpp"
25 #include "tcuStringTemplate.hpp"
26 #include "tcuCommandLine.hpp"
27
28 #include "qpXmlWriter.h"
29
30 #include <fstream>
31
32 namespace tcu
33 {
34
35 using std::string;
36
getNodeTypeName(TestNodeType nodeType)37 static const char *getNodeTypeName(TestNodeType nodeType)
38 {
39 switch (nodeType)
40 {
41 case NODETYPE_SELF_VALIDATE:
42 return "SelfValidate";
43 case NODETYPE_CAPABILITY:
44 return "Capability";
45 case NODETYPE_ACCURACY:
46 return "Accuracy";
47 case NODETYPE_PERFORMANCE:
48 return "Performance";
49 case NODETYPE_GROUP:
50 return "TestGroup";
51 default:
52 DE_ASSERT(false);
53 return DE_NULL;
54 }
55 }
56
57 // Utilities
58
makePackageFilename(const std::string & pattern,const std::string & packageName,const std::string & typeExtension)59 static std::string makePackageFilename(const std::string &pattern, const std::string &packageName,
60 const std::string &typeExtension)
61 {
62 std::map<string, string> args;
63 args["packageName"] = packageName;
64 args["typeExtension"] = typeExtension;
65 return StringTemplate(pattern).specialize(args);
66 }
67
writeXmlCaselist(TestHierarchyIterator & iter,qpXmlWriter * writer)68 static void writeXmlCaselist(TestHierarchyIterator &iter, qpXmlWriter *writer)
69 {
70 DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE &&
71 iter.getNode()->getNodeType() == NODETYPE_PACKAGE);
72
73 {
74 const TestNode *node = iter.getNode();
75 qpXmlAttribute attribs[1];
76 int numAttribs = 0;
77 attribs[numAttribs++] = qpSetStringAttrib("PackageName", node->getName());
78 DE_ASSERT(numAttribs <= DE_LENGTH_OF_ARRAY(attribs));
79
80 if (!qpXmlWriter_startDocument(writer, true) ||
81 !qpXmlWriter_startElement(writer, "TestCaseList", numAttribs, attribs))
82 throw Exception("Failed to start XML document");
83 }
84
85 iter.next();
86
87 while (iter.getNode()->getNodeType() != NODETYPE_PACKAGE)
88 {
89 const TestNode *const node = iter.getNode();
90 const TestNodeType nodeType = node->getNodeType();
91 const bool isEnter = iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE;
92
93 DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE ||
94 iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE);
95 {
96 if (isEnter)
97 {
98 const string caseName = node->getName();
99 qpXmlAttribute attribs[2];
100 int numAttribs = 0;
101
102 attribs[numAttribs++] = qpSetStringAttrib("Name", caseName.c_str());
103 attribs[numAttribs++] = qpSetStringAttrib("CaseType", getNodeTypeName(nodeType));
104 DE_ASSERT(numAttribs <= DE_LENGTH_OF_ARRAY(attribs));
105
106 if (!qpXmlWriter_startElement(writer, "TestCase", numAttribs, attribs))
107 throw Exception("Writing to case list file failed");
108 }
109 else
110 {
111 if (!qpXmlWriter_endElement(writer, "TestCase"))
112 throw tcu::Exception("Writing to case list file failed");
113 }
114 }
115
116 iter.next();
117 }
118
119 // This could be done in catch, but the file is corrupt at that point anyways.
120 if (!qpXmlWriter_endElement(writer, "TestCaseList") || !qpXmlWriter_endDocument(writer))
121 throw Exception("Failed to terminate XML document");
122 }
123
124 /*--------------------------------------------------------------------*//*!
125 * \brief Export the test list of each package into a separate XML file.
126 *//*--------------------------------------------------------------------*/
writeXmlCaselistsToFiles(TestPackageRoot & root,TestContext & testCtx,const CommandLine & cmdLine)127 void writeXmlCaselistsToFiles(TestPackageRoot &root, TestContext &testCtx, const CommandLine &cmdLine)
128 {
129 DefaultHierarchyInflater inflater(testCtx);
130 de::MovePtr<const CaseListFilter> caseListFilter(
131 testCtx.getCommandLine().createCaseListFilter(testCtx.getArchive()));
132
133 TestHierarchyIterator iter(root, inflater, *caseListFilter);
134 const char *const filenamePattern = cmdLine.getCaseListExportFile();
135
136 while (iter.getState() != TestHierarchyIterator::STATE_FINISHED)
137 {
138 const TestNode *node = iter.getNode();
139 const char *pkgName = node->getName();
140 const string filename = makePackageFilename(filenamePattern, pkgName, "xml");
141
142 DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE &&
143 node->getNodeType() == NODETYPE_PACKAGE);
144
145 FILE *file = DE_NULL;
146 qpXmlWriter *writer = DE_NULL;
147
148 try
149 {
150 file = fopen(filename.c_str(), "wb");
151 if (!file)
152 throw Exception("Failed to open " + filename);
153
154 writer = qpXmlWriter_createFileWriter(file, false, false);
155 if (!writer)
156 throw Exception("XML writer creation failed");
157
158 print("Writing test cases from '%s' to file '%s'..\n", pkgName, filename.c_str());
159
160 writeXmlCaselist(iter, writer);
161
162 qpXmlWriter_destroy(writer);
163 writer = DE_NULL;
164
165 fclose(file);
166 file = DE_NULL;
167 }
168 catch (...)
169 {
170 if (writer)
171 qpXmlWriter_destroy(writer);
172 if (file)
173 fclose(file);
174 throw;
175 }
176
177 DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE &&
178 iter.getNode()->getNodeType() == NODETYPE_PACKAGE);
179 iter.next();
180 }
181 }
182
183 /*--------------------------------------------------------------------*//*!
184 * \brief Export the test list of each package into a separate ascii file.
185 *//*--------------------------------------------------------------------*/
writeTxtCaselistsToFiles(TestPackageRoot & root,TestContext & testCtx,const CommandLine & cmdLine)186 void writeTxtCaselistsToFiles(TestPackageRoot &root, TestContext &testCtx, const CommandLine &cmdLine)
187 {
188 DefaultHierarchyInflater inflater(testCtx);
189 de::MovePtr<const CaseListFilter> caseListFilter(
190 testCtx.getCommandLine().createCaseListFilter(testCtx.getArchive()));
191
192 TestHierarchyIterator iter(root, inflater, *caseListFilter);
193 const char *const filenamePattern = cmdLine.getCaseListExportFile();
194
195 while (iter.getState() != TestHierarchyIterator::STATE_FINISHED)
196 {
197 const TestNode *node = iter.getNode();
198 const char *pkgName = node->getName();
199 const string filename = makePackageFilename(filenamePattern, pkgName, "txt");
200
201 DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE &&
202 node->getNodeType() == NODETYPE_PACKAGE);
203
204 std::ofstream out(filename.c_str(), std::ios_base::binary);
205 if (!out.is_open() || !out.good())
206 throw Exception("Failed to open " + filename);
207
208 print("Writing test cases from '%s' to file '%s'..\n", pkgName, filename.c_str());
209
210 try
211 {
212 iter.next();
213 }
214 catch (const tcu::NotSupportedError &)
215 {
216 return;
217 }
218
219 while (iter.getNode()->getNodeType() != NODETYPE_PACKAGE)
220 {
221 if (iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE)
222 out << (isTestNodeTypeExecutable(iter.getNode()->getNodeType()) ? "TEST" : "GROUP") << ": "
223 << iter.getNodePath() << "\n";
224 iter.next();
225 }
226
227 DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE &&
228 iter.getNode()->getNodeType() == NODETYPE_PACKAGE);
229 iter.next();
230 }
231 }
232
233 } // namespace tcu
234