1# -*- coding: utf-8 -*- 2# Copyright 2010-2018, Google Inc. 3# All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions are 7# met: 8# 9# * Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# * Redistributions in binary form must reproduce the above 12# copyright notice, this list of conditions and the following disclaimer 13# in the documentation and/or other materials provided with the 14# distribution. 15# * Neither the name of Google Inc. nor the names of its 16# contributors may be used to endorse or promote products derived from 17# this software without specific prior written permission. 18# 19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31"""Converting gtest result xml to python object. 32 33The gtest can output test result as xml file. Following class can parse it and 34store as python object. 35""" 36 37__author__ = "nona" 38 39import io 40import logging 41from xml.etree import ElementTree 42 43 44class Failure(object): 45 """Corresponding to failure element in test output xml.""" 46 47 def __init__(self, message, contents): 48 self.message = message 49 self.contents = contents 50 51 @classmethod 52 def CreateFromXMLElement(cls, element): 53 return cls(element.get('message'), element.text) 54 55 56class TestCase(object): 57 """Corresponding to testcase element in test output xml.""" 58 59 def __init__(self, name, status, time, classname, failures): 60 self.name = name 61 self.status = status 62 self.time = time 63 self.classname = classname 64 self.failures = failures 65 66 @classmethod 67 def CreateFromXMLElement(cls, element): 68 failures = [Failure.CreateFromXMLElement(failure) for failure in element] 69 return cls(element.get('name'), element.get('status'), 70 element.get('time'), element.get('classname'), failures) 71 72 73class TestSuite(object): 74 """Corresponding to testsuite element in test output xml.""" 75 76 def __init__(self, name, total, fail_num, disabled_num, error_num, time, 77 testcases): 78 self.name = name 79 self.total = int(total) 80 self.fail_num = int(fail_num) 81 self.disabled_num = int(disabled_num) 82 self.error_num = int(error_num) 83 self.time = time 84 self.testcases = testcases 85 86 def GetErrorSummary(self): 87 """Returns summarized error report text.""" 88 if self.fail_num == 0: 89 return '' 90 output = io.StringIO() 91 for testcase in self.testcases: 92 if not testcase.failures: 93 continue 94 print('%s.%s:' % (self.name, testcase.name), file=output) 95 for failure in testcase.failures: 96 print(failure.contents.encode('utf-8'), file=output) 97 return output.getvalue() 98 99 @classmethod 100 def CreateFromXMLElement(cls, element): 101 testcases = [TestCase.CreateFromXMLElement(testcase) for 102 testcase in element] 103 return cls(element.get('name'), element.get('tests'), 104 element.get('failures'), element.get('disabled'), 105 element.get('errors'), element.get('time'), testcases) 106 107 108class TestSuites(object): 109 """Corresponding to testsuites element in output xml.""" 110 111 def __init__(self, name, total, fail_num, disabled_num, error_num, time, 112 timestamp, testsuites): 113 self.name = name 114 self.total = int(total) 115 self.fail_num = int(fail_num) 116 self.disabled_num = int(disabled_num) 117 self.error_num = int(error_num) 118 self.timestamp = timestamp 119 self.time = time 120 self.testsuites = testsuites 121 122 def GetErrorSummary(self): 123 """Returns summarized unit test errors.""" 124 return '\n'.join(suite.GetErrorSummary() for suite in self.testsuites if 125 suite.fail_num != 0) 126 127 @classmethod 128 def CreateFromXMLElement(cls, element): 129 testsuites = [TestSuite.CreateFromXMLElement(testsuite) for 130 testsuite in element] 131 return cls(element.get('name'), element.get('tests'), 132 element.get('failures'), element.get('disabled'), 133 element.get('errors'), element.get('time'), 134 element.get('timestamp'), testsuites) 135 136 137def GetFromXMLFile(xml_fname): 138 """Create summary object from specified xml file.""" 139 try: 140 tree = ElementTree.parse(xml_fname) 141 except SyntaxError as reason: 142 logging.critical('XML Parse Failed: %s', reason) 143 return None 144 return TestSuites.CreateFromXMLElement(tree.getroot()) 145