blob: e0a7888e8d76871dbe4140fbd1c32271ae69c14e [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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 <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <stdexcept>
using std::map;
using std::set;
using std::string;
using std::vector;
enum Flags
{
FLAG_USE_LAST_INFO = (1 << 0)
};
struct CommandLine
{
CommandLine(void) : flags(0)
{
}
vector<string> srcFilenames;
string dstFilename;
uint32_t flags;
};
class LogHandler : public xe::TestLogHandler
{
public:
LogHandler(xe::BatchResult *batchResult, uint32_t 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 uint32_t m_flags;
};
static void readLogFile(xe::BatchResult *dstResult, const char *filename, uint32_t flags)
{
std::ifstream in(filename, std::ifstream::binary | std::ifstream::in);
LogHandler resultHandler(dstResult, flags);
xe::TestLogParser parser(&resultHandler);
uint8_t 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<string>::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;
}