]> SALOME platform Git repositories - tools/sat.git/commitdiff
Salome HOME
move unittestpy outside obsolescent test dir
authorChristian Van Wambeke <christian.van-wambeke@cea.fr>
Tue, 23 Jan 2018 09:31:17 +0000 (10:31 +0100)
committerChristian Van Wambeke <christian.van-wambeke@cea.fr>
Tue, 23 Jan 2018 09:31:17 +0000 (10:31 +0100)
16 files changed:
AllTestLauncherSat.py
test/config/test_option_edit.py
test/config/test_option_value.py
test/config/test_option_value_2.py
test/jobs/test_jobs.py
test/log/test_launch_browser.py
test/log/test_launch_browser2.py
test/prepare/test_clean.py
test/prepare/test_patch.py
test/prepare/test_source.py
test/unittestpy/HTMLTestRunner.py [deleted file]
test/unittestpy/__init__.py [deleted file]
test/unittestpy/tools.py [deleted file]
unittestpy/HTMLTestRunner.py [new file with mode: 0644]
unittestpy/__init__.py [new file with mode: 0644]
unittestpy/tools.py [new file with mode: 0644]

index 1a2be076ff9856e33e8144d2c5f4d4de190caa36..59f4fbda168664280f986233477f38b572badbb2 100755 (executable)
@@ -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("""
index a106791d5c002db01f4f3ed06c7f815faf9ee02f..c6674e9c8f2384c46038fe331091c81ab0a715c4 100755 (executable)
@@ -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
 
index 73cfd562a6e045219f3a2a389e1dba841ed56b32..50a7d847ffe389462254cffb17ef684ae67d8dd1 100755 (executable)
@@ -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"""
index 413c462ab09c4190dbd6640a7239bd8b9efd2529..c11fee1cff0860920f9e694744cf96e1d0350036 100755 (executable)
@@ -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"""
index 0a673a73b4da7c55d7e25fd39eed114c981c06e8..1b22378c73b5246f1b40e35cbc872d52f2cd8356 100755 (executable)
@@ -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"""
index 03d261fd60682f78dc21fcbf4b25d0b5894230bf..a9c8be45cd5790f2615bc1d3f9bd2af05abbfd63 100755 (executable)
@@ -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
 
index deaf65ed21d5087edd3f5e1f8647ce0f96910f19..38a61841058e585282c4d282d8af9e1627a7867c 100755 (executable)
@@ -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
 
index c753f8d922fe856bd995e2722c331902b49ec323..08bb54f1a3d6bd5f963207e1c9fc97a7e7ab4179 100755 (executable)
@@ -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"""
index ad7db3109b2a2fe7f6e62420d378105cf8211b32..1dc24d43dfb29f6fb0de06bf8ba56f246bb7af64 100755 (executable)
@@ -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"""
index f60badc0d922312d84e9f59d7dd965fac053255e..f7a053d47717a953eeba5748fc751fb8ed141fd6 100755 (executable)
@@ -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 (file)
index 0439bf4..0000000
+++ /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 = '<link rel="stylesheet" href="my_stylesheet.css" type="text/css">'
-
-    # 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 <script> block as CDATA.
-
-Version in 0.7.1
-* Back port to Python 2.3 (Frank Horowitz).
-* Fix missing scroll bars in detail log (Podi).
-"""
-
-# TODO: color stderr
-# TODO: simplify javascript using ,ore than 1 class in the class attribute?
-
-import datetime
-import StringIO
-import sys
-import time
-import unittest
-from xml.sax import saxutils
-
-
-# ------------------------------------------------------------------------
-# The redirectors below are used to capture output during testing. Output
-# sent to sys.stdout and sys.stderr are automatically captured. However
-# in some cases sys.stdout is already cached before HTMLTestRunner is
-# invoked (e.g. calling logging.basicConfig). In order to capture those
-# output, use the redirectors for the cached stream.
-#
-# e.g.
-#   >>> logging.basicConfig(stream=HTMLTestRunner.stdout_redirector)
-#   >>>
-
-class OutputRedirector(object):
-    """ Wrapper to redirect stdout or stderr """
-    def __init__(self, fp):
-        self.fp = fp
-
-    def write(self, s):
-        self.fp.write(s)
-
-    def writelines(self, lines):
-        self.fp.writelines(lines)
-
-    def flush(self):
-        self.fp.flush()
-
-stdout_redirector = OutputRedirector(sys.stdout)
-stderr_redirector = OutputRedirector(sys.stderr)
-
-
-
-# ----------------------------------------------------------------------
-# Template
-
-class Template_mixin(object):
-    """
-    Define a HTML template for report customerization and generation.
-
-    Overall structure of an HTML report
-
-    HTML
-    +------------------------+
-    |<html>                  |
-    |  <head>                |
-    |                        |
-    |   STYLESHEET           |
-    |   +----------------+   |
-    |   |                |   |
-    |   +----------------+   |
-    |                        |
-    |  </head>               |
-    |                        |
-    |  <body>                |
-    |                        |
-    |   HEADING              |
-    |   +----------------+   |
-    |   |                |   |
-    |   +----------------+   |
-    |                        |
-    |   REPORT               |
-    |   +----------------+   |
-    |   |                |   |
-    |   +----------------+   |
-    |                        |
-    |   ENDING               |
-    |   +----------------+   |
-    |   |                |   |
-    |   +----------------+   |
-    |                        |
-    |  </body>               |
-    |</html>                 |
-    +------------------------+
-    """
-
-    STATUS = {
-    0: 'pass',
-    1: 'fail',
-    2: 'error',
-    }
-
-    DEFAULT_TITLE = 'Unit Test Report'
-    DEFAULT_DESCRIPTION = ''
-
-    # ------------------------------------------------------------------------
-    # HTML Template
-
-    HTML_TMPL = r"""<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-    <title>%(title)s</title>
-    <meta name="generator" content="%(generator)s"/>
-    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
-    %(stylesheet)s
-</head>
-<body>
-<script language="javascript" type="text/javascript"><!--
-output_list = Array();
-
-/* level - 0:Summary; 1:Failed; 2:All */
-function showCase(level) {
-    trs = document.getElementsByTagName("tr");
-    for (var i = 0; i < trs.length; i++) {
-        tr = trs[i];
-        id = tr.id;
-        if (id.substr(0,2) == 'ft') {
-            if (level < 1) {
-                tr.className = 'hiddenRow';
-            }
-            else {
-                tr.className = '';
-            }
-        }
-        if (id.substr(0,2) == 'pt') {
-            if (level > 1) {
-                tr.className = '';
-            }
-            else {
-                tr.className = 'hiddenRow';
-            }
-        }
-    }
-}
-
-
-function showClassDetail(cid, count) {
-    var id_list = Array(count);
-    var toHide = 1;
-    for (var i = 0; i < count; i++) {
-        tid0 = 't' + cid.substr(1) + '.' + (i+1);
-        tid = 'f' + tid0;
-        tr = document.getElementById(tid);
-        if (!tr) {
-            tid = 'p' + tid0;
-            tr = document.getElementById(tid);
-        }
-        id_list[i] = tid;
-        if (tr.className) {
-            toHide = 0;
-        }
-    }
-    for (var i = 0; i < count; i++) {
-        tid = id_list[i];
-        if (toHide) {
-            document.getElementById('div_'+tid).style.display = 'none'
-            document.getElementById(tid).className = 'hiddenRow';
-        }
-        else {
-            document.getElementById(tid).className = '';
-        }
-    }
-}
-
-
-function showTestDetail(div_id){
-    var details_div = document.getElementById(div_id)
-    var displayState = details_div.style.display
-    // alert(displayState)
-    if (displayState != 'block' ) {
-        displayState = 'block'
-        details_div.style.display = 'block'
-    }
-    else {
-        details_div.style.display = 'none'
-    }
-}
-
-
-function html_escape(s) {
-    s = s.replace(/&/g,'&amp;');
-    s = s.replace(/</g,'&lt;');
-    s = s.replace(/>/g,'&gt;');
-    return s;
-}
-
-/* obsoleted by detail in <div>
-function showOutput(id, name) {
-    var w = window.open("", //url
-                    name,
-                    "resizable,scrollbars,status,width=800,height=450");
-    d = w.document;
-    d.write("<pre>");
-    d.write(html_escape(output_list[id]));
-    d.write("\n");
-    d.write("<a href='javascript:window.close()'>close</a>\n");
-    d.write("</pre>\n");
-    d.close();
-}
-*/
---></script>
-
-%(heading)s
-%(report)s
-%(ending)s
-
-</body>
-</html>
-"""
-    # variables: (title, generator, stylesheet, heading, report, ending)
-
-
-    # ------------------------------------------------------------------------
-    # Stylesheet
-    #
-    # alternatively use a <link> for external style sheet, e.g.
-    #   <link rel="stylesheet" href="$url" type="text/css">
-
-    STYLESHEET_TMPL = """
-<style type="text/css" media="screen">
-body        { font-family: verdana, arial, helvetica, sans-serif; font-size: 80%; }
-table       { font-size: 100%; }
-pre         { }
-
-/* -- heading ---------------------------------------------------------------------- */
-h1 {
-       font-size: 16pt;
-       color: gray;
-}
-.heading {
-    margin-top: 0ex;
-    margin-bottom: 1ex;
-}
-
-.heading .attribute {
-    margin-top: 1ex;
-    margin-bottom: 0;
-}
-
-.heading .description {
-    margin-top: 4ex;
-    margin-bottom: 6ex;
-}
-
-/* -- css div popup ------------------------------------------------------------------------ */
-a.popup_link {
-}
-
-a.popup_link:hover {
-    color: red;
-}
-
-.popup_window {
-    display: none;
-    position: relative;
-    left: 0px;
-    top: 0px;
-    /*border: solid #627173 1px; */
-    padding: 10px;
-    background-color: #E6E6D6;
-    font-family: "Lucida Console", "Courier New", Courier, monospace;
-    text-align: left;
-    font-size: 8pt;
-    width: 500px;
-}
-
-}
-/* -- report ------------------------------------------------------------------------ */
-#show_detail_line {
-    margin-top: 3ex;
-    margin-bottom: 1ex;
-}
-#result_table {
-    width: 80%;
-    border-collapse: collapse;
-    border: 1px solid #777;
-}
-#header_row {
-    font-weight: bold;
-    color: white;
-    background-color: #777;
-}
-#result_table td {
-    border: 1px solid #777;
-    padding: 2px;
-}
-#total_row  { font-weight: bold; }
-.passClass  { background-color: #6c6; }
-.failClass  { background-color: #c60; }
-.errorClass { background-color: #c00; }
-.passCase   { color: #6c6; }
-.failCase   { color: #c60; font-weight: bold; }
-.errorCase  { color: #c00; font-weight: bold; }
-.hiddenRow  { display: none; }
-.testcase   { margin-left: 2em; }
-
-
-/* -- ending ---------------------------------------------------------------------- */
-#ending {
-}
-
-</style>
-"""
-
-
-
-    # ------------------------------------------------------------------------
-    # Heading
-    #
-
-    HEADING_TMPL = """<div class='heading'>
-<h1>%(title)s</h1>
-%(parameters)s
-<p class='description'>%(description)s</p>
-</div>
-
-""" # variables: (title, parameters, description)
-
-    HEADING_ATTRIBUTE_TMPL = """<p class='attribute'><strong>%(name)s:</strong> %(value)s</p>
-""" # variables: (name, value)
-
-
-
-    # ------------------------------------------------------------------------
-    # Report
-    #
-
-    REPORT_TMPL = """
-<p id='show_detail_line'>Show
-<a href='javascript:showCase(0)'>Summary</a>
-<a href='javascript:showCase(1)'>Failed</a>
-<a href='javascript:showCase(2)'>All</a>
-</p>
-<table id='result_table'>
-<colgroup>
-<col align='left' />
-<col align='right' />
-<col align='right' />
-<col align='right' />
-<col align='right' />
-<col align='right' />
-</colgroup>
-<tr id='header_row'>
-    <td>Test Group/Test case</td>
-    <td>Count</td>
-    <td>Pass</td>
-    <td>Fail</td>
-    <td>Error</td>
-    <td>View</td>
-</tr>
-%(test_list)s
-<tr id='total_row'>
-    <td>Total</td>
-    <td>%(count)s</td>
-    <td>%(Pass)s</td>
-    <td>%(fail)s</td>
-    <td>%(error)s</td>
-    <td>&nbsp;</td>
-</tr>
-</table>
-""" # variables: (test_list, count, Pass, fail, error)
-
-    REPORT_CLASS_TMPL = r"""
-<tr class='%(style)s'>
-    <td>%(desc)s</td>
-    <td>%(count)s</td>
-    <td>%(Pass)s</td>
-    <td>%(fail)s</td>
-    <td>%(error)s</td>
-    <td><a href="javascript:showClassDetail('%(cid)s',%(count)s)">Detail</a></td>
-</tr>
-""" # variables: (style, desc, count, Pass, fail, error, cid)
-
-
-    REPORT_TEST_WITH_OUTPUT_TMPL = r"""
-<tr id='%(tid)s' class='%(Class)s'>
-    <td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
-    <td colspan='5' align='center'>
-
-    <!--css div popup start-->
-    <a class="popup_link" onfocus='this.blur();' href="javascript:showTestDetail('div_%(tid)s')" >
-        %(status)s</a>
-
-    <div id='div_%(tid)s' class="popup_window">
-        <div style='text-align: right; color:red;cursor:pointer'>
-        <a onfocus='this.blur();' onclick="document.getElementById('div_%(tid)s').style.display = 'none' " >
-           [x]</a>
-        </div>
-        <pre>
-        %(script)s
-        </pre>
-    </div>
-    <!--css div popup end-->
-
-    </td>
-</tr>
-""" # variables: (tid, Class, style, desc, status)
-
-
-    REPORT_TEST_NO_OUTPUT_TMPL = r"""
-<tr id='%(tid)s' class='%(Class)s'>
-    <td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
-    <td colspan='5' align='center'>%(status)s</td>
-</tr>
-""" # variables: (tid, Class, style, desc, status)
-
-
-    REPORT_TEST_OUTPUT_TMPL = r"""
-%(id)s: %(output)s
-""" # variables: (id, output)
-
-
-
-    # ------------------------------------------------------------------------
-    # ENDING
-    #
-
-    ENDING_TMPL = """<div id='ending'>&nbsp;</div>"""
-
-# -------------------- 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 (file)
index e69de29..0000000
diff --git a/test/unittestpy/tools.py b/test/unittestpy/tools.py
deleted file mode 100644 (file)
index 2930b99..0000000
+++ /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 (file)
index 0000000..0439bf4
--- /dev/null
@@ -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 = '<link rel="stylesheet" href="my_stylesheet.css" type="text/css">'
+
+    # 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 <script> block as CDATA.
+
+Version in 0.7.1
+* Back port to Python 2.3 (Frank Horowitz).
+* Fix missing scroll bars in detail log (Podi).
+"""
+
+# TODO: color stderr
+# TODO: simplify javascript using ,ore than 1 class in the class attribute?
+
+import datetime
+import StringIO
+import sys
+import time
+import unittest
+from xml.sax import saxutils
+
+
+# ------------------------------------------------------------------------
+# The redirectors below are used to capture output during testing. Output
+# sent to sys.stdout and sys.stderr are automatically captured. However
+# in some cases sys.stdout is already cached before HTMLTestRunner is
+# invoked (e.g. calling logging.basicConfig). In order to capture those
+# output, use the redirectors for the cached stream.
+#
+# e.g.
+#   >>> logging.basicConfig(stream=HTMLTestRunner.stdout_redirector)
+#   >>>
+
+class OutputRedirector(object):
+    """ Wrapper to redirect stdout or stderr """
+    def __init__(self, fp):
+        self.fp = fp
+
+    def write(self, s):
+        self.fp.write(s)
+
+    def writelines(self, lines):
+        self.fp.writelines(lines)
+
+    def flush(self):
+        self.fp.flush()
+
+stdout_redirector = OutputRedirector(sys.stdout)
+stderr_redirector = OutputRedirector(sys.stderr)
+
+
+
+# ----------------------------------------------------------------------
+# Template
+
+class Template_mixin(object):
+    """
+    Define a HTML template for report customerization and generation.
+
+    Overall structure of an HTML report
+
+    HTML
+    +------------------------+
+    |<html>                  |
+    |  <head>                |
+    |                        |
+    |   STYLESHEET           |
+    |   +----------------+   |
+    |   |                |   |
+    |   +----------------+   |
+    |                        |
+    |  </head>               |
+    |                        |
+    |  <body>                |
+    |                        |
+    |   HEADING              |
+    |   +----------------+   |
+    |   |                |   |
+    |   +----------------+   |
+    |                        |
+    |   REPORT               |
+    |   +----------------+   |
+    |   |                |   |
+    |   +----------------+   |
+    |                        |
+    |   ENDING               |
+    |   +----------------+   |
+    |   |                |   |
+    |   +----------------+   |
+    |                        |
+    |  </body>               |
+    |</html>                 |
+    +------------------------+
+    """
+
+    STATUS = {
+    0: 'pass',
+    1: 'fail',
+    2: 'error',
+    }
+
+    DEFAULT_TITLE = 'Unit Test Report'
+    DEFAULT_DESCRIPTION = ''
+
+    # ------------------------------------------------------------------------
+    # HTML Template
+
+    HTML_TMPL = r"""<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+    <title>%(title)s</title>
+    <meta name="generator" content="%(generator)s"/>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    %(stylesheet)s
+</head>
+<body>
+<script language="javascript" type="text/javascript"><!--
+output_list = Array();
+
+/* level - 0:Summary; 1:Failed; 2:All */
+function showCase(level) {
+    trs = document.getElementsByTagName("tr");
+    for (var i = 0; i < trs.length; i++) {
+        tr = trs[i];
+        id = tr.id;
+        if (id.substr(0,2) == 'ft') {
+            if (level < 1) {
+                tr.className = 'hiddenRow';
+            }
+            else {
+                tr.className = '';
+            }
+        }
+        if (id.substr(0,2) == 'pt') {
+            if (level > 1) {
+                tr.className = '';
+            }
+            else {
+                tr.className = 'hiddenRow';
+            }
+        }
+    }
+}
+
+
+function showClassDetail(cid, count) {
+    var id_list = Array(count);
+    var toHide = 1;
+    for (var i = 0; i < count; i++) {
+        tid0 = 't' + cid.substr(1) + '.' + (i+1);
+        tid = 'f' + tid0;
+        tr = document.getElementById(tid);
+        if (!tr) {
+            tid = 'p' + tid0;
+            tr = document.getElementById(tid);
+        }
+        id_list[i] = tid;
+        if (tr.className) {
+            toHide = 0;
+        }
+    }
+    for (var i = 0; i < count; i++) {
+        tid = id_list[i];
+        if (toHide) {
+            document.getElementById('div_'+tid).style.display = 'none'
+            document.getElementById(tid).className = 'hiddenRow';
+        }
+        else {
+            document.getElementById(tid).className = '';
+        }
+    }
+}
+
+
+function showTestDetail(div_id){
+    var details_div = document.getElementById(div_id)
+    var displayState = details_div.style.display
+    // alert(displayState)
+    if (displayState != 'block' ) {
+        displayState = 'block'
+        details_div.style.display = 'block'
+    }
+    else {
+        details_div.style.display = 'none'
+    }
+}
+
+
+function html_escape(s) {
+    s = s.replace(/&/g,'&amp;');
+    s = s.replace(/</g,'&lt;');
+    s = s.replace(/>/g,'&gt;');
+    return s;
+}
+
+/* obsoleted by detail in <div>
+function showOutput(id, name) {
+    var w = window.open("", //url
+                    name,
+                    "resizable,scrollbars,status,width=800,height=450");
+    d = w.document;
+    d.write("<pre>");
+    d.write(html_escape(output_list[id]));
+    d.write("\n");
+    d.write("<a href='javascript:window.close()'>close</a>\n");
+    d.write("</pre>\n");
+    d.close();
+}
+*/
+--></script>
+
+%(heading)s
+%(report)s
+%(ending)s
+
+</body>
+</html>
+"""
+    # variables: (title, generator, stylesheet, heading, report, ending)
+
+
+    # ------------------------------------------------------------------------
+    # Stylesheet
+    #
+    # alternatively use a <link> for external style sheet, e.g.
+    #   <link rel="stylesheet" href="$url" type="text/css">
+
+    STYLESHEET_TMPL = """
+<style type="text/css" media="screen">
+body        { font-family: verdana, arial, helvetica, sans-serif; font-size: 80%; }
+table       { font-size: 100%; }
+pre         { }
+
+/* -- heading ---------------------------------------------------------------------- */
+h1 {
+       font-size: 16pt;
+       color: gray;
+}
+.heading {
+    margin-top: 0ex;
+    margin-bottom: 1ex;
+}
+
+.heading .attribute {
+    margin-top: 1ex;
+    margin-bottom: 0;
+}
+
+.heading .description {
+    margin-top: 4ex;
+    margin-bottom: 6ex;
+}
+
+/* -- css div popup ------------------------------------------------------------------------ */
+a.popup_link {
+}
+
+a.popup_link:hover {
+    color: red;
+}
+
+.popup_window {
+    display: none;
+    position: relative;
+    left: 0px;
+    top: 0px;
+    /*border: solid #627173 1px; */
+    padding: 10px;
+    background-color: #E6E6D6;
+    font-family: "Lucida Console", "Courier New", Courier, monospace;
+    text-align: left;
+    font-size: 8pt;
+    width: 500px;
+}
+
+}
+/* -- report ------------------------------------------------------------------------ */
+#show_detail_line {
+    margin-top: 3ex;
+    margin-bottom: 1ex;
+}
+#result_table {
+    width: 80%;
+    border-collapse: collapse;
+    border: 1px solid #777;
+}
+#header_row {
+    font-weight: bold;
+    color: white;
+    background-color: #777;
+}
+#result_table td {
+    border: 1px solid #777;
+    padding: 2px;
+}
+#total_row  { font-weight: bold; }
+.passClass  { background-color: #6c6; }
+.failClass  { background-color: #c60; }
+.errorClass { background-color: #c00; }
+.passCase   { color: #6c6; }
+.failCase   { color: #c60; font-weight: bold; }
+.errorCase  { color: #c00; font-weight: bold; }
+.hiddenRow  { display: none; }
+.testcase   { margin-left: 2em; }
+
+
+/* -- ending ---------------------------------------------------------------------- */
+#ending {
+}
+
+</style>
+"""
+
+
+
+    # ------------------------------------------------------------------------
+    # Heading
+    #
+
+    HEADING_TMPL = """<div class='heading'>
+<h1>%(title)s</h1>
+%(parameters)s
+<p class='description'>%(description)s</p>
+</div>
+
+""" # variables: (title, parameters, description)
+
+    HEADING_ATTRIBUTE_TMPL = """<p class='attribute'><strong>%(name)s:</strong> %(value)s</p>
+""" # variables: (name, value)
+
+
+
+    # ------------------------------------------------------------------------
+    # Report
+    #
+
+    REPORT_TMPL = """
+<p id='show_detail_line'>Show
+<a href='javascript:showCase(0)'>Summary</a>
+<a href='javascript:showCase(1)'>Failed</a>
+<a href='javascript:showCase(2)'>All</a>
+</p>
+<table id='result_table'>
+<colgroup>
+<col align='left' />
+<col align='right' />
+<col align='right' />
+<col align='right' />
+<col align='right' />
+<col align='right' />
+</colgroup>
+<tr id='header_row'>
+    <td>Test Group/Test case</td>
+    <td>Count</td>
+    <td>Pass</td>
+    <td>Fail</td>
+    <td>Error</td>
+    <td>View</td>
+</tr>
+%(test_list)s
+<tr id='total_row'>
+    <td>Total</td>
+    <td>%(count)s</td>
+    <td>%(Pass)s</td>
+    <td>%(fail)s</td>
+    <td>%(error)s</td>
+    <td>&nbsp;</td>
+</tr>
+</table>
+""" # variables: (test_list, count, Pass, fail, error)
+
+    REPORT_CLASS_TMPL = r"""
+<tr class='%(style)s'>
+    <td>%(desc)s</td>
+    <td>%(count)s</td>
+    <td>%(Pass)s</td>
+    <td>%(fail)s</td>
+    <td>%(error)s</td>
+    <td><a href="javascript:showClassDetail('%(cid)s',%(count)s)">Detail</a></td>
+</tr>
+""" # variables: (style, desc, count, Pass, fail, error, cid)
+
+
+    REPORT_TEST_WITH_OUTPUT_TMPL = r"""
+<tr id='%(tid)s' class='%(Class)s'>
+    <td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
+    <td colspan='5' align='center'>
+
+    <!--css div popup start-->
+    <a class="popup_link" onfocus='this.blur();' href="javascript:showTestDetail('div_%(tid)s')" >
+        %(status)s</a>
+
+    <div id='div_%(tid)s' class="popup_window">
+        <div style='text-align: right; color:red;cursor:pointer'>
+        <a onfocus='this.blur();' onclick="document.getElementById('div_%(tid)s').style.display = 'none' " >
+           [x]</a>
+        </div>
+        <pre>
+        %(script)s
+        </pre>
+    </div>
+    <!--css div popup end-->
+
+    </td>
+</tr>
+""" # variables: (tid, Class, style, desc, status)
+
+
+    REPORT_TEST_NO_OUTPUT_TMPL = r"""
+<tr id='%(tid)s' class='%(Class)s'>
+    <td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
+    <td colspan='5' align='center'>%(status)s</td>
+</tr>
+""" # variables: (tid, Class, style, desc, status)
+
+
+    REPORT_TEST_OUTPUT_TMPL = r"""
+%(id)s: %(output)s
+""" # variables: (id, output)
+
+
+
+    # ------------------------------------------------------------------------
+    # ENDING
+    #
+
+    ENDING_TMPL = """<div id='ending'>&nbsp;</div>"""
+
+# -------------------- 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 (file)
index 0000000..e69de29
diff --git a/unittestpy/tools.py b/unittestpy/tools.py
new file mode 100644 (file)
index 0000000..2930b99
--- /dev/null
@@ -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