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: return "SelfValidate";
42 case NODETYPE_CAPABILITY: return "Capability";
43 case NODETYPE_ACCURACY: return "Accuracy";
44 case NODETYPE_PERFORMANCE: return "Performance";
45 case NODETYPE_GROUP: return "TestGroup";
46 default:
47 DE_ASSERT(false);
48 return DE_NULL;
49 }
50 }
51
52 // Utilities
53
makePackageFilename(const std::string & pattern,const std::string & packageName,const std::string & typeExtension)54 static std::string makePackageFilename (const std::string& pattern, const std::string& packageName, const std::string& typeExtension)
55 {
56 std::map<string, string> args;
57 args["packageName"] = packageName;
58 args["typeExtension"] = typeExtension;
59 return StringTemplate(pattern).specialize(args);
60 }
61
writeXmlCaselist(TestHierarchyIterator & iter,qpXmlWriter * writer)62 static void writeXmlCaselist (TestHierarchyIterator& iter, qpXmlWriter* writer)
63 {
64 DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE &&
65 iter.getNode()->getNodeType() == NODETYPE_PACKAGE);
66
67 {
68 const TestNode* node = iter.getNode();
69 qpXmlAttribute attribs[2];
70 int numAttribs = 0;
71 attribs[numAttribs++] = qpSetStringAttrib("PackageName", node->getName());
72 attribs[numAttribs++] = qpSetStringAttrib("Description", node->getDescription());
73 DE_ASSERT(numAttribs <= DE_LENGTH_OF_ARRAY(attribs));
74
75 if (!qpXmlWriter_startDocument(writer) ||
76 !qpXmlWriter_startElement(writer, "TestCaseList", numAttribs, attribs))
77 throw Exception("Failed to start XML document");
78 }
79
80 iter.next();
81
82 while (iter.getNode()->getNodeType() != NODETYPE_PACKAGE)
83 {
84 const TestNode* const node = iter.getNode();
85 const TestNodeType nodeType = node->getNodeType();
86 const bool isEnter = iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE;
87
88 DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE ||
89 iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE);
90 {
91 if (isEnter)
92 {
93 const string caseName = node->getName();
94 const string description = node->getDescription();
95 qpXmlAttribute attribs[3];
96 int numAttribs = 0;
97
98 attribs[numAttribs++] = qpSetStringAttrib("Name", caseName.c_str());
99 attribs[numAttribs++] = qpSetStringAttrib("CaseType", getNodeTypeName(nodeType));
100 attribs[numAttribs++] = qpSetStringAttrib("Description", description.c_str());
101 DE_ASSERT(numAttribs <= DE_LENGTH_OF_ARRAY(attribs));
102
103 if (!qpXmlWriter_startElement(writer, "TestCase", numAttribs, attribs))
104 throw Exception("Writing to case list file failed");
105 }
106 else
107 {
108 if (!qpXmlWriter_endElement(writer, "TestCase"))
109 throw tcu::Exception("Writing to case list file failed");
110 }
111 }
112
113 iter.next();
114 }
115
116 // This could be done in catch, but the file is corrupt at that point anyways.
117 if (!qpXmlWriter_endElement(writer, "TestCaseList") ||
118 !qpXmlWriter_endDocument(writer))
119 throw Exception("Failed to terminate XML document");
120 }
121
122 /*--------------------------------------------------------------------*//*!
123 * \brief Export the test list of each package into a separate XML file.
124 *//*--------------------------------------------------------------------*/
writeXmlCaselistsToFiles(TestPackageRoot & root,TestContext & testCtx,const CommandLine & cmdLine)125 void writeXmlCaselistsToFiles (TestPackageRoot& root, TestContext& testCtx, const CommandLine& cmdLine)
126 {
127 DefaultHierarchyInflater inflater (testCtx);
128 de::MovePtr<const CaseListFilter> caseListFilter (testCtx.getCommandLine().createCaseListFilter(testCtx.getArchive()));
129
130 TestHierarchyIterator iter (root, inflater, *caseListFilter);
131 const char* const filenamePattern = cmdLine.getCaseListExportFile();
132
133 while (iter.getState() != TestHierarchyIterator::STATE_FINISHED)
134 {
135 const TestNode* node = iter.getNode();
136 const char* pkgName = node->getName();
137 const string filename = makePackageFilename(filenamePattern, pkgName, "xml");
138
139 DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE &&
140 node->getNodeType() == NODETYPE_PACKAGE);
141
142 FILE* file = DE_NULL;
143 qpXmlWriter* writer = DE_NULL;
144
145 try
146 {
147 file = fopen(filename.c_str(), "wb");
148 if (!file)
149 throw Exception("Failed to open " + filename);
150
151 writer = qpXmlWriter_createFileWriter(file, DE_FALSE, DE_FALSE);
152 if (!writer)
153 throw Exception("XML writer creation failed");
154
155 print("Writing test cases from '%s' to file '%s'..\n", pkgName, filename.c_str());
156
157 writeXmlCaselist(iter, writer);
158
159 qpXmlWriter_destroy(writer);
160 writer = DE_NULL;
161
162 fclose(file);
163 file = DE_NULL;
164 }
165 catch (...)
166 {
167 if (writer)
168 qpXmlWriter_destroy(writer);
169 if (file)
170 fclose(file);
171 throw;
172 }
173
174 DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE &&
175 iter.getNode()->getNodeType() == NODETYPE_PACKAGE);
176 iter.next();
177 }
178 }
179
180 /*--------------------------------------------------------------------*//*!
181 * \brief Export the test list of each package into a separate ascii file.
182 *//*--------------------------------------------------------------------*/
writeTxtCaselistsToFiles(TestPackageRoot & root,TestContext & testCtx,const CommandLine & cmdLine)183 void writeTxtCaselistsToFiles (TestPackageRoot& root, TestContext& testCtx, const CommandLine& cmdLine)
184 {
185 DefaultHierarchyInflater inflater (testCtx);
186 de::MovePtr<const CaseListFilter> caseListFilter (testCtx.getCommandLine().createCaseListFilter(testCtx.getArchive()));
187
188 TestHierarchyIterator iter (root, inflater, *caseListFilter);
189 const char* const filenamePattern = cmdLine.getCaseListExportFile();
190
191 while (iter.getState() != TestHierarchyIterator::STATE_FINISHED)
192 {
193 const TestNode* node = iter.getNode();
194 const char* pkgName = node->getName();
195 const string filename = makePackageFilename(filenamePattern, pkgName, "txt");
196
197 DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE &&
198 node->getNodeType() == NODETYPE_PACKAGE);
199
200 std::ofstream out(filename.c_str(), std::ios_base::binary);
201 if (!out.is_open() || !out.good())
202 throw Exception("Failed to open " + filename);
203
204 print("Writing test cases from '%s' to file '%s'..\n", pkgName, filename.c_str());
205
206 try
207 {
208 iter.next();
209 }
210 catch (const tcu::NotSupportedError&)
211 {
212 return;
213 }
214
215 while (iter.getNode()->getNodeType() != NODETYPE_PACKAGE)
216 {
217 if (iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE)
218 out << (isTestNodeTypeExecutable(iter.getNode()->getNodeType()) ? "TEST" : "GROUP") << ": " << iter.getNodePath() << "\n";
219 iter.next();
220 }
221
222 DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE &&
223 iter.getNode()->getNodeType() == NODETYPE_PACKAGE);
224 iter.next();
225 }
226 }
227
228 } // tcu
229