| /*------------------------------------------------------------------------- |
| * drawElements Quality Program Test Executor |
| * ------------------------------------------ |
| * |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Extract values by name from logs. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "xeTestLogParser.hpp" |
| #include "xeTestResultParser.hpp" |
| #include "deFilePath.hpp" |
| #include "deString.h" |
| |
| #include <vector> |
| #include <string> |
| #include <cstdio> |
| #include <cstdlib> |
| #include <fstream> |
| #include <iostream> |
| #include <stdexcept> |
| |
| using std::vector; |
| using std::string; |
| using std::set; |
| using std::map; |
| |
| struct CommandLine |
| { |
| CommandLine (void) |
| : statusCode(false) |
| { |
| } |
| |
| string filename; |
| vector<string> tagNames; |
| bool statusCode; |
| }; |
| |
| typedef xe::ri::NumericValue Value; |
| |
| struct CaseValues |
| { |
| string casePath; |
| xe::TestCaseType caseType; |
| xe::TestStatusCode statusCode; |
| string statusDetails; |
| |
| vector<Value> values; |
| }; |
| |
| class BatchResultValues |
| { |
| public: |
| BatchResultValues (const vector<string>& tagNames) |
| : m_tagNames(tagNames) |
| { |
| } |
| |
| ~BatchResultValues (void) |
| { |
| for (vector<CaseValues*>::iterator i = m_caseValues.begin(); i != m_caseValues.end(); ++i) |
| delete *i; |
| } |
| |
| void add (const CaseValues& result) |
| { |
| CaseValues* copy = new CaseValues(result); |
| try |
| { |
| m_caseValues.push_back(copy); |
| } |
| catch (...) |
| { |
| delete copy; |
| throw; |
| } |
| } |
| |
| const vector<string>& getTagNames (void) const { return m_tagNames; } |
| |
| size_t size (void) const { return m_caseValues.size(); } |
| const CaseValues& operator[] (size_t ndx) const { return *m_caseValues[ndx]; } |
| |
| private: |
| vector<string> m_tagNames; |
| vector<CaseValues*> m_caseValues; |
| }; |
| |
| static Value findValueByTag (const xe::ri::List& items, const string& tagName) |
| { |
| for (int ndx = 0; ndx < items.getNumItems(); ndx++) |
| { |
| const xe::ri::Item& item = items.getItem(ndx); |
| |
| if (item.getType() == xe::ri::TYPE_SECTION) |
| { |
| const Value value = findValueByTag(static_cast<const xe::ri::Section&>(item).items, tagName); |
| if (value.getType() != Value::TYPE_EMPTY) |
| return value; |
| } |
| else if (item.getType() == xe::ri::TYPE_NUMBER) |
| { |
| const xe::ri::Number& value = static_cast<const xe::ri::Number&>(item); |
| return value.value; |
| } |
| } |
| |
| return Value(); |
| } |
| |
| class TagParser : public xe::TestLogHandler |
| { |
| public: |
| TagParser (BatchResultValues& result) |
| : m_result(result) |
| { |
| } |
| |
| void setSessionInfo (const xe::SessionInfo&) |
| { |
| // Ignored. |
| } |
| |
| xe::TestCaseResultPtr startTestCaseResult (const char* casePath) |
| { |
| return xe::TestCaseResultPtr(new xe::TestCaseResultData(casePath)); |
| } |
| |
| void testCaseResultUpdated (const xe::TestCaseResultPtr&) |
| { |
| // Ignored. |
| } |
| |
| void testCaseResultComplete (const xe::TestCaseResultPtr& caseData) |
| { |
| const vector<string>& tagNames = m_result.getTagNames(); |
| CaseValues tagResult; |
| |
| tagResult.casePath = caseData->getTestCasePath(); |
| tagResult.caseType = xe::TESTCASETYPE_SELF_VALIDATE; |
| tagResult.statusCode = caseData->getStatusCode(); |
| tagResult.statusDetails = caseData->getStatusDetails(); |
| tagResult.values.resize(tagNames.size()); |
| |
| if (caseData->getDataSize() > 0 && caseData->getStatusCode() == xe::TESTSTATUSCODE_LAST) |
| { |
| xe::TestCaseResult fullResult; |
| xe::TestResultParser::ParseResult parseResult; |
| |
| m_testResultParser.init(&fullResult); |
| parseResult = m_testResultParser.parse(caseData->getData(), caseData->getDataSize()); |
| |
| if ((parseResult != xe::TestResultParser::PARSERESULT_ERROR && fullResult.statusCode != xe::TESTSTATUSCODE_LAST) || |
| (tagResult.statusCode == xe::TESTSTATUSCODE_LAST && fullResult.statusCode != xe::TESTSTATUSCODE_LAST)) |
| { |
| tagResult.statusCode = fullResult.statusCode; |
| tagResult.statusDetails = fullResult.statusDetails; |
| } |
| else if (tagResult.statusCode == xe::TESTSTATUSCODE_LAST) |
| { |
| DE_ASSERT(parseResult == xe::TestResultParser::PARSERESULT_ERROR); |
| tagResult.statusCode = xe::TESTSTATUSCODE_INTERNAL_ERROR; |
| tagResult.statusDetails = "Test case result parsing failed"; |
| } |
| |
| if (parseResult != xe::TestResultParser::PARSERESULT_ERROR) |
| { |
| for (int valNdx = 0; valNdx < (int)tagNames.size(); valNdx++) |
| tagResult.values[valNdx] = findValueByTag(fullResult.resultItems, tagNames[valNdx]); |
| } |
| } |
| |
| m_result.add(tagResult); |
| } |
| |
| private: |
| BatchResultValues& m_result; |
| xe::TestResultParser m_testResultParser; |
| }; |
| |
| static void readLogFile (BatchResultValues& batchResult, const char* filename) |
| { |
| std::ifstream in (filename, std::ifstream::binary|std::ifstream::in); |
| TagParser resultHandler (batchResult); |
| xe::TestLogParser parser (&resultHandler); |
| deUint8 buf [1024]; |
| int numRead = 0; |
| |
| if (!in.good()) |
| throw std::runtime_error(string("Failed to open '") + filename + "'"); |
| |
| for (;;) |
| { |
| in.read((char*)&buf[0], DE_LENGTH_OF_ARRAY(buf)); |
| numRead = (int)in.gcount(); |
| |
| if (numRead <= 0) |
| break; |
| |
| parser.parse(&buf[0], numRead); |
| } |
| |
| in.close(); |
| } |
| |
| static void printTaggedValues (const CommandLine& cmdLine, std::ostream& dst) |
| { |
| BatchResultValues values(cmdLine.tagNames); |
| |
| readLogFile(values, cmdLine.filename.c_str()); |
| |
| // Header |
| { |
| dst << "CasePath"; |
| if (cmdLine.statusCode) |
| dst << ",StatusCode"; |
| |
| for (vector<string>::const_iterator tagName = values.getTagNames().begin(); tagName != values.getTagNames().end(); ++tagName) |
| dst << "," << *tagName; |
| |
| dst << "\n"; |
| } |
| |
| for (int resultNdx = 0; resultNdx < (int)values.size(); resultNdx++) |
| { |
| const CaseValues& result = values[resultNdx]; |
| |
| dst << result.casePath; |
| if (cmdLine.statusCode) |
| dst << "," << xe::getTestStatusCodeName(result.statusCode); |
| |
| for (vector<Value>::const_iterator value = result.values.begin(); value != result.values.end(); ++value) |
| dst << "," << *value; |
| |
| dst << "\n"; |
| } |
| } |
| |
| static void printHelp (const char* binName) |
| { |
| printf("%s: [filename] [name 1] [[name 2]...]\n", binName); |
| printf(" --statuscode Include status code as first entry.\n"); |
| } |
| |
| static bool parseCommandLine (CommandLine& cmdLine, int argc, const char* const* argv) |
| { |
| for (int argNdx = 1; argNdx < argc; argNdx++) |
| { |
| const char* arg = argv[argNdx]; |
| |
| if (deStringEqual(arg, "--statuscode")) |
| cmdLine.statusCode = true; |
| else if (!deStringBeginsWith(arg, "--")) |
| { |
| if (cmdLine.filename.empty()) |
| cmdLine.filename = arg; |
| else |
| cmdLine.tagNames.push_back(arg); |
| } |
| else |
| return false; |
| } |
| |
| if (cmdLine.filename.empty()) |
| return false; |
| |
| return true; |
| } |
| |
| int main (int argc, const char* const* argv) |
| { |
| try |
| { |
| CommandLine cmdLine; |
| |
| if (!parseCommandLine(cmdLine, argc, argv)) |
| { |
| printHelp(argv[0]); |
| return -1; |
| } |
| |
| printTaggedValues(cmdLine, std::cout); |
| } |
| catch (const std::exception& e) |
| { |
| printf("FATAL ERROR: %s\n", e.what()); |
| return -1; |
| } |
| |
| return 0; |
| } |