#3684: bug fix in time accumulation and addition of unit test from kruset
This commit is contained in:
parent
9f56a76361
commit
c11b088006
|
@ -37,6 +37,8 @@
|
||||||
Library for reading and manipulating Ant JUnit XML result files.
|
Library for reading and manipulating Ant JUnit XML result files.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import cStringIO
|
import cStringIO
|
||||||
|
@ -180,6 +182,7 @@ class Result(object):
|
||||||
self.num_errors += r.num_errors
|
self.num_errors += r.num_errors
|
||||||
self.num_failures += r.num_failures
|
self.num_failures += r.num_failures
|
||||||
self.num_tests += r.num_tests
|
self.num_tests += r.num_tests
|
||||||
|
self.time += r.time
|
||||||
self.test_case_results.extend(r.test_case_results)
|
self.test_case_results.extend(r.test_case_results)
|
||||||
if r.system_out:
|
if r.system_out:
|
||||||
self.system_out += '\n'+r.system_out
|
self.system_out += '\n'+r.system_out
|
||||||
|
@ -240,7 +243,7 @@ def _load_suite_results(test_suite_name, test_suite, result):
|
||||||
elif not classname.startswith(result.name):
|
elif not classname.startswith(result.name):
|
||||||
classname = "%s.%s"%(result.name,classname)
|
classname = "%s.%s"%(result.name,classname)
|
||||||
|
|
||||||
time = node.getAttribute('time') or 0.0
|
time = float(node.getAttribute('time')) or 0.0
|
||||||
tc_result = TestCaseResult("%s/%s"%(test_suite_name,name))
|
tc_result = TestCaseResult("%s/%s"%(test_suite_name,name))
|
||||||
tc_result.classname = classname
|
tc_result.classname = classname
|
||||||
tc_result.time = time
|
tc_result.time = time
|
||||||
|
@ -310,14 +313,14 @@ def read(test_file, test_name):
|
||||||
try:
|
try:
|
||||||
xml_str = _read_file_safe_xml(test_file)
|
xml_str = _read_file_safe_xml(test_file)
|
||||||
if not xml_str.strip():
|
if not xml_str.strip():
|
||||||
print "WARN: test result file is empty [%s]"%(test_file)
|
print("WARN: test result file is empty [%s]"%(test_file))
|
||||||
return Result(test_name, 0, 0, 0)
|
return Result(test_name, 0, 0, 0)
|
||||||
test_suites = parseString(xml_str).getElementsByTagName('testsuite')
|
test_suites = parseString(xml_str).getElementsByTagName('testsuite')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print "WARN: cannot read test result file [%s]: %s"%(test_file, str(e))
|
print("WARN: cannot read test result file [%s]: %s"%(test_file, str(e)))
|
||||||
return Result(test_name, 0, 0, 0)
|
return Result(test_name, 0, 0, 0)
|
||||||
if not test_suites:
|
if not test_suites:
|
||||||
print "WARN: test result file [%s] contains no results"%(test_file)
|
print("WARN: test result file [%s] contains no results"%(test_file))
|
||||||
return Result(test_name, 0, 0, 0)
|
return Result(test_name, 0, 0, 0)
|
||||||
|
|
||||||
results = Result(test_name, 0, 0, 0)
|
results = Result(test_name, 0, 0, 0)
|
||||||
|
@ -328,7 +331,7 @@ def read(test_file, test_name):
|
||||||
err, fail, tests = [string.atoi(val) for val in vals]
|
err, fail, tests = [string.atoi(val) for val in vals]
|
||||||
|
|
||||||
result = Result(test_name, err, fail, tests)
|
result = Result(test_name, err, fail, tests)
|
||||||
result.time = test_suite.getAttribute('time') or 0.0
|
result.time = float(test_suite.getAttribute('time')) or 0.0
|
||||||
|
|
||||||
# Create a prefix based on the test result filename. The idea is to
|
# Create a prefix based on the test result filename. The idea is to
|
||||||
# disambiguate the case when tests of the same name are provided in
|
# disambiguate the case when tests of the same name are provided in
|
||||||
|
@ -447,5 +450,5 @@ def print_summary(junit_results, runner_name='ROSUNIT'):
|
||||||
else:
|
else:
|
||||||
buff.write(" * FAILURES: 0\n")
|
buff.write(" * FAILURES: 0\n")
|
||||||
|
|
||||||
print buff.getvalue()
|
print(buff.getvalue())
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,189 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# Software License Agreement (BSD License)
|
||||||
|
#
|
||||||
|
# Copyright (c) 2008, Willow Garage, Inc.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above
|
||||||
|
# copyright notice, this list of conditions and the following
|
||||||
|
# disclaimer in the documentation and/or other materials provided
|
||||||
|
# with the distribution.
|
||||||
|
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived
|
||||||
|
# from this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
# Revision $Id: $
|
||||||
|
|
||||||
|
import os
|
||||||
|
import io
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
junitxml = None
|
||||||
|
|
||||||
|
## Basic test of xmlresult functionality of reading gtest xml files and
|
||||||
|
## summarizing their results into a new file.
|
||||||
|
class MockResult():
|
||||||
|
def __init__(self, directory, filename, suites = [], noSuitesRoot = False):
|
||||||
|
self.filename = os.path.join(directory, filename)
|
||||||
|
self.suites = suites
|
||||||
|
# whether to suppress <testsuites> root node
|
||||||
|
self.noSuitesRoot = noSuitesRoot
|
||||||
|
|
||||||
|
class MockSuite():
|
||||||
|
def __init__(self, cases, name, tests = 0, errors = 0, fail = 0, time = 1):
|
||||||
|
self.cases = cases
|
||||||
|
self.tests = tests
|
||||||
|
self.time = time
|
||||||
|
self.fail = fail
|
||||||
|
self.errors = errors
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
|
||||||
|
class MockCase():
|
||||||
|
def __init__(self, name, errorList = [], classname="", time = 1):
|
||||||
|
self.classname = classname
|
||||||
|
self.name = name
|
||||||
|
self.time = time
|
||||||
|
self.errorList = errorList
|
||||||
|
|
||||||
|
class MockErrorType(Exception):
|
||||||
|
def __init__(self, value, etype = ''):
|
||||||
|
self.value = value
|
||||||
|
self.__name__ = value
|
||||||
|
self.type = etype
|
||||||
|
|
||||||
|
def _writeMockResultFile(result):
|
||||||
|
"writes a test result as a gtest compatible test runner would do"
|
||||||
|
with open(result.filename, 'w') as f:
|
||||||
|
f.write(u"""<?xml version="1.0" encoding="UTF-8"?>""")
|
||||||
|
if len(result.suites) > 1 or result.noSuitesRoot == False:
|
||||||
|
f.write(u"""<testsuites>\n""")
|
||||||
|
for suite in result.suites:
|
||||||
|
f.write('<testsuite tests="'+str(suite.tests)+'" failures="'+str(suite.fail)+'" time="'+str(suite.time)+'" errors="'+str(suite.errors)+'" name="'+suite.name+'">\n')
|
||||||
|
for case in suite.cases:
|
||||||
|
f.write('<testcase name="'+case.name+'" status="run" time="'+str(case.time)+'" classname="'+case.classname+'">\n')
|
||||||
|
for error in case.errorList:
|
||||||
|
f.write('<failure message="'+error.value+'" type="'+error.value+'"/>\n')
|
||||||
|
f.write('</testcase>\n')
|
||||||
|
f.write('</testsuite>\n')
|
||||||
|
if len(result.suites) > 1 or result.noSuitesRoot == False:
|
||||||
|
f.write(u"""</testsuites>\n""")
|
||||||
|
|
||||||
|
|
||||||
|
class XmlResultTestRead(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
# lazy-import to get coverage
|
||||||
|
global junitxml
|
||||||
|
if junitxml is None:
|
||||||
|
import rosunit.junitxml
|
||||||
|
junitxml = rosunit.junitxml
|
||||||
|
|
||||||
|
self.directory = tempfile.mkdtemp()
|
||||||
|
|
||||||
|
# setting up mock results as dict so results can be checked individually
|
||||||
|
self.mockresults={
|
||||||
|
"empty": MockResult(self.directory, "empty.xml", []),
|
||||||
|
"emptysuite": MockResult(self.directory, "emptysuite.xml", [MockSuite([], "emptySuite", 0, 0, 0, 0)]),
|
||||||
|
"succ1": MockResult(self.directory, "succ1.xml", [MockSuite([MockCase("succCase")],"succ1suite", 1, 0, 0, 1)]),
|
||||||
|
"err1": MockResult(self.directory, "err1.xml", [MockSuite([MockCase("errCase")],"err1suite", 1, 1, 0, 1)]),
|
||||||
|
"fail1": MockResult(self.directory, "fail1.xml", [MockSuite([MockCase("failCase")],"fail1suite", 1, 0, 1, 1)]),
|
||||||
|
"noroot": MockResult(self.directory, "succ1.xml", [MockSuite([MockCase("succCase")],"succ1suite", 1, 0, 0, 1)], noSuitesRoot = True),
|
||||||
|
"multicase": MockResult(self.directory,
|
||||||
|
"multicase.xml",
|
||||||
|
[MockSuite([MockCase("succCase"),
|
||||||
|
MockCase("errCase"),
|
||||||
|
MockCase("failCase")],
|
||||||
|
"succ1suite", 3, 1, 1, time = 3)]),
|
||||||
|
"multisuite": MockResult(self.directory,
|
||||||
|
"multisuite.xml",
|
||||||
|
[MockSuite([MockCase("succCase")],"succ1suite", 1, 0, 0, 1),
|
||||||
|
MockSuite([MockCase("errCase")],"err1suite", 1, 1, 0, 1),
|
||||||
|
MockSuite([MockCase("failCase")],"fail1suite", 1, 0, 1, 1)])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for name, result in self.mockresults.items():
|
||||||
|
_writeMockResultFile(result)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
shutil.rmtree(self.directory)
|
||||||
|
#pass
|
||||||
|
|
||||||
|
def testReadNoSuites(self):
|
||||||
|
result = junitxml.read(self.mockresults["empty"].filename, "fooname")
|
||||||
|
self.assert_(result is not None)
|
||||||
|
self.assertEquals(0.0, result.time)
|
||||||
|
self.assertEquals(0, result.num_tests)
|
||||||
|
self.assertEquals(0, result.num_errors)
|
||||||
|
self.assertEquals(0, result.num_failures)
|
||||||
|
|
||||||
|
def testReadEmptySuite(self):
|
||||||
|
result = junitxml.read(self.mockresults["emptysuite"].filename, "fooname")
|
||||||
|
self.assert_(result is not None)
|
||||||
|
self.assertEquals(0.0, result.time)
|
||||||
|
self.assertEquals(0, result.num_tests)
|
||||||
|
self.assertEquals(0, result.num_errors)
|
||||||
|
self.assertEquals(0, result.num_failures)
|
||||||
|
|
||||||
|
def testReadSuccess(self):
|
||||||
|
result = junitxml.read(self.mockresults["succ1"].filename, "fooname")
|
||||||
|
self.assert_(result is not None)
|
||||||
|
self.assertEquals(1.0, result.time)
|
||||||
|
self.assertEquals(1, result.num_tests)
|
||||||
|
self.assertEquals(0, result.num_errors)
|
||||||
|
self.assertEquals(0, result.num_failures)
|
||||||
|
|
||||||
|
def testReadError(self):
|
||||||
|
result = junitxml.read(self.mockresults["err1"].filename, "fooname")
|
||||||
|
self.assert_(result is not None)
|
||||||
|
self.assertEquals(1.0, result.time)
|
||||||
|
self.assertEquals(1, result.num_tests)
|
||||||
|
self.assertEquals(1, result.num_errors)
|
||||||
|
self.assertEquals(0, result.num_failures)
|
||||||
|
|
||||||
|
def testReadFail(self):
|
||||||
|
result = junitxml.read(self.mockresults["fail1"].filename, "fooname")
|
||||||
|
self.assert_(result is not None)
|
||||||
|
self.assertEquals(1.0, result.time)
|
||||||
|
self.assertEquals(1, result.num_tests)
|
||||||
|
self.assertEquals(0, result.num_errors)
|
||||||
|
self.assertEquals(1, result.num_failures)
|
||||||
|
|
||||||
|
def testReadMulticase(self):
|
||||||
|
result = junitxml.read(self.mockresults["multicase"].filename, "fooname")
|
||||||
|
self.assert_(result is not None)
|
||||||
|
self.assertEquals(3.0, result.time)
|
||||||
|
self.assertEquals(3, result.num_tests)
|
||||||
|
self.assertEquals(1, result.num_errors)
|
||||||
|
self.assertEquals(1, result.num_failures)
|
||||||
|
|
||||||
|
def testReadMultisuite(self):
|
||||||
|
result = junitxml.read(self.mockresults["multisuite"].filename, "fooname")
|
||||||
|
self.assert_(result is not None)
|
||||||
|
self.assertEquals(3.0, result.time)
|
||||||
|
self.assertEquals(3, result.num_tests)
|
||||||
|
self.assertEquals(1, result.num_errors)
|
||||||
|
self.assertEquals(1, result.num_failures)
|
Loading…
Reference in New Issue