1*635a8641SAndroid Build Coastguard Worker // Copyright 2013 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker
5*635a8641SAndroid Build Coastguard Worker #include "base/test/gtest_xml_util.h"
6*635a8641SAndroid Build Coastguard Worker
7*635a8641SAndroid Build Coastguard Worker #include <stdint.h>
8*635a8641SAndroid Build Coastguard Worker
9*635a8641SAndroid Build Coastguard Worker #include "base/base64.h"
10*635a8641SAndroid Build Coastguard Worker #include "base/files/file_util.h"
11*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
12*635a8641SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/test/gtest_util.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/test/launcher/test_launcher.h"
16*635a8641SAndroid Build Coastguard Worker #include "third_party/libxml/chromium/libxml_utils.h"
17*635a8641SAndroid Build Coastguard Worker
18*635a8641SAndroid Build Coastguard Worker namespace base {
19*635a8641SAndroid Build Coastguard Worker
20*635a8641SAndroid Build Coastguard Worker namespace {
21*635a8641SAndroid Build Coastguard Worker
22*635a8641SAndroid Build Coastguard Worker // This is used for the xml parser to report errors. This assumes the context
23*635a8641SAndroid Build Coastguard Worker // is a pointer to a std::string where the error message should be appended.
XmlErrorFunc(void * context,const char * message,...)24*635a8641SAndroid Build Coastguard Worker static void XmlErrorFunc(void *context, const char *message, ...) {
25*635a8641SAndroid Build Coastguard Worker va_list args;
26*635a8641SAndroid Build Coastguard Worker va_start(args, message);
27*635a8641SAndroid Build Coastguard Worker std::string* error = static_cast<std::string*>(context);
28*635a8641SAndroid Build Coastguard Worker StringAppendV(error, message, args);
29*635a8641SAndroid Build Coastguard Worker va_end(args);
30*635a8641SAndroid Build Coastguard Worker }
31*635a8641SAndroid Build Coastguard Worker
32*635a8641SAndroid Build Coastguard Worker } // namespace
33*635a8641SAndroid Build Coastguard Worker
ProcessGTestOutput(const base::FilePath & output_file,std::vector<TestResult> * results,bool * crashed)34*635a8641SAndroid Build Coastguard Worker bool ProcessGTestOutput(const base::FilePath& output_file,
35*635a8641SAndroid Build Coastguard Worker std::vector<TestResult>* results,
36*635a8641SAndroid Build Coastguard Worker bool* crashed) {
37*635a8641SAndroid Build Coastguard Worker DCHECK(results);
38*635a8641SAndroid Build Coastguard Worker
39*635a8641SAndroid Build Coastguard Worker std::string xml_contents;
40*635a8641SAndroid Build Coastguard Worker if (!ReadFileToString(output_file, &xml_contents))
41*635a8641SAndroid Build Coastguard Worker return false;
42*635a8641SAndroid Build Coastguard Worker
43*635a8641SAndroid Build Coastguard Worker // Silence XML errors - otherwise they go to stderr.
44*635a8641SAndroid Build Coastguard Worker std::string xml_errors;
45*635a8641SAndroid Build Coastguard Worker ScopedXmlErrorFunc error_func(&xml_errors, &XmlErrorFunc);
46*635a8641SAndroid Build Coastguard Worker
47*635a8641SAndroid Build Coastguard Worker XmlReader xml_reader;
48*635a8641SAndroid Build Coastguard Worker if (!xml_reader.Load(xml_contents))
49*635a8641SAndroid Build Coastguard Worker return false;
50*635a8641SAndroid Build Coastguard Worker
51*635a8641SAndroid Build Coastguard Worker enum {
52*635a8641SAndroid Build Coastguard Worker STATE_INIT,
53*635a8641SAndroid Build Coastguard Worker STATE_TESTSUITE,
54*635a8641SAndroid Build Coastguard Worker STATE_TESTCASE,
55*635a8641SAndroid Build Coastguard Worker STATE_TEST_RESULT,
56*635a8641SAndroid Build Coastguard Worker STATE_FAILURE,
57*635a8641SAndroid Build Coastguard Worker STATE_END,
58*635a8641SAndroid Build Coastguard Worker } state = STATE_INIT;
59*635a8641SAndroid Build Coastguard Worker
60*635a8641SAndroid Build Coastguard Worker while (xml_reader.Read()) {
61*635a8641SAndroid Build Coastguard Worker xml_reader.SkipToElement();
62*635a8641SAndroid Build Coastguard Worker std::string node_name(xml_reader.NodeName());
63*635a8641SAndroid Build Coastguard Worker
64*635a8641SAndroid Build Coastguard Worker switch (state) {
65*635a8641SAndroid Build Coastguard Worker case STATE_INIT:
66*635a8641SAndroid Build Coastguard Worker if (node_name == "testsuites" && !xml_reader.IsClosingElement())
67*635a8641SAndroid Build Coastguard Worker state = STATE_TESTSUITE;
68*635a8641SAndroid Build Coastguard Worker else
69*635a8641SAndroid Build Coastguard Worker return false;
70*635a8641SAndroid Build Coastguard Worker break;
71*635a8641SAndroid Build Coastguard Worker case STATE_TESTSUITE:
72*635a8641SAndroid Build Coastguard Worker if (node_name == "testsuites" && xml_reader.IsClosingElement())
73*635a8641SAndroid Build Coastguard Worker state = STATE_END;
74*635a8641SAndroid Build Coastguard Worker else if (node_name == "testsuite" && !xml_reader.IsClosingElement())
75*635a8641SAndroid Build Coastguard Worker state = STATE_TESTCASE;
76*635a8641SAndroid Build Coastguard Worker else
77*635a8641SAndroid Build Coastguard Worker return false;
78*635a8641SAndroid Build Coastguard Worker break;
79*635a8641SAndroid Build Coastguard Worker case STATE_TESTCASE:
80*635a8641SAndroid Build Coastguard Worker if (node_name == "testsuite" && xml_reader.IsClosingElement()) {
81*635a8641SAndroid Build Coastguard Worker state = STATE_TESTSUITE;
82*635a8641SAndroid Build Coastguard Worker } else if (node_name == "x-teststart" &&
83*635a8641SAndroid Build Coastguard Worker !xml_reader.IsClosingElement()) {
84*635a8641SAndroid Build Coastguard Worker // This is our custom extension that helps recognize which test was
85*635a8641SAndroid Build Coastguard Worker // running when the test binary crashed.
86*635a8641SAndroid Build Coastguard Worker TestResult result;
87*635a8641SAndroid Build Coastguard Worker
88*635a8641SAndroid Build Coastguard Worker std::string test_case_name;
89*635a8641SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("classname", &test_case_name))
90*635a8641SAndroid Build Coastguard Worker return false;
91*635a8641SAndroid Build Coastguard Worker std::string test_name;
92*635a8641SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("name", &test_name))
93*635a8641SAndroid Build Coastguard Worker return false;
94*635a8641SAndroid Build Coastguard Worker result.full_name = FormatFullTestName(test_case_name, test_name);
95*635a8641SAndroid Build Coastguard Worker
96*635a8641SAndroid Build Coastguard Worker result.elapsed_time = TimeDelta();
97*635a8641SAndroid Build Coastguard Worker
98*635a8641SAndroid Build Coastguard Worker // Assume the test crashed - we can correct that later.
99*635a8641SAndroid Build Coastguard Worker result.status = TestResult::TEST_CRASH;
100*635a8641SAndroid Build Coastguard Worker
101*635a8641SAndroid Build Coastguard Worker results->push_back(result);
102*635a8641SAndroid Build Coastguard Worker } else if (node_name == "testcase" && !xml_reader.IsClosingElement()) {
103*635a8641SAndroid Build Coastguard Worker std::string test_status;
104*635a8641SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("status", &test_status))
105*635a8641SAndroid Build Coastguard Worker return false;
106*635a8641SAndroid Build Coastguard Worker
107*635a8641SAndroid Build Coastguard Worker if (test_status != "run" && test_status != "notrun")
108*635a8641SAndroid Build Coastguard Worker return false;
109*635a8641SAndroid Build Coastguard Worker if (test_status != "run")
110*635a8641SAndroid Build Coastguard Worker break;
111*635a8641SAndroid Build Coastguard Worker
112*635a8641SAndroid Build Coastguard Worker TestResult result;
113*635a8641SAndroid Build Coastguard Worker
114*635a8641SAndroid Build Coastguard Worker std::string test_case_name;
115*635a8641SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("classname", &test_case_name))
116*635a8641SAndroid Build Coastguard Worker return false;
117*635a8641SAndroid Build Coastguard Worker std::string test_name;
118*635a8641SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("name", &test_name))
119*635a8641SAndroid Build Coastguard Worker return false;
120*635a8641SAndroid Build Coastguard Worker result.full_name = test_case_name + "." + test_name;
121*635a8641SAndroid Build Coastguard Worker
122*635a8641SAndroid Build Coastguard Worker std::string test_time_str;
123*635a8641SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("time", &test_time_str))
124*635a8641SAndroid Build Coastguard Worker return false;
125*635a8641SAndroid Build Coastguard Worker result.elapsed_time = TimeDelta::FromMicroseconds(
126*635a8641SAndroid Build Coastguard Worker static_cast<int64_t>(strtod(test_time_str.c_str(), nullptr) *
127*635a8641SAndroid Build Coastguard Worker Time::kMicrosecondsPerSecond));
128*635a8641SAndroid Build Coastguard Worker
129*635a8641SAndroid Build Coastguard Worker result.status = TestResult::TEST_SUCCESS;
130*635a8641SAndroid Build Coastguard Worker
131*635a8641SAndroid Build Coastguard Worker if (!results->empty() &&
132*635a8641SAndroid Build Coastguard Worker results->back().full_name == result.full_name &&
133*635a8641SAndroid Build Coastguard Worker results->back().status == TestResult::TEST_CRASH) {
134*635a8641SAndroid Build Coastguard Worker // Erase the fail-safe "crashed" result - now we know the test did
135*635a8641SAndroid Build Coastguard Worker // not crash.
136*635a8641SAndroid Build Coastguard Worker results->pop_back();
137*635a8641SAndroid Build Coastguard Worker }
138*635a8641SAndroid Build Coastguard Worker
139*635a8641SAndroid Build Coastguard Worker results->push_back(result);
140*635a8641SAndroid Build Coastguard Worker } else if (node_name == "failure" && !xml_reader.IsClosingElement()) {
141*635a8641SAndroid Build Coastguard Worker std::string failure_message;
142*635a8641SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("message", &failure_message))
143*635a8641SAndroid Build Coastguard Worker return false;
144*635a8641SAndroid Build Coastguard Worker
145*635a8641SAndroid Build Coastguard Worker DCHECK(!results->empty());
146*635a8641SAndroid Build Coastguard Worker results->back().status = TestResult::TEST_FAILURE;
147*635a8641SAndroid Build Coastguard Worker
148*635a8641SAndroid Build Coastguard Worker state = STATE_FAILURE;
149*635a8641SAndroid Build Coastguard Worker } else if (node_name == "testcase" && xml_reader.IsClosingElement()) {
150*635a8641SAndroid Build Coastguard Worker // Deliberately empty.
151*635a8641SAndroid Build Coastguard Worker } else if (node_name == "x-test-result-part" &&
152*635a8641SAndroid Build Coastguard Worker !xml_reader.IsClosingElement()) {
153*635a8641SAndroid Build Coastguard Worker std::string result_type;
154*635a8641SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("type", &result_type))
155*635a8641SAndroid Build Coastguard Worker return false;
156*635a8641SAndroid Build Coastguard Worker
157*635a8641SAndroid Build Coastguard Worker std::string file_name;
158*635a8641SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("file", &file_name))
159*635a8641SAndroid Build Coastguard Worker return false;
160*635a8641SAndroid Build Coastguard Worker
161*635a8641SAndroid Build Coastguard Worker std::string line_number_str;
162*635a8641SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("line", &line_number_str))
163*635a8641SAndroid Build Coastguard Worker return false;
164*635a8641SAndroid Build Coastguard Worker
165*635a8641SAndroid Build Coastguard Worker int line_number;
166*635a8641SAndroid Build Coastguard Worker if (!StringToInt(line_number_str, &line_number))
167*635a8641SAndroid Build Coastguard Worker return false;
168*635a8641SAndroid Build Coastguard Worker
169*635a8641SAndroid Build Coastguard Worker TestResultPart::Type type;
170*635a8641SAndroid Build Coastguard Worker if (!TestResultPart::TypeFromString(result_type, &type))
171*635a8641SAndroid Build Coastguard Worker return false;
172*635a8641SAndroid Build Coastguard Worker
173*635a8641SAndroid Build Coastguard Worker TestResultPart test_result_part;
174*635a8641SAndroid Build Coastguard Worker test_result_part.type = type;
175*635a8641SAndroid Build Coastguard Worker test_result_part.file_name = file_name,
176*635a8641SAndroid Build Coastguard Worker test_result_part.line_number = line_number;
177*635a8641SAndroid Build Coastguard Worker DCHECK(!results->empty());
178*635a8641SAndroid Build Coastguard Worker results->back().test_result_parts.push_back(test_result_part);
179*635a8641SAndroid Build Coastguard Worker
180*635a8641SAndroid Build Coastguard Worker state = STATE_TEST_RESULT;
181*635a8641SAndroid Build Coastguard Worker } else {
182*635a8641SAndroid Build Coastguard Worker return false;
183*635a8641SAndroid Build Coastguard Worker }
184*635a8641SAndroid Build Coastguard Worker break;
185*635a8641SAndroid Build Coastguard Worker case STATE_TEST_RESULT:
186*635a8641SAndroid Build Coastguard Worker if (node_name == "summary" && !xml_reader.IsClosingElement()) {
187*635a8641SAndroid Build Coastguard Worker std::string summary;
188*635a8641SAndroid Build Coastguard Worker if (!xml_reader.ReadElementContent(&summary))
189*635a8641SAndroid Build Coastguard Worker return false;
190*635a8641SAndroid Build Coastguard Worker
191*635a8641SAndroid Build Coastguard Worker if (!Base64Decode(summary, &summary))
192*635a8641SAndroid Build Coastguard Worker return false;
193*635a8641SAndroid Build Coastguard Worker
194*635a8641SAndroid Build Coastguard Worker DCHECK(!results->empty());
195*635a8641SAndroid Build Coastguard Worker DCHECK(!results->back().test_result_parts.empty());
196*635a8641SAndroid Build Coastguard Worker results->back().test_result_parts.back().summary = summary;
197*635a8641SAndroid Build Coastguard Worker } else if (node_name == "summary" && xml_reader.IsClosingElement()) {
198*635a8641SAndroid Build Coastguard Worker } else if (node_name == "message" && !xml_reader.IsClosingElement()) {
199*635a8641SAndroid Build Coastguard Worker std::string message;
200*635a8641SAndroid Build Coastguard Worker if (!xml_reader.ReadElementContent(&message))
201*635a8641SAndroid Build Coastguard Worker return false;
202*635a8641SAndroid Build Coastguard Worker
203*635a8641SAndroid Build Coastguard Worker if (!Base64Decode(message, &message))
204*635a8641SAndroid Build Coastguard Worker return false;
205*635a8641SAndroid Build Coastguard Worker
206*635a8641SAndroid Build Coastguard Worker DCHECK(!results->empty());
207*635a8641SAndroid Build Coastguard Worker DCHECK(!results->back().test_result_parts.empty());
208*635a8641SAndroid Build Coastguard Worker results->back().test_result_parts.back().message = message;
209*635a8641SAndroid Build Coastguard Worker } else if (node_name == "message" && xml_reader.IsClosingElement()) {
210*635a8641SAndroid Build Coastguard Worker } else if (node_name == "x-test-result-part" &&
211*635a8641SAndroid Build Coastguard Worker xml_reader.IsClosingElement()) {
212*635a8641SAndroid Build Coastguard Worker state = STATE_TESTCASE;
213*635a8641SAndroid Build Coastguard Worker } else {
214*635a8641SAndroid Build Coastguard Worker return false;
215*635a8641SAndroid Build Coastguard Worker }
216*635a8641SAndroid Build Coastguard Worker break;
217*635a8641SAndroid Build Coastguard Worker case STATE_FAILURE:
218*635a8641SAndroid Build Coastguard Worker if (node_name == "failure" && xml_reader.IsClosingElement())
219*635a8641SAndroid Build Coastguard Worker state = STATE_TESTCASE;
220*635a8641SAndroid Build Coastguard Worker else
221*635a8641SAndroid Build Coastguard Worker return false;
222*635a8641SAndroid Build Coastguard Worker break;
223*635a8641SAndroid Build Coastguard Worker case STATE_END:
224*635a8641SAndroid Build Coastguard Worker // If we are here and there are still XML elements, the file has wrong
225*635a8641SAndroid Build Coastguard Worker // format.
226*635a8641SAndroid Build Coastguard Worker return false;
227*635a8641SAndroid Build Coastguard Worker }
228*635a8641SAndroid Build Coastguard Worker }
229*635a8641SAndroid Build Coastguard Worker
230*635a8641SAndroid Build Coastguard Worker *crashed = (state != STATE_END);
231*635a8641SAndroid Build Coastguard Worker return true;
232*635a8641SAndroid Build Coastguard Worker }
233*635a8641SAndroid Build Coastguard Worker
234*635a8641SAndroid Build Coastguard Worker } // namespace base
235