1/*------------------------------------------------------------------------- 2 * drawElements Quality Program Test Executor 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 Extract values by name from logs. 22 *//*--------------------------------------------------------------------*/ 23 24#include "xeTestLogParser.hpp" 25#include "xeTestResultParser.hpp" 26#include "deFilePath.hpp" 27#include "deString.h" 28 29#include <vector> 30#include <string> 31#include <cstdio> 32#include <cstdlib> 33#include <fstream> 34#include <iostream> 35#include <stdexcept> 36 37using std::vector; 38using std::string; 39using std::set; 40using std::map; 41 42struct CommandLine 43{ 44 CommandLine (void) 45 : statusCode(false) 46 { 47 } 48 49 string filename; 50 vector<string> tagNames; 51 bool statusCode; 52}; 53 54typedef xe::ri::NumericValue Value; 55 56struct CaseValues 57{ 58 string casePath; 59 xe::TestCaseType caseType; 60 xe::TestStatusCode statusCode; 61 string statusDetails; 62 63 vector<Value> values; 64}; 65 66class BatchResultValues 67{ 68public: 69 BatchResultValues (const vector<string>& tagNames) 70 : m_tagNames(tagNames) 71 { 72 } 73 74 ~BatchResultValues (void) 75 { 76 for (vector<CaseValues*>::iterator i = m_caseValues.begin(); i != m_caseValues.end(); ++i) 77 delete *i; 78 } 79 80 void add (const CaseValues& result) 81 { 82 CaseValues* copy = new CaseValues(result); 83 try 84 { 85 m_caseValues.push_back(copy); 86 } 87 catch (...) 88 { 89 delete copy; 90 throw; 91 } 92 } 93 94 const vector<string>& getTagNames (void) const { return m_tagNames; } 95 96 size_t size (void) const { return m_caseValues.size(); } 97 const CaseValues& operator[] (size_t ndx) const { return *m_caseValues[ndx]; } 98 99private: 100 vector<string> m_tagNames; 101 vector<CaseValues*> m_caseValues; 102}; 103 104static Value findValueByTag (const xe::ri::List& items, const string& tagName) 105{ 106 for (int ndx = 0; ndx < items.getNumItems(); ndx++) 107 { 108 const xe::ri::Item& item = items.getItem(ndx); 109 110 if (item.getType() == xe::ri::TYPE_SECTION) 111 { 112 const Value value = findValueByTag(static_cast<const xe::ri::Section&>(item).items, tagName); 113 if (value.getType() != Value::TYPE_EMPTY) 114 return value; 115 } 116 else if (item.getType() == xe::ri::TYPE_NUMBER) 117 { 118 const xe::ri::Number& value = static_cast<const xe::ri::Number&>(item); 119 return value.value; 120 } 121 } 122 123 return Value(); 124} 125 126class TagParser : public xe::TestLogHandler 127{ 128public: 129 TagParser (BatchResultValues& result) 130 : m_result(result) 131 { 132 } 133 134 void setSessionInfo (const xe::SessionInfo&) 135 { 136 // Ignored. 137 } 138 139 xe::TestCaseResultPtr startTestCaseResult (const char* casePath) 140 { 141 return xe::TestCaseResultPtr(new xe::TestCaseResultData(casePath)); 142 } 143 144 void testCaseResultUpdated (const xe::TestCaseResultPtr&) 145 { 146 // Ignored. 147 } 148 149 void testCaseResultComplete (const xe::TestCaseResultPtr& caseData) 150 { 151 const vector<string>& tagNames = m_result.getTagNames(); 152 CaseValues tagResult; 153 154 tagResult.casePath = caseData->getTestCasePath(); 155 tagResult.caseType = xe::TESTCASETYPE_SELF_VALIDATE; 156 tagResult.statusCode = caseData->getStatusCode(); 157 tagResult.statusDetails = caseData->getStatusDetails(); 158 tagResult.values.resize(tagNames.size()); 159 160 if (caseData->getDataSize() > 0 && caseData->getStatusCode() == xe::TESTSTATUSCODE_LAST) 161 { 162 xe::TestCaseResult fullResult; 163 xe::TestResultParser::ParseResult parseResult; 164 165 m_testResultParser.init(&fullResult); 166 parseResult = m_testResultParser.parse(caseData->getData(), caseData->getDataSize()); 167 168 if ((parseResult != xe::TestResultParser::PARSERESULT_ERROR && fullResult.statusCode != xe::TESTSTATUSCODE_LAST) || 169 (tagResult.statusCode == xe::TESTSTATUSCODE_LAST && fullResult.statusCode != xe::TESTSTATUSCODE_LAST)) 170 { 171 tagResult.statusCode = fullResult.statusCode; 172 tagResult.statusDetails = fullResult.statusDetails; 173 } 174 else if (tagResult.statusCode == xe::TESTSTATUSCODE_LAST) 175 { 176 DE_ASSERT(parseResult == xe::TestResultParser::PARSERESULT_ERROR); 177 tagResult.statusCode = xe::TESTSTATUSCODE_INTERNAL_ERROR; 178 tagResult.statusDetails = "Test case result parsing failed"; 179 } 180 181 if (parseResult != xe::TestResultParser::PARSERESULT_ERROR) 182 { 183 for (int valNdx = 0; valNdx < (int)tagNames.size(); valNdx++) 184 tagResult.values[valNdx] = findValueByTag(fullResult.resultItems, tagNames[valNdx]); 185 } 186 } 187 188 m_result.add(tagResult); 189 } 190 191private: 192 BatchResultValues& m_result; 193 xe::TestResultParser m_testResultParser; 194}; 195 196static void readLogFile (BatchResultValues& batchResult, const char* filename) 197{ 198 std::ifstream in (filename, std::ifstream::binary|std::ifstream::in); 199 TagParser resultHandler (batchResult); 200 xe::TestLogParser parser (&resultHandler); 201 deUint8 buf [1024]; 202 int numRead = 0; 203 204 if (!in.good()) 205 throw std::runtime_error(string("Failed to open '") + filename + "'"); 206 207 for (;;) 208 { 209 in.read((char*)&buf[0], DE_LENGTH_OF_ARRAY(buf)); 210 numRead = (int)in.gcount(); 211 212 if (numRead <= 0) 213 break; 214 215 parser.parse(&buf[0], numRead); 216 } 217 218 in.close(); 219} 220 221static void printTaggedValues (const CommandLine& cmdLine, std::ostream& dst) 222{ 223 BatchResultValues values(cmdLine.tagNames); 224 225 readLogFile(values, cmdLine.filename.c_str()); 226 227 // Header 228 { 229 dst << "CasePath"; 230 if (cmdLine.statusCode) 231 dst << ",StatusCode"; 232 233 for (vector<string>::const_iterator tagName = values.getTagNames().begin(); tagName != values.getTagNames().end(); ++tagName) 234 dst << "," << *tagName; 235 236 dst << "\n"; 237 } 238 239 for (int resultNdx = 0; resultNdx < (int)values.size(); resultNdx++) 240 { 241 const CaseValues& result = values[resultNdx]; 242 243 dst << result.casePath; 244 if (cmdLine.statusCode) 245 dst << "," << xe::getTestStatusCodeName(result.statusCode); 246 247 for (vector<Value>::const_iterator value = result.values.begin(); value != result.values.end(); ++value) 248 dst << "," << *value; 249 250 dst << "\n"; 251 } 252} 253 254static void printHelp (const char* binName) 255{ 256 printf("%s: [filename] [name 1] [[name 2]...]\n", binName); 257 printf(" --statuscode Include status code as first entry.\n"); 258} 259 260static bool parseCommandLine (CommandLine& cmdLine, int argc, const char* const* argv) 261{ 262 for (int argNdx = 1; argNdx < argc; argNdx++) 263 { 264 const char* arg = argv[argNdx]; 265 266 if (deStringEqual(arg, "--statuscode")) 267 cmdLine.statusCode = true; 268 else if (!deStringBeginsWith(arg, "--")) 269 { 270 if (cmdLine.filename.empty()) 271 cmdLine.filename = arg; 272 else 273 cmdLine.tagNames.push_back(arg); 274 } 275 else 276 return false; 277 } 278 279 if (cmdLine.filename.empty()) 280 return false; 281 282 return true; 283} 284 285int main (int argc, const char* const* argv) 286{ 287 try 288 { 289 CommandLine cmdLine; 290 291 if (!parseCommandLine(cmdLine, argc, argv)) 292 { 293 printHelp(argv[0]); 294 return -1; 295 } 296 297 printTaggedValues(cmdLine, std::cout); 298 } 299 catch (const std::exception& e) 300 { 301 printf("FATAL ERROR: %s\n", e.what()); 302 return -1; 303 } 304 305 return 0; 306} 307