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 {
CommandLineCommandLine44 	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:
BatchResultValues(const vector<string> & tagNames)69 	BatchResultValues (const vector<string>& tagNames)
70 		: m_tagNames(tagNames)
71 	{
72 	}
73 
~BatchResultValues(void)74 	~BatchResultValues (void)
75 	{
76 		for (vector<CaseValues*>::iterator i = m_caseValues.begin(); i != m_caseValues.end(); ++i)
77 			delete *i;
78 	}
79 
add(const CaseValues & result)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 
getTagNames(void) const94 	const vector<string>&	getTagNames		(void) const		{ return m_tagNames;			}
95 
size(void) const96 	size_t					size			(void) const		{ return m_caseValues.size();	}
operator [](size_t ndx) const97 	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 
findValueByTag(const xe::ri::List & items,const string & tagName)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:
TagParser(BatchResultValues & result)129 	TagParser (BatchResultValues& result)
130 		: m_result(result)
131 	{
132 	}
133 
setSessionInfo(const xe::SessionInfo &)134 	void setSessionInfo (const xe::SessionInfo&)
135 	{
136 		// Ignored.
137 	}
138 
startTestCaseResult(const char * casePath)139 	xe::TestCaseResultPtr startTestCaseResult (const char* casePath)
140 	{
141 		return xe::TestCaseResultPtr(new xe::TestCaseResultData(casePath));
142 	}
143 
testCaseResultUpdated(const xe::TestCaseResultPtr &)144 	void testCaseResultUpdated (const xe::TestCaseResultPtr&)
145 	{
146 		// Ignored.
147 	}
148 
testCaseResultComplete(const xe::TestCaseResultPtr & caseData)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 
readLogFile(BatchResultValues & batchResult,const char * filename)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 
printTaggedValues(const CommandLine & cmdLine,std::ostream & dst)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 
printHelp(const char * binName)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 
parseCommandLine(CommandLine & cmdLine,int argc,const char * const * argv)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 
main(int argc,const char * const * argv)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