xref: /aosp_15_r20/external/cronet/base/test/gtest_xml_util.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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