1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/test/gtest_xml_util.h"
7 #include "base/files/file_util.h"
8 #include "base/logging.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/test/gtest_util.h"
11 #include "base/test/launcher/test_launcher.h"
12 #include "third_party/libxml/chromium/libxml_utils.h"
18 // This is used for the xml parser to report errors. This assumes the context
19 // is a pointer to a std::string where the error message should be appended.
20 static void XmlErrorFunc(void *context
, const char *message
, ...) {
22 va_start(args
, message
);
23 std::string
* error
= static_cast<std::string
*>(context
);
24 StringAppendV(error
, message
, args
);
30 bool ProcessGTestOutput(const base::FilePath
& output_file
,
31 std::vector
<TestResult
>* results
,
35 std::string xml_contents
;
36 if (!ReadFileToString(output_file
, &xml_contents
))
39 // Silence XML errors - otherwise they go to stderr.
40 std::string xml_errors
;
41 ScopedXmlErrorFunc
error_func(&xml_errors
, &XmlErrorFunc
);
44 if (!xml_reader
.Load(xml_contents
))
55 while (xml_reader
.Read()) {
56 xml_reader
.SkipToElement();
57 std::string
node_name(xml_reader
.NodeName());
61 if (node_name
== "testsuites" && !xml_reader
.IsClosingElement())
62 state
= STATE_TESTSUITE
;
67 if (node_name
== "testsuites" && xml_reader
.IsClosingElement())
69 else if (node_name
== "testsuite" && !xml_reader
.IsClosingElement())
70 state
= STATE_TESTCASE
;
75 if (node_name
== "testsuite" && xml_reader
.IsClosingElement()) {
76 state
= STATE_TESTSUITE
;
77 } else if (node_name
== "x-teststart" &&
78 !xml_reader
.IsClosingElement()) {
79 // This is our custom extension that helps recognize which test was
80 // running when the test binary crashed.
83 std::string test_case_name
;
84 if (!xml_reader
.NodeAttribute("classname", &test_case_name
))
86 std::string test_name
;
87 if (!xml_reader
.NodeAttribute("name", &test_name
))
89 result
.full_name
= FormatFullTestName(test_case_name
, test_name
);
91 result
.elapsed_time
= TimeDelta();
93 // Assume the test crashed - we can correct that later.
94 result
.status
= TestResult::TEST_CRASH
;
96 results
->push_back(result
);
97 } else if (node_name
== "testcase" && !xml_reader
.IsClosingElement()) {
98 std::string test_status
;
99 if (!xml_reader
.NodeAttribute("status", &test_status
))
102 if (test_status
!= "run" && test_status
!= "notrun")
104 if (test_status
!= "run")
109 std::string test_case_name
;
110 if (!xml_reader
.NodeAttribute("classname", &test_case_name
))
112 std::string test_name
;
113 if (!xml_reader
.NodeAttribute("name", &test_name
))
115 result
.full_name
= test_case_name
+ "." + test_name
;
117 std::string test_time_str
;
118 if (!xml_reader
.NodeAttribute("time", &test_time_str
))
120 result
.elapsed_time
= TimeDelta::FromMicroseconds(
121 static_cast<int64
>(strtod(test_time_str
.c_str(), NULL
) *
122 Time::kMicrosecondsPerSecond
));
124 result
.status
= TestResult::TEST_SUCCESS
;
126 if (!results
->empty() &&
127 results
->at(results
->size() - 1).full_name
== result
.full_name
&&
128 results
->at(results
->size() - 1).status
==
129 TestResult::TEST_CRASH
) {
130 // Erase the fail-safe "crashed" result - now we know the test did
135 results
->push_back(result
);
136 } else if (node_name
== "failure" && !xml_reader
.IsClosingElement()) {
137 std::string failure_message
;
138 if (!xml_reader
.NodeAttribute("message", &failure_message
))
141 DCHECK(!results
->empty());
142 results
->at(results
->size() - 1).status
= TestResult::TEST_FAILURE
;
144 state
= STATE_FAILURE
;
145 } else if (node_name
== "testcase" && xml_reader
.IsClosingElement()) {
146 // Deliberately empty.
152 if (node_name
== "failure" && xml_reader
.IsClosingElement())
153 state
= STATE_TESTCASE
;
158 // If we are here and there are still XML elements, the file has wrong
164 *crashed
= (state
!= STATE_END
);