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 32namespace tcu 33{ 34 35using std::string; 36 37static 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 54static 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 62static 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 *//*--------------------------------------------------------------------*/ 122void 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 *//*--------------------------------------------------------------------*/ 180void 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