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