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 37 using std::vector; 38 using std::string; 39 using std::set; 40 using std::map; 41 42 struct CommandLine 43 { 44 CommandLine (void) 45 : statusCode(false) 46 { 47 } 48 49 string filename; 50 vector<string> tagNames; 51 bool statusCode; 52 }; 53 54 typedef xe::ri::NumericValue Value; 55 56 struct CaseValues 57 { 58 string casePath; 59 xe::TestCaseType caseType; 60 xe::TestStatusCode statusCode; 61 string statusDetails; 62 63 vector<Value> values; 64 }; 65 66 class BatchResultValues 67 { 68 public: 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 99 private: 100 vector<string> m_tagNames; 101 vector<CaseValues*> m_caseValues; 102 }; 103 104 static 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 126 class TagParser : public xe::TestLogHandler 127 { 128 public: 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 191 private: 192 BatchResultValues& m_result; 193 xe::TestResultParser m_testResultParser; 194 }; 195 196 static 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 221 static 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 254 static 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 260 static 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 285 int 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