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[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 *//*--------------------------------------------------------------------*/ 125void 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 *//*--------------------------------------------------------------------*/ 183void 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 iter.next(); 207 208 while (iter.getNode()->getNodeType() != NODETYPE_PACKAGE) 209 { 210 if (iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE) 211 out << (isTestNodeTypeExecutable(iter.getNode()->getNodeType()) ? "TEST" : "GROUP") << ": " << iter.getNodePath() << "\n"; 212 iter.next(); 213 } 214 215 DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE && 216 iter.getNode()->getNodeType() == NODETYPE_PACKAGE); 217 iter.next(); 218 } 219} 220 221} // tcu 222