1*6777b538SAndroid Build Coastguard Worker // Copyright 2013 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/test/gtest_xml_util.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include "base/base64.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/test/gtest_util.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/test/launcher/test_launcher.h"
15*6777b538SAndroid Build Coastguard Worker #include "third_party/libxml/chromium/libxml_utils.h"
16*6777b538SAndroid Build Coastguard Worker #include "third_party/libxml/chromium/xml_reader.h"
17*6777b538SAndroid Build Coastguard Worker
18*6777b538SAndroid Build Coastguard Worker namespace base {
19*6777b538SAndroid Build Coastguard Worker
20*6777b538SAndroid Build Coastguard Worker namespace {
21*6777b538SAndroid Build Coastguard Worker
22*6777b538SAndroid Build Coastguard Worker // No-op error handler that replaces libxml's default, which writes to stderr.
23*6777b538SAndroid Build Coastguard Worker // The test launcher's worker threads speculatively parse results XML to detect
24*6777b538SAndroid Build Coastguard Worker // timeouts in the processes they manage, so logging parsing errors could be
25*6777b538SAndroid Build Coastguard Worker // noisy (e.g., crbug.com/1466897).
NullXmlErrorFunc(void * context,const char * message,...)26*6777b538SAndroid Build Coastguard Worker void NullXmlErrorFunc(void* context, const char* message, ...) {}
27*6777b538SAndroid Build Coastguard Worker
28*6777b538SAndroid Build Coastguard Worker } // namespace
29*6777b538SAndroid Build Coastguard Worker
30*6777b538SAndroid Build Coastguard Worker struct Link {
31*6777b538SAndroid Build Coastguard Worker // The name of the test case.
32*6777b538SAndroid Build Coastguard Worker std::string name;
33*6777b538SAndroid Build Coastguard Worker // The name of the classname of the test.
34*6777b538SAndroid Build Coastguard Worker std::string classname;
35*6777b538SAndroid Build Coastguard Worker // The name of the link.
36*6777b538SAndroid Build Coastguard Worker std::string link_name;
37*6777b538SAndroid Build Coastguard Worker // The actual link.
38*6777b538SAndroid Build Coastguard Worker std::string link;
39*6777b538SAndroid Build Coastguard Worker };
40*6777b538SAndroid Build Coastguard Worker
41*6777b538SAndroid Build Coastguard Worker struct Property {
42*6777b538SAndroid Build Coastguard Worker // The name of the property.
43*6777b538SAndroid Build Coastguard Worker std::string name;
44*6777b538SAndroid Build Coastguard Worker // The value of the property.
45*6777b538SAndroid Build Coastguard Worker std::string value;
46*6777b538SAndroid Build Coastguard Worker };
47*6777b538SAndroid Build Coastguard Worker
48*6777b538SAndroid Build Coastguard Worker struct Tag {
49*6777b538SAndroid Build Coastguard Worker // The name of the test case.
50*6777b538SAndroid Build Coastguard Worker std::string name;
51*6777b538SAndroid Build Coastguard Worker // The name of the classname of the test.
52*6777b538SAndroid Build Coastguard Worker std::string classname;
53*6777b538SAndroid Build Coastguard Worker // The name of the tag.
54*6777b538SAndroid Build Coastguard Worker std::string tag_name;
55*6777b538SAndroid Build Coastguard Worker // The value of the tag.
56*6777b538SAndroid Build Coastguard Worker std::string tag_value;
57*6777b538SAndroid Build Coastguard Worker };
58*6777b538SAndroid Build Coastguard Worker
ProcessGTestOutput(const base::FilePath & output_file,std::vector<TestResult> * results,bool * crashed)59*6777b538SAndroid Build Coastguard Worker bool ProcessGTestOutput(const base::FilePath& output_file,
60*6777b538SAndroid Build Coastguard Worker std::vector<TestResult>* results,
61*6777b538SAndroid Build Coastguard Worker bool* crashed) {
62*6777b538SAndroid Build Coastguard Worker DCHECK(results);
63*6777b538SAndroid Build Coastguard Worker
64*6777b538SAndroid Build Coastguard Worker std::string xml_contents;
65*6777b538SAndroid Build Coastguard Worker if (!ReadFileToString(output_file, &xml_contents))
66*6777b538SAndroid Build Coastguard Worker return false;
67*6777b538SAndroid Build Coastguard Worker
68*6777b538SAndroid Build Coastguard Worker // Silence XML errors - otherwise they go to stderr.
69*6777b538SAndroid Build Coastguard Worker ScopedXmlErrorFunc error_func(nullptr, &NullXmlErrorFunc);
70*6777b538SAndroid Build Coastguard Worker
71*6777b538SAndroid Build Coastguard Worker XmlReader xml_reader;
72*6777b538SAndroid Build Coastguard Worker if (!xml_reader.Load(xml_contents))
73*6777b538SAndroid Build Coastguard Worker return false;
74*6777b538SAndroid Build Coastguard Worker
75*6777b538SAndroid Build Coastguard Worker enum {
76*6777b538SAndroid Build Coastguard Worker STATE_INIT,
77*6777b538SAndroid Build Coastguard Worker STATE_TESTSUITE,
78*6777b538SAndroid Build Coastguard Worker STATE_TESTCASE,
79*6777b538SAndroid Build Coastguard Worker STATE_TEST_RESULT,
80*6777b538SAndroid Build Coastguard Worker STATE_FAILURE,
81*6777b538SAndroid Build Coastguard Worker STATE_END,
82*6777b538SAndroid Build Coastguard Worker } state = STATE_INIT;
83*6777b538SAndroid Build Coastguard Worker
84*6777b538SAndroid Build Coastguard Worker std::vector<Link> links;
85*6777b538SAndroid Build Coastguard Worker
86*6777b538SAndroid Build Coastguard Worker std::vector<Property> properties;
87*6777b538SAndroid Build Coastguard Worker
88*6777b538SAndroid Build Coastguard Worker std::vector<Tag> tags;
89*6777b538SAndroid Build Coastguard Worker
90*6777b538SAndroid Build Coastguard Worker while (xml_reader.Read()) {
91*6777b538SAndroid Build Coastguard Worker xml_reader.SkipToElement();
92*6777b538SAndroid Build Coastguard Worker std::string node_name(xml_reader.NodeName());
93*6777b538SAndroid Build Coastguard Worker
94*6777b538SAndroid Build Coastguard Worker switch (state) {
95*6777b538SAndroid Build Coastguard Worker case STATE_INIT:
96*6777b538SAndroid Build Coastguard Worker if (node_name == "testsuites" && !xml_reader.IsClosingElement())
97*6777b538SAndroid Build Coastguard Worker state = STATE_TESTSUITE;
98*6777b538SAndroid Build Coastguard Worker else
99*6777b538SAndroid Build Coastguard Worker return false;
100*6777b538SAndroid Build Coastguard Worker break;
101*6777b538SAndroid Build Coastguard Worker case STATE_TESTSUITE:
102*6777b538SAndroid Build Coastguard Worker if (node_name == "testsuites" && xml_reader.IsClosingElement())
103*6777b538SAndroid Build Coastguard Worker state = STATE_END;
104*6777b538SAndroid Build Coastguard Worker else if (node_name == "testsuite" && !xml_reader.IsClosingElement())
105*6777b538SAndroid Build Coastguard Worker state = STATE_TESTCASE;
106*6777b538SAndroid Build Coastguard Worker else
107*6777b538SAndroid Build Coastguard Worker return false;
108*6777b538SAndroid Build Coastguard Worker break;
109*6777b538SAndroid Build Coastguard Worker case STATE_TESTCASE:
110*6777b538SAndroid Build Coastguard Worker if (node_name == "testsuite" && xml_reader.IsClosingElement()) {
111*6777b538SAndroid Build Coastguard Worker state = STATE_TESTSUITE;
112*6777b538SAndroid Build Coastguard Worker } else if (node_name == "x-teststart" &&
113*6777b538SAndroid Build Coastguard Worker !xml_reader.IsClosingElement()) {
114*6777b538SAndroid Build Coastguard Worker // This is our custom extension that helps recognize which test was
115*6777b538SAndroid Build Coastguard Worker // running when the test binary crashed.
116*6777b538SAndroid Build Coastguard Worker TestResult result;
117*6777b538SAndroid Build Coastguard Worker
118*6777b538SAndroid Build Coastguard Worker std::string test_case_name;
119*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("classname", &test_case_name))
120*6777b538SAndroid Build Coastguard Worker return false;
121*6777b538SAndroid Build Coastguard Worker std::string test_name;
122*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("name", &test_name))
123*6777b538SAndroid Build Coastguard Worker return false;
124*6777b538SAndroid Build Coastguard Worker result.full_name = FormatFullTestName(test_case_name, test_name);
125*6777b538SAndroid Build Coastguard Worker
126*6777b538SAndroid Build Coastguard Worker result.elapsed_time = TimeDelta();
127*6777b538SAndroid Build Coastguard Worker
128*6777b538SAndroid Build Coastguard Worker std::string test_timestamp_str;
129*6777b538SAndroid Build Coastguard Worker Time test_timestamp;
130*6777b538SAndroid Build Coastguard Worker if (xml_reader.NodeAttribute("timestamp", &test_timestamp_str) &&
131*6777b538SAndroid Build Coastguard Worker Time::FromString(test_timestamp_str.c_str(), &test_timestamp)) {
132*6777b538SAndroid Build Coastguard Worker result.timestamp = test_timestamp;
133*6777b538SAndroid Build Coastguard Worker }
134*6777b538SAndroid Build Coastguard Worker
135*6777b538SAndroid Build Coastguard Worker // Assume the test crashed - we can correct that later.
136*6777b538SAndroid Build Coastguard Worker result.status = TestResult::TEST_CRASH;
137*6777b538SAndroid Build Coastguard Worker
138*6777b538SAndroid Build Coastguard Worker results->push_back(result);
139*6777b538SAndroid Build Coastguard Worker } else if (node_name == "testcase" && !xml_reader.IsClosingElement()) {
140*6777b538SAndroid Build Coastguard Worker std::string test_status;
141*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("status", &test_status))
142*6777b538SAndroid Build Coastguard Worker return false;
143*6777b538SAndroid Build Coastguard Worker
144*6777b538SAndroid Build Coastguard Worker if (test_status != "run" && test_status != "notrun")
145*6777b538SAndroid Build Coastguard Worker return false;
146*6777b538SAndroid Build Coastguard Worker if (test_status != "run")
147*6777b538SAndroid Build Coastguard Worker break;
148*6777b538SAndroid Build Coastguard Worker
149*6777b538SAndroid Build Coastguard Worker TestResult result;
150*6777b538SAndroid Build Coastguard Worker
151*6777b538SAndroid Build Coastguard Worker std::string test_case_name;
152*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("classname", &test_case_name))
153*6777b538SAndroid Build Coastguard Worker return false;
154*6777b538SAndroid Build Coastguard Worker std::string test_name;
155*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("name", &test_name))
156*6777b538SAndroid Build Coastguard Worker return false;
157*6777b538SAndroid Build Coastguard Worker result.full_name = test_case_name + "." + test_name;
158*6777b538SAndroid Build Coastguard Worker
159*6777b538SAndroid Build Coastguard Worker std::string test_time_str;
160*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("time", &test_time_str))
161*6777b538SAndroid Build Coastguard Worker return false;
162*6777b538SAndroid Build Coastguard Worker result.elapsed_time = Microseconds(
163*6777b538SAndroid Build Coastguard Worker static_cast<int64_t>(strtod(test_time_str.c_str(), nullptr) *
164*6777b538SAndroid Build Coastguard Worker Time::kMicrosecondsPerSecond));
165*6777b538SAndroid Build Coastguard Worker
166*6777b538SAndroid Build Coastguard Worker // The timestamp attribute records the local date and time of the test
167*6777b538SAndroid Build Coastguard Worker // execution. It might be missing in the xml generated by older
168*6777b538SAndroid Build Coastguard Worker // version of test launcher or gtest.
169*6777b538SAndroid Build Coastguard Worker // https://github.com/google/googletest/blob/main/docs/advanced.md#generating-an-xml-report
170*6777b538SAndroid Build Coastguard Worker std::string test_timestamp_str;
171*6777b538SAndroid Build Coastguard Worker Time test_timestamp;
172*6777b538SAndroid Build Coastguard Worker if (xml_reader.NodeAttribute("timestamp", &test_timestamp_str) &&
173*6777b538SAndroid Build Coastguard Worker Time::FromString(test_timestamp_str.c_str(), &test_timestamp)) {
174*6777b538SAndroid Build Coastguard Worker result.timestamp = test_timestamp;
175*6777b538SAndroid Build Coastguard Worker }
176*6777b538SAndroid Build Coastguard Worker
177*6777b538SAndroid Build Coastguard Worker result.status = TestResult::TEST_SUCCESS;
178*6777b538SAndroid Build Coastguard Worker
179*6777b538SAndroid Build Coastguard Worker if (!results->empty() &&
180*6777b538SAndroid Build Coastguard Worker results->back().full_name == result.full_name &&
181*6777b538SAndroid Build Coastguard Worker results->back().status == TestResult::TEST_CRASH) {
182*6777b538SAndroid Build Coastguard Worker // Erase the fail-safe "crashed" result - now we know the test did
183*6777b538SAndroid Build Coastguard Worker // not crash.
184*6777b538SAndroid Build Coastguard Worker results->pop_back();
185*6777b538SAndroid Build Coastguard Worker }
186*6777b538SAndroid Build Coastguard Worker
187*6777b538SAndroid Build Coastguard Worker for (const Link& link : links) {
188*6777b538SAndroid Build Coastguard Worker if (link.name == test_name && link.classname == test_case_name) {
189*6777b538SAndroid Build Coastguard Worker result.AddLink(link.link_name, link.link);
190*6777b538SAndroid Build Coastguard Worker }
191*6777b538SAndroid Build Coastguard Worker }
192*6777b538SAndroid Build Coastguard Worker links.clear();
193*6777b538SAndroid Build Coastguard Worker for (const Property& property : properties) {
194*6777b538SAndroid Build Coastguard Worker result.AddProperty(property.name, property.value);
195*6777b538SAndroid Build Coastguard Worker }
196*6777b538SAndroid Build Coastguard Worker properties.clear();
197*6777b538SAndroid Build Coastguard Worker for (const Tag& tag : tags) {
198*6777b538SAndroid Build Coastguard Worker if (tag.name == test_name && tag.classname == test_case_name) {
199*6777b538SAndroid Build Coastguard Worker result.AddTag(tag.tag_name, tag.tag_value);
200*6777b538SAndroid Build Coastguard Worker }
201*6777b538SAndroid Build Coastguard Worker }
202*6777b538SAndroid Build Coastguard Worker tags.clear();
203*6777b538SAndroid Build Coastguard Worker results->push_back(result);
204*6777b538SAndroid Build Coastguard Worker } else if (node_name == "link" && !xml_reader.IsClosingElement()) {
205*6777b538SAndroid Build Coastguard Worker Link link;
206*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("name", &link.name))
207*6777b538SAndroid Build Coastguard Worker return false;
208*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("classname", &link.classname))
209*6777b538SAndroid Build Coastguard Worker return false;
210*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("link_name", &link.link_name))
211*6777b538SAndroid Build Coastguard Worker return false;
212*6777b538SAndroid Build Coastguard Worker if (!xml_reader.ReadElementContent(&link.link))
213*6777b538SAndroid Build Coastguard Worker return false;
214*6777b538SAndroid Build Coastguard Worker links.push_back(link);
215*6777b538SAndroid Build Coastguard Worker } else if (node_name == "link" && xml_reader.IsClosingElement()) {
216*6777b538SAndroid Build Coastguard Worker // Deliberately empty.
217*6777b538SAndroid Build Coastguard Worker } else if (node_name == "tag" && !xml_reader.IsClosingElement()) {
218*6777b538SAndroid Build Coastguard Worker Tag tag;
219*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("name", &tag.name))
220*6777b538SAndroid Build Coastguard Worker return false;
221*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("classname", &tag.classname))
222*6777b538SAndroid Build Coastguard Worker return false;
223*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("tag_name", &tag.tag_name))
224*6777b538SAndroid Build Coastguard Worker return false;
225*6777b538SAndroid Build Coastguard Worker if (!xml_reader.ReadElementContent(&tag.tag_value))
226*6777b538SAndroid Build Coastguard Worker return false;
227*6777b538SAndroid Build Coastguard Worker tags.push_back(tag);
228*6777b538SAndroid Build Coastguard Worker } else if (node_name == "tag" && xml_reader.IsClosingElement()) {
229*6777b538SAndroid Build Coastguard Worker // Deliberately empty.
230*6777b538SAndroid Build Coastguard Worker } else if (node_name == "properties" &&
231*6777b538SAndroid Build Coastguard Worker !xml_reader.IsClosingElement()) {
232*6777b538SAndroid Build Coastguard Worker // Deliberately empty, begin of the test properties.
233*6777b538SAndroid Build Coastguard Worker } else if (node_name == "property" && !xml_reader.IsClosingElement()) {
234*6777b538SAndroid Build Coastguard Worker Property property;
235*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("name", &property.name))
236*6777b538SAndroid Build Coastguard Worker return false;
237*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("value", &property.value))
238*6777b538SAndroid Build Coastguard Worker return false;
239*6777b538SAndroid Build Coastguard Worker properties.push_back(property);
240*6777b538SAndroid Build Coastguard Worker } else if (node_name == "properties" && xml_reader.IsClosingElement()) {
241*6777b538SAndroid Build Coastguard Worker // Deliberately empty, end of the test properties.
242*6777b538SAndroid Build Coastguard Worker } else if (node_name == "failure" && !xml_reader.IsClosingElement()) {
243*6777b538SAndroid Build Coastguard Worker std::string failure_message;
244*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("message", &failure_message))
245*6777b538SAndroid Build Coastguard Worker return false;
246*6777b538SAndroid Build Coastguard Worker
247*6777b538SAndroid Build Coastguard Worker DCHECK(!results->empty());
248*6777b538SAndroid Build Coastguard Worker results->back().status = TestResult::TEST_FAILURE;
249*6777b538SAndroid Build Coastguard Worker
250*6777b538SAndroid Build Coastguard Worker state = STATE_FAILURE;
251*6777b538SAndroid Build Coastguard Worker } else if (node_name == "testcase" && xml_reader.IsClosingElement()) {
252*6777b538SAndroid Build Coastguard Worker // Deliberately empty.
253*6777b538SAndroid Build Coastguard Worker } else if (node_name == "x-test-result-part" &&
254*6777b538SAndroid Build Coastguard Worker !xml_reader.IsClosingElement()) {
255*6777b538SAndroid Build Coastguard Worker std::string result_type;
256*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("type", &result_type))
257*6777b538SAndroid Build Coastguard Worker return false;
258*6777b538SAndroid Build Coastguard Worker
259*6777b538SAndroid Build Coastguard Worker std::string file_name;
260*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("file", &file_name))
261*6777b538SAndroid Build Coastguard Worker return false;
262*6777b538SAndroid Build Coastguard Worker
263*6777b538SAndroid Build Coastguard Worker std::string line_number_str;
264*6777b538SAndroid Build Coastguard Worker if (!xml_reader.NodeAttribute("line", &line_number_str))
265*6777b538SAndroid Build Coastguard Worker return false;
266*6777b538SAndroid Build Coastguard Worker
267*6777b538SAndroid Build Coastguard Worker int line_number;
268*6777b538SAndroid Build Coastguard Worker if (!StringToInt(line_number_str, &line_number))
269*6777b538SAndroid Build Coastguard Worker return false;
270*6777b538SAndroid Build Coastguard Worker
271*6777b538SAndroid Build Coastguard Worker TestResultPart::Type type;
272*6777b538SAndroid Build Coastguard Worker if (!TestResultPart::TypeFromString(result_type, &type))
273*6777b538SAndroid Build Coastguard Worker return false;
274*6777b538SAndroid Build Coastguard Worker
275*6777b538SAndroid Build Coastguard Worker TestResultPart test_result_part;
276*6777b538SAndroid Build Coastguard Worker test_result_part.type = type;
277*6777b538SAndroid Build Coastguard Worker test_result_part.file_name = file_name,
278*6777b538SAndroid Build Coastguard Worker test_result_part.line_number = line_number;
279*6777b538SAndroid Build Coastguard Worker DCHECK(!results->empty());
280*6777b538SAndroid Build Coastguard Worker results->back().test_result_parts.push_back(test_result_part);
281*6777b538SAndroid Build Coastguard Worker
282*6777b538SAndroid Build Coastguard Worker state = STATE_TEST_RESULT;
283*6777b538SAndroid Build Coastguard Worker } else {
284*6777b538SAndroid Build Coastguard Worker return false;
285*6777b538SAndroid Build Coastguard Worker }
286*6777b538SAndroid Build Coastguard Worker break;
287*6777b538SAndroid Build Coastguard Worker case STATE_TEST_RESULT:
288*6777b538SAndroid Build Coastguard Worker if (node_name == "summary" && !xml_reader.IsClosingElement()) {
289*6777b538SAndroid Build Coastguard Worker std::string summary;
290*6777b538SAndroid Build Coastguard Worker if (!xml_reader.ReadElementContent(&summary))
291*6777b538SAndroid Build Coastguard Worker return false;
292*6777b538SAndroid Build Coastguard Worker
293*6777b538SAndroid Build Coastguard Worker if (!Base64Decode(summary, &summary))
294*6777b538SAndroid Build Coastguard Worker return false;
295*6777b538SAndroid Build Coastguard Worker
296*6777b538SAndroid Build Coastguard Worker DCHECK(!results->empty());
297*6777b538SAndroid Build Coastguard Worker DCHECK(!results->back().test_result_parts.empty());
298*6777b538SAndroid Build Coastguard Worker results->back().test_result_parts.back().summary = summary;
299*6777b538SAndroid Build Coastguard Worker } else if (node_name == "summary" && xml_reader.IsClosingElement()) {
300*6777b538SAndroid Build Coastguard Worker } else if (node_name == "message" && !xml_reader.IsClosingElement()) {
301*6777b538SAndroid Build Coastguard Worker std::string message;
302*6777b538SAndroid Build Coastguard Worker if (!xml_reader.ReadElementContent(&message))
303*6777b538SAndroid Build Coastguard Worker return false;
304*6777b538SAndroid Build Coastguard Worker
305*6777b538SAndroid Build Coastguard Worker if (!Base64Decode(message, &message))
306*6777b538SAndroid Build Coastguard Worker return false;
307*6777b538SAndroid Build Coastguard Worker
308*6777b538SAndroid Build Coastguard Worker DCHECK(!results->empty());
309*6777b538SAndroid Build Coastguard Worker DCHECK(!results->back().test_result_parts.empty());
310*6777b538SAndroid Build Coastguard Worker results->back().test_result_parts.back().message = message;
311*6777b538SAndroid Build Coastguard Worker } else if (node_name == "message" && xml_reader.IsClosingElement()) {
312*6777b538SAndroid Build Coastguard Worker } else if (node_name == "x-test-result-part" &&
313*6777b538SAndroid Build Coastguard Worker xml_reader.IsClosingElement()) {
314*6777b538SAndroid Build Coastguard Worker state = STATE_TESTCASE;
315*6777b538SAndroid Build Coastguard Worker } else {
316*6777b538SAndroid Build Coastguard Worker return false;
317*6777b538SAndroid Build Coastguard Worker }
318*6777b538SAndroid Build Coastguard Worker break;
319*6777b538SAndroid Build Coastguard Worker case STATE_FAILURE:
320*6777b538SAndroid Build Coastguard Worker if (node_name == "failure" && xml_reader.IsClosingElement())
321*6777b538SAndroid Build Coastguard Worker state = STATE_TESTCASE;
322*6777b538SAndroid Build Coastguard Worker else
323*6777b538SAndroid Build Coastguard Worker return false;
324*6777b538SAndroid Build Coastguard Worker break;
325*6777b538SAndroid Build Coastguard Worker case STATE_END:
326*6777b538SAndroid Build Coastguard Worker // If we are here and there are still XML elements, the file has wrong
327*6777b538SAndroid Build Coastguard Worker // format.
328*6777b538SAndroid Build Coastguard Worker return false;
329*6777b538SAndroid Build Coastguard Worker }
330*6777b538SAndroid Build Coastguard Worker }
331*6777b538SAndroid Build Coastguard Worker
332*6777b538SAndroid Build Coastguard Worker if (crashed) {
333*6777b538SAndroid Build Coastguard Worker *crashed = (state != STATE_END);
334*6777b538SAndroid Build Coastguard Worker }
335*6777b538SAndroid Build Coastguard Worker return true;
336*6777b538SAndroid Build Coastguard Worker }
337*6777b538SAndroid Build Coastguard Worker
338*6777b538SAndroid Build Coastguard Worker } // namespace base
339