/*------------------------------------------------------------------------- * 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 Merge two test logs. * * \todo [2013-11-08 pyry] Write variant that can operate with less memory. *//*--------------------------------------------------------------------*/ #include "xeTestLogParser.hpp" #include "xeTestResultParser.hpp" #include "xeTestLogWriter.hpp" #include "deString.h" #include #include #include #include #include #include #include using std::vector; using std::string; using std::set; using std::map; enum Flags { FLAG_USE_LAST_INFO = (1<<0) }; struct CommandLine { CommandLine (void) : flags(0) { } vector srcFilenames; string dstFilename; deUint32 flags; }; class LogHandler : public xe::TestLogHandler { public: LogHandler (xe::BatchResult* batchResult, deUint32 flags) : m_batchResult (batchResult) , m_flags (flags) { } void setSessionInfo (const xe::SessionInfo& info) { xe::SessionInfo& combinedInfo = m_batchResult->getSessionInfo(); if (m_flags & FLAG_USE_LAST_INFO) { if (!info.targetName.empty()) combinedInfo.targetName = info.targetName; if (!info.releaseId.empty()) combinedInfo.releaseId = info.releaseId; if (!info.releaseName.empty()) combinedInfo.releaseName = info.releaseName; if (!info.candyTargetName.empty()) combinedInfo.candyTargetName = info.candyTargetName; if (!info.configName.empty()) combinedInfo.configName = info.configName; if (!info.resultName.empty()) combinedInfo.resultName = info.resultName; if (!info.timestamp.empty()) combinedInfo.timestamp = info.timestamp; } else { if (combinedInfo.targetName.empty()) combinedInfo.targetName = info.targetName; if (combinedInfo.releaseId.empty()) combinedInfo.releaseId = info.releaseId; if (combinedInfo.releaseName.empty()) combinedInfo.releaseName = info.releaseName; if (combinedInfo.candyTargetName.empty()) combinedInfo.candyTargetName = info.candyTargetName; if (combinedInfo.configName.empty()) combinedInfo.configName = info.configName; if (combinedInfo.resultName.empty()) combinedInfo.resultName = info.resultName; if (combinedInfo.timestamp.empty()) combinedInfo.timestamp = info.timestamp; } } xe::TestCaseResultPtr startTestCaseResult (const char* casePath) { if (m_batchResult->hasTestCaseResult(casePath)) { xe::TestCaseResultPtr existingResult = m_batchResult->getTestCaseResult(casePath); existingResult->clear(); return existingResult; } else return m_batchResult->createTestCaseResult(casePath); } void testCaseResultUpdated (const xe::TestCaseResultPtr&) { // Ignored. } void testCaseResultComplete (const xe::TestCaseResultPtr&) { // Ignored. } private: xe::BatchResult* const m_batchResult; const deUint32 m_flags; }; static void readLogFile (xe::BatchResult* dstResult, const char* filename, deUint32 flags) { std::ifstream in (filename, std::ifstream::binary|std::ifstream::in); LogHandler resultHandler (dstResult, flags); xe::TestLogParser parser (&resultHandler); deUint8 buf [2048]; 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 mergeTestLogs (const CommandLine& cmdLine) { xe::BatchResult batchResult; for (vector::const_iterator filename = cmdLine.srcFilenames.begin(); filename != cmdLine.srcFilenames.end(); ++filename) readLogFile(&batchResult, filename->c_str(), cmdLine.flags); if (!cmdLine.dstFilename.empty()) xe::writeBatchResultToFile(batchResult, cmdLine.dstFilename.c_str()); else xe::writeTestLog(batchResult, std::cout); } static void printHelp (const char* binName) { printf("%s: [filename] [[filename 2] ...]\n", binName); printf(" --dst=[filename] Write final log to file, otherwise written to stdout.\n"); printf(" --info=[first|last] Select which session info to use (default: first).\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 (!deStringBeginsWith(arg, "--")) cmdLine.srcFilenames.push_back(arg); else if (deStringBeginsWith(arg, "--dst=")) { if (!cmdLine.dstFilename.empty()) return false; cmdLine.dstFilename = arg+6; } else if (deStringEqual(arg, "--info=first")) cmdLine.flags &= ~FLAG_USE_LAST_INFO; else if (deStringEqual(arg, "--info=last")) cmdLine.flags |= FLAG_USE_LAST_INFO; else return false; } if (cmdLine.srcFilenames.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; } mergeTestLogs(cmdLine); } catch (const std::exception& e) { printf("FATAL ERROR: %s\n", e.what()); return -1; } return 0; }