Home | History | Annotate | Download | only in tools
      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