Vulkan: Add wide-color tests
[platform/upstream/VK-GL-CTS.git] / executor / tools / xeBatchResultToXml.cpp
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 Batch result to XML export.
22  *//*--------------------------------------------------------------------*/
23
24 #include "xeTestLogParser.hpp"
25 #include "xeTestResultParser.hpp"
26 #include "xeXMLWriter.hpp"
27 #include "xeTestLogWriter.hpp"
28 #include "deFilePath.hpp"
29 #include "deString.h"
30 #include "deStringUtil.hpp"
31 #include "deCommandLine.hpp"
32
33 #include <vector>
34 #include <string>
35 #include <map>
36 #include <cstdio>
37 #include <fstream>
38 #include <iostream>
39
40 using std::vector;
41 using std::string;
42 using std::map;
43
44 static const char*      CASELIST_STYLESHEET             = "caselist.xsl";
45 static const char*      TESTCASE_STYLESHEET             = "testlog.xsl";
46
47 enum OutputMode
48 {
49         OUTPUTMODE_SEPARATE = 0,        //!< Separate
50         OUTPUTMODE_SINGLE,
51
52         OUTPUTMODE_LAST
53 };
54
55 namespace opt
56 {
57
58 DE_DECLARE_COMMAND_LINE_OPT(OutMode, OutputMode);
59
60 void registerOptions (de::cmdline::Parser& parser)
61 {
62         using de::cmdline::Option;
63         using de::cmdline::NamedValue;
64
65         static const NamedValue<OutputMode> s_modes[] =
66         {
67                 { "single",             OUTPUTMODE_SINGLE       },
68                 { "separate",   OUTPUTMODE_SEPARATE     }
69         };
70
71         parser << Option<OutMode>("m", "mode", "Output mode", s_modes, "single");
72 }
73
74 } // opt
75
76 struct CommandLine
77 {
78         CommandLine (void)
79                 : outputMode(OUTPUTMODE_SINGLE)
80         {
81         }
82
83         std::string             batchResultFile;
84         std::string             outputPath;
85         OutputMode              outputMode;
86 };
87
88 static bool parseCommandLine (CommandLine& cmdLine, int argc, const char* const* argv)
89 {
90         de::cmdline::Parser                     parser;
91         de::cmdline::CommandLine        opts;
92
93         opt::registerOptions(parser);
94
95         if (!parser.parse(argc-1, argv+1, &opts, std::cerr) ||
96                 opts.getArgs().size() != 2)
97         {
98                 printf("%s: [options] [testlog] [destination path]\n", argv[0]);
99                 parser.help(std::cout);
100                 return false;
101         }
102
103         cmdLine.outputMode              = opts.getOption<opt::OutMode>();
104         cmdLine.batchResultFile = opts.getArgs()[0];
105         cmdLine.outputPath              = opts.getArgs()[1];
106
107         return true;
108 }
109
110 static void parseBatchResult (xe::TestLogParser& parser, const char* filename)
111 {
112         std::ifstream   in                      (filename, std::ios_base::binary);
113         deUint8                 buf[2048];
114
115         for (;;)
116         {
117                 in.read((char*)&buf[0], sizeof(buf));
118                 int numRead = (int)in.gcount();
119
120                 if (numRead > 0)
121                         parser.parse(&buf[0], numRead);
122
123                 if (numRead < (int)sizeof(buf))
124                         break;
125         }
126 }
127
128 // Export to single file
129
130 struct BatchResultTotals
131 {
132         BatchResultTotals (void)
133         {
134                 for (int i = 0;i < xe::TESTSTATUSCODE_LAST; i++)
135                         countByCode[i] = 0;
136         }
137
138         int countByCode[xe::TESTSTATUSCODE_LAST];
139 };
140
141 class ResultToSingleXmlLogHandler : public xe::TestLogHandler
142 {
143 public:
144         ResultToSingleXmlLogHandler (xe::xml::Writer& writer, BatchResultTotals& totals)
145                 : m_writer      (writer)
146                 , m_totals      (totals)
147         {
148         }
149
150         void setSessionInfo (const xe::SessionInfo&)
151         {
152         }
153
154         xe::TestCaseResultPtr startTestCaseResult (const char* casePath)
155         {
156                 return xe::TestCaseResultPtr(new xe::TestCaseResultData(casePath));
157         }
158
159         void testCaseResultUpdated (const xe::TestCaseResultPtr&)
160         {
161         }
162
163         void testCaseResultComplete (const xe::TestCaseResultPtr& resultData)
164         {
165                 xe::TestCaseResult result;
166
167                 xe::parseTestCaseResultFromData(&m_resultParser, &result, *resultData.get());
168
169                 // Write result.
170                 xe::writeTestResult(result, m_writer);
171
172                 // Record total
173                 XE_CHECK(de::inBounds<int>(result.statusCode, 0, xe::TESTSTATUSCODE_LAST));
174                 m_totals.countByCode[result.statusCode] += 1;
175         }
176
177 private:
178         xe::xml::Writer&                m_writer;
179         BatchResultTotals&              m_totals;
180         xe::TestResultParser    m_resultParser;
181 };
182
183 static void writeTotals (xe::xml::Writer& writer, const BatchResultTotals& totals)
184 {
185         using xe::xml::Writer;
186
187         int totalCases = 0;
188
189         writer << Writer::BeginElement("ResultTotals");
190
191         for (int code = 0; code < xe::TESTSTATUSCODE_LAST; code++)
192         {
193                 writer << Writer::Attribute(xe::getTestStatusCodeName((xe::TestStatusCode)code), de::toString(totals.countByCode[code]).c_str());
194                 totalCases += totals.countByCode[code];
195         }
196
197         writer << Writer::Attribute("All", de::toString(totalCases).c_str())
198                    << Writer::EndElement;
199 }
200
201 static void batchResultToSingleXmlFile (const char* batchResultFilename, const char* dstFileName)
202 {
203         std::ofstream                           out                     (dstFileName, std::ios_base::binary);
204         xe::xml::Writer                         writer          (out);
205         BatchResultTotals                       totals;
206         ResultToSingleXmlLogHandler     handler         (writer, totals);
207         xe::TestLogParser                       parser          (&handler);
208
209         XE_CHECK(out.good());
210
211         out << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
212                 << "<?xml-stylesheet href=\"" << TESTCASE_STYLESHEET << "\" type=\"text/xsl\"?>\n";
213
214         writer << xe::xml::Writer::BeginElement("BatchResult")
215                    << xe::xml::Writer::Attribute("FileName", de::FilePath(batchResultFilename).getBaseName());
216
217         // Parse and write individual cases
218         parseBatchResult(parser, batchResultFilename);
219
220         // Write ResultTotals
221         writeTotals(writer, totals);
222
223         writer << xe::xml::Writer::EndElement;
224         out << "\n";
225 }
226
227 // Export to separate files
228
229 class ResultToXmlFilesLogHandler : public xe::TestLogHandler
230 {
231 public:
232         ResultToXmlFilesLogHandler (vector<xe::TestCaseResultHeader>& resultHeaders, const char* dstPath)
233                 : m_resultHeaders       (resultHeaders)
234                 , m_dstPath                     (dstPath)
235         {
236         }
237
238         void setSessionInfo (const xe::SessionInfo&)
239         {
240         }
241
242         xe::TestCaseResultPtr startTestCaseResult (const char* casePath)
243         {
244                 return xe::TestCaseResultPtr(new xe::TestCaseResultData(casePath));
245         }
246
247         void testCaseResultUpdated (const xe::TestCaseResultPtr&)
248         {
249         }
250
251         void testCaseResultComplete (const xe::TestCaseResultPtr& resultData)
252         {
253                 xe::TestCaseResult result;
254
255                 xe::parseTestCaseResultFromData(&m_resultParser, &result, *resultData.get());
256
257                 // Write result.
258                 {
259                         de::FilePath    casePath        = de::FilePath::join(m_dstPath, (result.casePath + ".xml").c_str());
260                         std::ofstream   out                     (casePath.getPath(), std::ofstream::binary|std::ofstream::trunc);
261                         xe::xml::Writer xmlWriter       (out);
262
263                         if (!out.good())
264                                 throw xe::Error(string("Failed to open ") + casePath.getPath());
265
266                         out << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
267                                 << "<?xml-stylesheet href=\"" << TESTCASE_STYLESHEET << "\" type=\"text/xsl\"?>\n";
268                         xe::writeTestResult(result, xmlWriter);
269                         out << "\n";
270                 }
271
272                 m_resultHeaders.push_back(xe::TestCaseResultHeader(result));
273         }
274
275 private:
276         vector<xe::TestCaseResultHeader>&       m_resultHeaders;
277         std::string                                                     m_dstPath;
278         xe::TestResultParser                            m_resultParser;
279 };
280
281 typedef std::map<const xe::TestCase*, const xe::TestCaseResultHeader*> ShortTestResultMap;
282
283 static void writeTestCaseListNode (const xe::TestNode* testNode, const ShortTestResultMap& resultMap, xe::xml::Writer& dst)
284 {
285         using xe::xml::Writer;
286
287         bool    isGroup         = testNode->getNodeType() == xe::TESTNODETYPE_GROUP;
288         string  fullPath;
289         testNode->getFullPath(fullPath);
290
291         if (isGroup)
292         {
293                 const xe::TestGroup* group = static_cast<const xe::TestGroup*>(testNode);
294
295                 dst << Writer::BeginElement("TestGroup")
296                         << Writer::Attribute("Name", testNode->getName());
297
298                 for (int childNdx = 0; childNdx < group->getNumChildren(); childNdx++)
299                         writeTestCaseListNode(group->getChild(childNdx), resultMap, dst);
300
301                 dst << Writer::EndElement;
302         }
303         else
304         {
305                 DE_ASSERT(testNode->getNodeType() == xe::TESTNODETYPE_TEST_CASE);
306
307                 const xe::TestCase*                                     testCase        = static_cast<const xe::TestCase*>(testNode);
308                 ShortTestResultMap::const_iterator      resultPos       = resultMap.find(testCase);
309                 const xe::TestCaseResultHeader*         result          = resultPos != resultMap.end() ? resultPos->second : DE_NULL;
310
311                 DE_ASSERT(result);
312
313                 dst << Writer::BeginElement("TestCase")
314                         << Writer::Attribute("Name", testNode->getName())
315                         << Writer::Attribute("Type", xe::getTestCaseTypeName(result->caseType))
316                         << Writer::Attribute("StatusCode", xe::getTestStatusCodeName(result->statusCode))
317                         << Writer::Attribute("StatusDetails", result->statusDetails.c_str())
318                         << Writer::EndElement;
319         }
320 }
321
322 static void writeTestCaseList (const xe::TestRoot& root, const ShortTestResultMap& resultMap, xe::xml::Writer& dst)
323 {
324         using xe::xml::Writer;
325
326         dst << Writer::BeginElement("TestRoot");
327
328         for (int childNdx = 0; childNdx < root.getNumChildren(); childNdx++)
329                 writeTestCaseListNode(root.getChild(childNdx), resultMap, dst);
330
331         dst << Writer::EndElement;
332 }
333
334 static void batchResultToSeparateXmlFiles (const char* batchResultFilename, const char* dstPath)
335 {
336         xe::TestRoot                                            testRoot;
337         vector<xe::TestCaseResultHeader>        shortResults;
338         ShortTestResultMap                                      resultMap;
339
340         // Initialize destination directory.
341         if (!de::FilePath(dstPath).exists())
342                 de::createDirectoryAndParents(dstPath);
343         else
344                 XE_CHECK_MSG(de::FilePath(dstPath).getType() == de::FilePath::TYPE_DIRECTORY, "Destination is not directory");
345
346         // Parse batch result and write out test cases.
347         {
348                 ResultToXmlFilesLogHandler      handler         (shortResults, dstPath);
349                 xe::TestLogParser                       parser          (&handler);
350
351                 parseBatchResult(parser, batchResultFilename);
352         }
353
354         // Build case hierarchy & short result map.
355         {
356                 xe::TestHierarchyBuilder hierarchyBuilder(&testRoot);
357
358                 for (vector<xe::TestCaseResultHeader>::const_iterator result = shortResults.begin(); result != shortResults.end(); result++)
359                 {
360                         xe::TestCase* testCase = hierarchyBuilder.createCase(result->casePath.c_str(), result->caseType);
361                         resultMap.insert(std::make_pair(testCase, &(*result)));
362                 }
363         }
364
365         // Create caselist.
366         {
367                 de::FilePath    indexPath       = de::FilePath::join(dstPath, "caselist.xml");
368                 std::ofstream   out                     (indexPath.getPath(), std::ofstream::binary|std::ofstream::trunc);
369                 xe::xml::Writer xmlWriter       (out);
370
371                 XE_CHECK_MSG(out.good(), "Failed to open caselist.xml");
372
373                 out << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
374                         << "<?xml-stylesheet href=\"" << CASELIST_STYLESHEET << "\" type=\"text/xsl\"?>\n";
375                 writeTestCaseList(testRoot, resultMap, xmlWriter);
376                 out << "\n";
377         }
378 }
379
380 int main (int argc, const char* const* argv)
381 {
382         try
383         {
384                 CommandLine cmdLine;
385                 if (!parseCommandLine(cmdLine, argc, argv))
386                         return -1;
387
388                 if (cmdLine.outputMode == OUTPUTMODE_SINGLE)
389                         batchResultToSingleXmlFile(cmdLine.batchResultFile.c_str(), cmdLine.outputPath.c_str());
390                 else
391                         batchResultToSeparateXmlFiles(cmdLine.batchResultFile.c_str(), cmdLine.outputPath.c_str());
392         }
393         catch (const std::exception& e)
394         {
395                 printf("%s\n", e.what());
396                 return -1;
397         }
398
399         return 0;
400 }