From: Christian Van Wambeke Date: Tue, 23 Jan 2018 09:31:17 +0000 (+0100) Subject: move unittestpy outside obsolescent test dir X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=c456140cf388575f43f3cd815a8e2bf359077bb5;p=tools%2Fsat.git move unittestpy outside obsolescent test dir --- diff --git a/AllTestLauncherSat.py b/AllTestLauncherSat.py index 1a2be07..59f4fbd 100755 --- a/AllTestLauncherSat.py +++ b/AllTestLauncherSat.py @@ -73,7 +73,7 @@ def errPrint(aStr): sys.stderr.write(aStr + '\n') try: - import test.unittestpy.HTMLTestRunner as HTST + import unittestpy.HTMLTestRunner as HTST except: HTST = None errPrint(""" diff --git a/test/config/test_option_edit.py b/test/config/test_option_edit.py index a106791..c6674e9 100755 --- a/test/config/test_option_edit.py +++ b/test/config/test_option_edit.py @@ -24,7 +24,7 @@ import time import unittest from src.salomeTools import Sat -from test.unittestpy.tools import check_proc_existence_and_kill_multi +from unittestpy.tools import check_proc_existence_and_kill_multi sleep_time = 2 diff --git a/test/config/test_option_value.py b/test/config/test_option_value.py index 73cfd56..50a7d84 100755 --- a/test/config/test_option_value.py +++ b/test/config/test_option_value.py @@ -23,7 +23,7 @@ import platform import unittest from src.salomeTools import Sat -from test.unittestpy.tools import outRedirection +from unittestpy.tools import outRedirection class TestCase(unittest.TestCase): """sat config --value""" diff --git a/test/config/test_option_value_2.py b/test/config/test_option_value_2.py index 413c462..c11fee1 100755 --- a/test/config/test_option_value_2.py +++ b/test/config/test_option_value_2.py @@ -23,7 +23,7 @@ import platform import unittest from src.salomeTools import Sat -from test.unittestpy.tools import outRedirection +from unittestpy.tools import outRedirection class TestCase(unittest.TestCase): """sat config -v VARS.python""" diff --git a/test/jobs/test_jobs.py b/test/jobs/test_jobs.py index 0a673a7..1b22378 100755 --- a/test/jobs/test_jobs.py +++ b/test/jobs/test_jobs.py @@ -22,7 +22,7 @@ import sys import unittest from src.salomeTools import Sat -from test.unittestpy.tools import outRedirection +from unittestpy.tools import outRedirection class TestCase(unittest.TestCase): "Test the jobs command""" diff --git a/test/log/test_launch_browser.py b/test/log/test_launch_browser.py index 03d261f..a9c8be4 100755 --- a/test/log/test_launch_browser.py +++ b/test/log/test_launch_browser.py @@ -26,7 +26,7 @@ import io import unittest from src.salomeTools import Sat -from test.unittestpy.tools import check_proc_existence_and_kill_multi +from unittestpy.tools import check_proc_existence_and_kill_multi sleep_time = 2 diff --git a/test/log/test_launch_browser2.py b/test/log/test_launch_browser2.py index deaf65e..38a6184 100755 --- a/test/log/test_launch_browser2.py +++ b/test/log/test_launch_browser2.py @@ -24,7 +24,7 @@ import time import unittest from src.salomeTools import Sat -from test.unittestpy.tools import check_proc_existence_and_kill_multi +from unittestpy.tools import check_proc_existence_and_kill_multi sleep_time = 2 diff --git a/test/prepare/test_clean.py b/test/prepare/test_clean.py index c753f8d..08bb54f 100755 --- a/test/prepare/test_clean.py +++ b/test/prepare/test_clean.py @@ -23,8 +23,7 @@ import unittest from src.salomeTools import Sat import src.product - -from test.unittestpy.tools import outRedirection +from unittestpy.tools import outRedirection class TestCase(unittest.TestCase): """Test of the clean command""" diff --git a/test/prepare/test_patch.py b/test/prepare/test_patch.py index ad7db31..1dc24d4 100755 --- a/test/prepare/test_patch.py +++ b/test/prepare/test_patch.py @@ -24,7 +24,7 @@ import unittest from src.salomeTools import Sat import src.product -from test.unittestpy.tools import outRedirection +from unittestpy.tools import outRedirection class TestCase(unittest.TestCase): """Test of the patch command""" diff --git a/test/prepare/test_source.py b/test/prepare/test_source.py index f60badc..f7a053d 100755 --- a/test/prepare/test_source.py +++ b/test/prepare/test_source.py @@ -23,7 +23,7 @@ import unittest from src.salomeTools import Sat import src.product -from test.unittestpy.tools import outRedirection +from unittestpy.tools import outRedirection class TestCase(unittest.TestCase): """Test of the source command""" diff --git a/test/unittestpy/HTMLTestRunner.py b/test/unittestpy/HTMLTestRunner.py deleted file mode 100644 index 0439bf4..0000000 --- a/test/unittestpy/HTMLTestRunner.py +++ /dev/null @@ -1,824 +0,0 @@ -""" -A TestRunner for use with the Python unit testing framework. It -generates a HTML report to show the result at a glance. - -The simplest way to use this is to invoke its main method. E.g. - - import unittest - import HTMLTestRunner - - ... define your tests ... - - if __name__ == '__main__': - HTMLTestRunner.main() - - -For more customization options, instantiates a HTMLTestRunner object. -HTMLTestRunner is a counterpart to unittest's TextTestRunner. E.g. - - # output to a file - fp = file('my_report.html', 'wb') - runner = HTMLTestRunner.HTMLTestRunner( - stream=fp, - title='My unit test', - description='This demonstrates the report output by HTMLTestRunner.' - ) - - # Use an external stylesheet. - # See the Template_mixin class for more customizable options - runner.STYLESHEET_TMPL = '' - - # run the test - runner.run(my_test_suite) - - ------------------------------------------------------------------------- -Copyright (c) 2004-2007, Wai Yip Tung -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 Wai Yip Tung 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. -""" - -# URL: http://tungwaiyip.info/software/HTMLTestRunner.html - -__author__ = "Wai Yip Tung" -__version__ = "0.8.2" - - -""" -Change History - -Version 0.8.2 -* Show output inline instead of popup window (Viorel Lupu). - -Version in 0.8.1 -* Validated XHTML (Wolfgang Borgert). -* Added description of test classes and test cases. - -Version in 0.8.0 -* Define Template_mixin class for customization. -* Workaround a IE 6 bug that it does not treat - -%(heading)s -%(report)s -%(ending)s - - - -""" - # variables: (title, generator, stylesheet, heading, report, ending) - - - # ------------------------------------------------------------------------ - # Stylesheet - # - # alternatively use a for external style sheet, e.g. - # - - STYLESHEET_TMPL = """ - -""" - - - - # ------------------------------------------------------------------------ - # Heading - # - - HEADING_TMPL = """
-

%(title)s

-%(parameters)s -

%(description)s

-
- -""" # variables: (title, parameters, description) - - HEADING_ATTRIBUTE_TMPL = """

%(name)s: %(value)s

-""" # variables: (name, value) - - - - # ------------------------------------------------------------------------ - # Report - # - - REPORT_TMPL = """ -

Show -Summary -Failed -All -

- -------- - - - - - - - - -%(test_list)s - - - - - - - - -
Test Group/Test caseCountPassFailErrorView
Total%(count)s%(Pass)s%(fail)s%(error)s 
-""" # variables: (test_list, count, Pass, fail, error) - - REPORT_CLASS_TMPL = r""" - - %(desc)s - %(count)s - %(Pass)s - %(fail)s - %(error)s - Detail - -""" # variables: (style, desc, count, Pass, fail, error, cid) - - - REPORT_TEST_WITH_OUTPUT_TMPL = r""" - -
%(desc)s
- - - - - %(status)s - - - - - - -""" # variables: (tid, Class, style, desc, status) - - - REPORT_TEST_NO_OUTPUT_TMPL = r""" - -
%(desc)s
- %(status)s - -""" # variables: (tid, Class, style, desc, status) - - - REPORT_TEST_OUTPUT_TMPL = r""" -%(id)s: %(output)s -""" # variables: (id, output) - - - - # ------------------------------------------------------------------------ - # ENDING - # - - ENDING_TMPL = """
 
""" - -# -------------------- The end of the Template class ------------------- - - -TestResult = unittest.TestResult - -class _TestResult(TestResult): - # note: _TestResult is a pure representation of results. - # It lacks the output and reporting ability compares to unittest._TextTestResult. - - def __init__(self, verbosity=1): - TestResult.__init__(self) - self.stdout0 = None - self.stderr0 = None - self.success_count = 0 - self.failure_count = 0 - self.error_count = 0 - self.verbosity = verbosity - - # result is a list of result in 4 tuple - # ( - # result code (0: success; 1: fail; 2: error), - # TestCase object, - # Test output (byte string), - # stack trace, - # ) - self.result = [] - - - def startTest(self, test): - TestResult.startTest(self, test) - # just one buffer for both stdout and stderr - self.outputBuffer = StringIO.StringIO() - stdout_redirector.fp = self.outputBuffer - stderr_redirector.fp = self.outputBuffer - self.stdout0 = sys.stdout - self.stderr0 = sys.stderr - sys.stdout = stdout_redirector - sys.stderr = stderr_redirector - - - def complete_output(self): - """ - Disconnect output redirection and return buffer. - Safe to call multiple times. - """ - if self.stdout0: - sys.stdout = self.stdout0 - sys.stderr = self.stderr0 - self.stdout0 = None - self.stderr0 = None - return self.outputBuffer.getvalue() - - - def stopTest(self, test): - # Usually one of addSuccess, addError or addFailure would have been called. - # But there are some path in unittest that would bypass this. - # We must disconnect stdout in stopTest(), which is guaranteed to be called. - self.complete_output() - - - def addSuccess(self, test): - self.success_count += 1 - TestResult.addSuccess(self, test) - output = self.complete_output() - self.result.append((0, test, output, '')) - if self.verbosity > 1: - sys.stderr.write('ok ') - sys.stderr.write(str(test)) - sys.stderr.write('\n') - else: - sys.stderr.write('.') - - def addError(self, test, err): - self.error_count += 1 - TestResult.addError(self, test, err) - _, _exc_str = self.errors[-1] - output = self.complete_output() - self.result.append((2, test, output, _exc_str)) - if self.verbosity > 1: - sys.stderr.write('E ') - sys.stderr.write(str(test)) - sys.stderr.write('\n') - else: - sys.stderr.write('E') - - def addFailure(self, test, err): - self.failure_count += 1 - TestResult.addFailure(self, test, err) - _, _exc_str = self.failures[-1] - output = self.complete_output() - self.result.append((1, test, output, _exc_str)) - if self.verbosity > 1: - sys.stderr.write('F ') - sys.stderr.write(str(test)) - sys.stderr.write('\n') - else: - sys.stderr.write('F') - - -class HTMLTestRunner(Template_mixin): - """ - """ - def __init__(self, stream=sys.stdout, verbosity=1, title=None, description=None): - self.stream = stream - self.verbosity = verbosity - if title is None: - self.title = self.DEFAULT_TITLE - else: - self.title = title - if description is None: - self.description = self.DEFAULT_DESCRIPTION - else: - self.description = description - - self.startTime = datetime.datetime.now() - - - def run(self, test): - "Run the given test case or test suite." - result = _TestResult(self.verbosity) - test(result) - self.stopTime = datetime.datetime.now() - self.generateReport(test, result) - print >>sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime) - return result - - - def sortResult(self, result_list): - # unittest does not seems to run in any particular order. - # Here at least we want to group them together by class. - rmap = {} - classes = [] - for n,t,o,e in result_list: - cls = t.__class__ - if not rmap.has_key(cls): - rmap[cls] = [] - classes.append(cls) - rmap[cls].append((n,t,o,e)) - r = [(cls, rmap[cls]) for cls in classes] - return r - - - def getReportAttributes(self, result): - """ - Return report attributes as a list of (name, value). - Override this to add custom attributes. - """ - startTime = str(self.startTime)[:19] - duration = str(self.stopTime - self.startTime) - status = [] - if result.success_count: status.append('Pass %s' % result.success_count) - if result.failure_count: status.append('Failure %s' % result.failure_count) - if result.error_count: status.append('Error %s' % result.error_count ) - if status: - status = ' '.join(status) - else: - status = 'none' - return [ - ('Start Time', startTime), - ('Duration', duration), - ('Status', status), - ] - - - def generateReport(self, test, result): - report_attrs = self.getReportAttributes(result) - generator = 'HTMLTestRunner %s' % __version__ - stylesheet = self._generate_stylesheet() - heading = self._generate_heading(report_attrs) - report = self._generate_report(result) - ending = self._generate_ending() - output = self.HTML_TMPL % dict( - title = saxutils.escape(self.title), - generator = generator, - stylesheet = stylesheet, - heading = heading, - report = report, - ending = ending, - ) - self.stream.write(output.encode('utf8')) - - - def _generate_stylesheet(self): - return self.STYLESHEET_TMPL - - - def _generate_heading(self, report_attrs): - a_lines = [] - for name, value in report_attrs: - line = self.HEADING_ATTRIBUTE_TMPL % dict( - name = saxutils.escape(name), - value = saxutils.escape(value), - ) - a_lines.append(line) - heading = self.HEADING_TMPL % dict( - title = saxutils.escape(self.title), - parameters = ''.join(a_lines), - description = saxutils.escape(self.description), - ) - return heading - - - def _generate_report(self, result): - rows = [] - sortedResult = self.sortResult(result.result) - for cid, (cls, cls_results) in enumerate(sortedResult): - # subtotal for a class - np = nf = ne = 0 - for n,t,o,e in cls_results: - if n == 0: np += 1 - elif n == 1: nf += 1 - else: ne += 1 - - # format class description - if cls.__module__ == "__main__": - name = cls.__name__ - else: - name = "%s.%s" % (cls.__module__, cls.__name__) - doc = cls.__doc__ and cls.__doc__.split("\n")[0] or "" - desc = doc and '%s: %s' % (name, doc) or name - - row = self.REPORT_CLASS_TMPL % dict( - style = ne > 0 and 'errorClass' or nf > 0 and 'failClass' or 'passClass', - desc = desc, - count = np+nf+ne, - Pass = np, - fail = nf, - error = ne, - cid = 'c%s' % (cid+1), - ) - rows.append(row) - - for tid, (n,t,o,e) in enumerate(cls_results): - self._generate_report_test(rows, cid, tid, n, t, o, e) - - report = self.REPORT_TMPL % dict( - test_list = ''.join(rows), - count = str(result.success_count+result.failure_count+result.error_count), - Pass = str(result.success_count), - fail = str(result.failure_count), - error = str(result.error_count), - ) - return report - - - def _generate_report_test(self, rows, cid, tid, n, t, o, e): - # e.g. 'pt1.1', 'ft1.1', etc - has_output = bool(o or e) - tid = (n == 0 and 'p' or 'f') + 't%s.%s' % (cid+1,tid+1) - name = t.id().split('.')[-1] - doc = t.shortDescription() or "" - desc = doc and ('%s: %s' % (name, doc)) or name - tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL - - # o and e should be byte string because they are collected from stdout and stderr? - if isinstance(o,str): - # TODO: some problem with 'string_escape': it escape \n and mess up formating - # uo = unicode(o.encode('string_escape')) - uo = o.decode('latin-1') - else: - uo = o - if isinstance(e,str): - # TODO: some problem with 'string_escape': it escape \n and mess up formating - # ue = unicode(e.encode('string_escape')) - ue = e.decode('latin-1') - else: - ue = e - - script = self.REPORT_TEST_OUTPUT_TMPL % dict( - id = tid, - output = saxutils.escape(uo+ue), - ) - - row = tmpl % dict( - tid = tid, - Class = (n == 0 and 'hiddenRow' or 'none'), - style = n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'none'), - desc = desc, - script = script, - status = self.STATUS[n], - ) - rows.append(row) - if not has_output: - return - - def _generate_ending(self): - return self.ENDING_TMPL - - -############################################################################## -# Facilities for running tests from the command line -############################################################################## - -# Note: Reuse unittest.TestProgram to launch test. In the future we may -# build our own launcher to support more specific command line -# parameters like test title, CSS, etc. -class TestProgram(unittest.TestProgram): - """ - A variation of the unittest.TestProgram. Please refer to the base - class for command line parameters. - """ - def runTests(self): - # Pick HTMLTestRunner as the default test runner. - # base class's testRunner parameter is not useful because it means - # we have to instantiate HTMLTestRunner before we know self.verbosity. - if self.testRunner is None: - self.testRunner = HTMLTestRunner(verbosity=self.verbosity) - unittest.TestProgram.runTests(self) - -main = TestProgram - -############################################################################## -# Executing this module from the command line -############################################################################## - -if __name__ == "__main__": - main(module=None) diff --git a/test/unittestpy/__init__.py b/test/unittestpy/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/test/unittestpy/tools.py b/test/unittestpy/tools.py deleted file mode 100644 index 2930b99..0000000 --- a/test/unittestpy/tools.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- -# Copyright (C) 2010-2012 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import tempfile -import sys -import subprocess -import time - -class outRedirection(): - '''redirection of standart output - useful for testing the terminal display - ''' - def __init__(self): - '''initialization - ''' - self._fstream = tempfile.NamedTemporaryFile(mode='w') - self.saveout = sys.stdout - sys.stdout = self._fstream - - def flush(self): - self._fstream.flush() - - def end_redirection(self): - self._fstream.seek(0) - ff = open(self._fstream.name, 'r') - self.res = ff.read() - self._fstream.close() - sys.stdout = self.saveout - - def read_results(self): - try: - return self.res - except Exception as exc: - print('Problem with redirection : %s' % exc) - sys.exit(1) - -def kill9(pid): - subprocess.call("kill -9 " + pid, shell=True) - -def check_proc_existence_and_kill(regex): - cmd = 'ps aux | grep "' + regex + '"' - psRes = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).communicate()[0] - psRes = psRes.split('\n') - for line in psRes: - if 'grep' in line or len(line) == 0: - continue - line2 = [i for i in line.split(' ') if i != ''] - pid = line2[1] - kill9(pid) - return pid - return 0 - -def check_proc_existence_and_kill_multi(regex, nb_kills, time_between_two_checks = 1): - found = False - i = 0 - while not found and i < nb_kills : - found = check_proc_existence_and_kill(regex) - if found: - return found - time.sleep(time_between_two_checks) - i+=1 - return 0 \ No newline at end of file diff --git a/unittestpy/HTMLTestRunner.py b/unittestpy/HTMLTestRunner.py new file mode 100644 index 0000000..0439bf4 --- /dev/null +++ b/unittestpy/HTMLTestRunner.py @@ -0,0 +1,824 @@ +""" +A TestRunner for use with the Python unit testing framework. It +generates a HTML report to show the result at a glance. + +The simplest way to use this is to invoke its main method. E.g. + + import unittest + import HTMLTestRunner + + ... define your tests ... + + if __name__ == '__main__': + HTMLTestRunner.main() + + +For more customization options, instantiates a HTMLTestRunner object. +HTMLTestRunner is a counterpart to unittest's TextTestRunner. E.g. + + # output to a file + fp = file('my_report.html', 'wb') + runner = HTMLTestRunner.HTMLTestRunner( + stream=fp, + title='My unit test', + description='This demonstrates the report output by HTMLTestRunner.' + ) + + # Use an external stylesheet. + # See the Template_mixin class for more customizable options + runner.STYLESHEET_TMPL = '' + + # run the test + runner.run(my_test_suite) + + +------------------------------------------------------------------------ +Copyright (c) 2004-2007, Wai Yip Tung +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 Wai Yip Tung 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. +""" + +# URL: http://tungwaiyip.info/software/HTMLTestRunner.html + +__author__ = "Wai Yip Tung" +__version__ = "0.8.2" + + +""" +Change History + +Version 0.8.2 +* Show output inline instead of popup window (Viorel Lupu). + +Version in 0.8.1 +* Validated XHTML (Wolfgang Borgert). +* Added description of test classes and test cases. + +Version in 0.8.0 +* Define Template_mixin class for customization. +* Workaround a IE 6 bug that it does not treat + +%(heading)s +%(report)s +%(ending)s + + + +""" + # variables: (title, generator, stylesheet, heading, report, ending) + + + # ------------------------------------------------------------------------ + # Stylesheet + # + # alternatively use a for external style sheet, e.g. + # + + STYLESHEET_TMPL = """ + +""" + + + + # ------------------------------------------------------------------------ + # Heading + # + + HEADING_TMPL = """
+

%(title)s

+%(parameters)s +

%(description)s

+
+ +""" # variables: (title, parameters, description) + + HEADING_ATTRIBUTE_TMPL = """

%(name)s: %(value)s

+""" # variables: (name, value) + + + + # ------------------------------------------------------------------------ + # Report + # + + REPORT_TMPL = """ +

Show +Summary +Failed +All +

+ ++++++++ + + + + + + + + +%(test_list)s + + + + + + + + +
Test Group/Test caseCountPassFailErrorView
Total%(count)s%(Pass)s%(fail)s%(error)s 
+""" # variables: (test_list, count, Pass, fail, error) + + REPORT_CLASS_TMPL = r""" + + %(desc)s + %(count)s + %(Pass)s + %(fail)s + %(error)s + Detail + +""" # variables: (style, desc, count, Pass, fail, error, cid) + + + REPORT_TEST_WITH_OUTPUT_TMPL = r""" + +
%(desc)s
+ + + + + %(status)s + + + + + + +""" # variables: (tid, Class, style, desc, status) + + + REPORT_TEST_NO_OUTPUT_TMPL = r""" + +
%(desc)s
+ %(status)s + +""" # variables: (tid, Class, style, desc, status) + + + REPORT_TEST_OUTPUT_TMPL = r""" +%(id)s: %(output)s +""" # variables: (id, output) + + + + # ------------------------------------------------------------------------ + # ENDING + # + + ENDING_TMPL = """
 
""" + +# -------------------- The end of the Template class ------------------- + + +TestResult = unittest.TestResult + +class _TestResult(TestResult): + # note: _TestResult is a pure representation of results. + # It lacks the output and reporting ability compares to unittest._TextTestResult. + + def __init__(self, verbosity=1): + TestResult.__init__(self) + self.stdout0 = None + self.stderr0 = None + self.success_count = 0 + self.failure_count = 0 + self.error_count = 0 + self.verbosity = verbosity + + # result is a list of result in 4 tuple + # ( + # result code (0: success; 1: fail; 2: error), + # TestCase object, + # Test output (byte string), + # stack trace, + # ) + self.result = [] + + + def startTest(self, test): + TestResult.startTest(self, test) + # just one buffer for both stdout and stderr + self.outputBuffer = StringIO.StringIO() + stdout_redirector.fp = self.outputBuffer + stderr_redirector.fp = self.outputBuffer + self.stdout0 = sys.stdout + self.stderr0 = sys.stderr + sys.stdout = stdout_redirector + sys.stderr = stderr_redirector + + + def complete_output(self): + """ + Disconnect output redirection and return buffer. + Safe to call multiple times. + """ + if self.stdout0: + sys.stdout = self.stdout0 + sys.stderr = self.stderr0 + self.stdout0 = None + self.stderr0 = None + return self.outputBuffer.getvalue() + + + def stopTest(self, test): + # Usually one of addSuccess, addError or addFailure would have been called. + # But there are some path in unittest that would bypass this. + # We must disconnect stdout in stopTest(), which is guaranteed to be called. + self.complete_output() + + + def addSuccess(self, test): + self.success_count += 1 + TestResult.addSuccess(self, test) + output = self.complete_output() + self.result.append((0, test, output, '')) + if self.verbosity > 1: + sys.stderr.write('ok ') + sys.stderr.write(str(test)) + sys.stderr.write('\n') + else: + sys.stderr.write('.') + + def addError(self, test, err): + self.error_count += 1 + TestResult.addError(self, test, err) + _, _exc_str = self.errors[-1] + output = self.complete_output() + self.result.append((2, test, output, _exc_str)) + if self.verbosity > 1: + sys.stderr.write('E ') + sys.stderr.write(str(test)) + sys.stderr.write('\n') + else: + sys.stderr.write('E') + + def addFailure(self, test, err): + self.failure_count += 1 + TestResult.addFailure(self, test, err) + _, _exc_str = self.failures[-1] + output = self.complete_output() + self.result.append((1, test, output, _exc_str)) + if self.verbosity > 1: + sys.stderr.write('F ') + sys.stderr.write(str(test)) + sys.stderr.write('\n') + else: + sys.stderr.write('F') + + +class HTMLTestRunner(Template_mixin): + """ + """ + def __init__(self, stream=sys.stdout, verbosity=1, title=None, description=None): + self.stream = stream + self.verbosity = verbosity + if title is None: + self.title = self.DEFAULT_TITLE + else: + self.title = title + if description is None: + self.description = self.DEFAULT_DESCRIPTION + else: + self.description = description + + self.startTime = datetime.datetime.now() + + + def run(self, test): + "Run the given test case or test suite." + result = _TestResult(self.verbosity) + test(result) + self.stopTime = datetime.datetime.now() + self.generateReport(test, result) + print >>sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime) + return result + + + def sortResult(self, result_list): + # unittest does not seems to run in any particular order. + # Here at least we want to group them together by class. + rmap = {} + classes = [] + for n,t,o,e in result_list: + cls = t.__class__ + if not rmap.has_key(cls): + rmap[cls] = [] + classes.append(cls) + rmap[cls].append((n,t,o,e)) + r = [(cls, rmap[cls]) for cls in classes] + return r + + + def getReportAttributes(self, result): + """ + Return report attributes as a list of (name, value). + Override this to add custom attributes. + """ + startTime = str(self.startTime)[:19] + duration = str(self.stopTime - self.startTime) + status = [] + if result.success_count: status.append('Pass %s' % result.success_count) + if result.failure_count: status.append('Failure %s' % result.failure_count) + if result.error_count: status.append('Error %s' % result.error_count ) + if status: + status = ' '.join(status) + else: + status = 'none' + return [ + ('Start Time', startTime), + ('Duration', duration), + ('Status', status), + ] + + + def generateReport(self, test, result): + report_attrs = self.getReportAttributes(result) + generator = 'HTMLTestRunner %s' % __version__ + stylesheet = self._generate_stylesheet() + heading = self._generate_heading(report_attrs) + report = self._generate_report(result) + ending = self._generate_ending() + output = self.HTML_TMPL % dict( + title = saxutils.escape(self.title), + generator = generator, + stylesheet = stylesheet, + heading = heading, + report = report, + ending = ending, + ) + self.stream.write(output.encode('utf8')) + + + def _generate_stylesheet(self): + return self.STYLESHEET_TMPL + + + def _generate_heading(self, report_attrs): + a_lines = [] + for name, value in report_attrs: + line = self.HEADING_ATTRIBUTE_TMPL % dict( + name = saxutils.escape(name), + value = saxutils.escape(value), + ) + a_lines.append(line) + heading = self.HEADING_TMPL % dict( + title = saxutils.escape(self.title), + parameters = ''.join(a_lines), + description = saxutils.escape(self.description), + ) + return heading + + + def _generate_report(self, result): + rows = [] + sortedResult = self.sortResult(result.result) + for cid, (cls, cls_results) in enumerate(sortedResult): + # subtotal for a class + np = nf = ne = 0 + for n,t,o,e in cls_results: + if n == 0: np += 1 + elif n == 1: nf += 1 + else: ne += 1 + + # format class description + if cls.__module__ == "__main__": + name = cls.__name__ + else: + name = "%s.%s" % (cls.__module__, cls.__name__) + doc = cls.__doc__ and cls.__doc__.split("\n")[0] or "" + desc = doc and '%s: %s' % (name, doc) or name + + row = self.REPORT_CLASS_TMPL % dict( + style = ne > 0 and 'errorClass' or nf > 0 and 'failClass' or 'passClass', + desc = desc, + count = np+nf+ne, + Pass = np, + fail = nf, + error = ne, + cid = 'c%s' % (cid+1), + ) + rows.append(row) + + for tid, (n,t,o,e) in enumerate(cls_results): + self._generate_report_test(rows, cid, tid, n, t, o, e) + + report = self.REPORT_TMPL % dict( + test_list = ''.join(rows), + count = str(result.success_count+result.failure_count+result.error_count), + Pass = str(result.success_count), + fail = str(result.failure_count), + error = str(result.error_count), + ) + return report + + + def _generate_report_test(self, rows, cid, tid, n, t, o, e): + # e.g. 'pt1.1', 'ft1.1', etc + has_output = bool(o or e) + tid = (n == 0 and 'p' or 'f') + 't%s.%s' % (cid+1,tid+1) + name = t.id().split('.')[-1] + doc = t.shortDescription() or "" + desc = doc and ('%s: %s' % (name, doc)) or name + tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL + + # o and e should be byte string because they are collected from stdout and stderr? + if isinstance(o,str): + # TODO: some problem with 'string_escape': it escape \n and mess up formating + # uo = unicode(o.encode('string_escape')) + uo = o.decode('latin-1') + else: + uo = o + if isinstance(e,str): + # TODO: some problem with 'string_escape': it escape \n and mess up formating + # ue = unicode(e.encode('string_escape')) + ue = e.decode('latin-1') + else: + ue = e + + script = self.REPORT_TEST_OUTPUT_TMPL % dict( + id = tid, + output = saxutils.escape(uo+ue), + ) + + row = tmpl % dict( + tid = tid, + Class = (n == 0 and 'hiddenRow' or 'none'), + style = n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'none'), + desc = desc, + script = script, + status = self.STATUS[n], + ) + rows.append(row) + if not has_output: + return + + def _generate_ending(self): + return self.ENDING_TMPL + + +############################################################################## +# Facilities for running tests from the command line +############################################################################## + +# Note: Reuse unittest.TestProgram to launch test. In the future we may +# build our own launcher to support more specific command line +# parameters like test title, CSS, etc. +class TestProgram(unittest.TestProgram): + """ + A variation of the unittest.TestProgram. Please refer to the base + class for command line parameters. + """ + def runTests(self): + # Pick HTMLTestRunner as the default test runner. + # base class's testRunner parameter is not useful because it means + # we have to instantiate HTMLTestRunner before we know self.verbosity. + if self.testRunner is None: + self.testRunner = HTMLTestRunner(verbosity=self.verbosity) + unittest.TestProgram.runTests(self) + +main = TestProgram + +############################################################################## +# Executing this module from the command line +############################################################################## + +if __name__ == "__main__": + main(module=None) diff --git a/unittestpy/__init__.py b/unittestpy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/unittestpy/tools.py b/unittestpy/tools.py new file mode 100644 index 0000000..2930b99 --- /dev/null +++ b/unittestpy/tools.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- +# Copyright (C) 2010-2012 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import tempfile +import sys +import subprocess +import time + +class outRedirection(): + '''redirection of standart output + useful for testing the terminal display + ''' + def __init__(self): + '''initialization + ''' + self._fstream = tempfile.NamedTemporaryFile(mode='w') + self.saveout = sys.stdout + sys.stdout = self._fstream + + def flush(self): + self._fstream.flush() + + def end_redirection(self): + self._fstream.seek(0) + ff = open(self._fstream.name, 'r') + self.res = ff.read() + self._fstream.close() + sys.stdout = self.saveout + + def read_results(self): + try: + return self.res + except Exception as exc: + print('Problem with redirection : %s' % exc) + sys.exit(1) + +def kill9(pid): + subprocess.call("kill -9 " + pid, shell=True) + +def check_proc_existence_and_kill(regex): + cmd = 'ps aux | grep "' + regex + '"' + psRes = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).communicate()[0] + psRes = psRes.split('\n') + for line in psRes: + if 'grep' in line or len(line) == 0: + continue + line2 = [i for i in line.split(' ') if i != ''] + pid = line2[1] + kill9(pid) + return pid + return 0 + +def check_proc_existence_and_kill_multi(regex, nb_kills, time_between_two_checks = 1): + found = False + i = 0 + while not found and i < nb_kills : + found = check_proc_existence_and_kill(regex) + if found: + return found + time.sleep(time_between_two_checks) + i+=1 + return 0 \ No newline at end of file