Package rosunit :: Module pyunit
[frames] | no frames]

Source Code for Module rosunit.pyunit

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2008, Willow Garage, Inc. 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Willow Garage, Inc. nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32  # 
 33  # Revision $Id$ 
 34   
 35  """ 
 36  Wrapper for running Python unittest within rosunit/rostest framework. 
 37  """ 
 38  from __future__ import print_function 
 39  from __future__ import with_statement 
 40   
 41  import sys 
 42   
 43  from .baretest import print_unittest_summary 
 44  from .core import XML_OUTPUT_FLAG 
 45  from .core import create_xml_runner 
 46   
 47   
48 -def unitrun(package, test_name, test, sysargs=None, coverage_packages=None):
49 """ 50 Wrapper routine from running python unitttests with 51 JUnit-compatible XML output. This is meant for unittests that do 52 not not need a running ROS graph (i.e. offline tests only). 53 54 This enables JUnit-compatible test reporting so that 55 test results can be reported to higher-level tools. 56 57 WARNING: unitrun() will trigger a sys.exit() on test failure in 58 order to properly exit with an error code. This routine is meant 59 to be used as a main() routine, not as a library. 60 61 @param package: name of ROS package that is running the test 62 @type package: str 63 @param test: a test case instance or a name resolving to a test case or suite 64 @type test: unittest.TestCase, or string 65 @param coverage_packages: list of Python package to compute coverage results for. Defaults to package 66 @type coverage_packages: [str] 67 @param sysargs: (optional) alternate sys.argv 68 @type sysargs: [str] 69 """ 70 if sysargs is None: 71 # lazy-init sys args 72 import sys 73 sysargs = sys.argv 74 75 import unittest 76 77 if coverage_packages is None: 78 coverage_packages = [package] 79 80 # parse sysargs 81 result_file = None 82 for arg in sysargs: 83 if arg.startswith(XML_OUTPUT_FLAG): 84 result_file = arg[len(XML_OUTPUT_FLAG):] 85 text_mode = '--text' in sysargs 86 87 coverage_mode = '--cov' in sysargs or '--covhtml' in sysargs 88 if coverage_mode: 89 start_coverage(coverage_packages) 90 91 # create and run unittest suite with our xmllrunner wrapper 92 suite = None 93 if isinstance(test, str): 94 suite = unittest.TestLoader().loadTestsFromName(test) 95 else: 96 # some callers pass a TestCase type (instead of an instance) 97 suite = unittest.TestLoader().loadTestsFromTestCase(test) 98 99 if text_mode: 100 result = unittest.TextTestRunner(verbosity=2).run(suite) 101 else: 102 result = create_xml_runner(package, test_name, result_file).run(suite) 103 if coverage_mode: 104 cov_html_dir = 'covhtml' if '--covhtml' in sysargs else None 105 stop_coverage(coverage_packages, html=cov_html_dir) 106 107 # test over, summarize results and exit appropriately 108 print_unittest_summary(result) 109 110 if not result.wasSuccessful(): 111 import sys 112 sys.exit(1)
113 114 115 # coverage instance 116 _cov = None 117 118
119 -def start_coverage(packages):
120 global _cov 121 try: 122 import coverage 123 try: 124 _cov = coverage.coverage() 125 # load previous results as we need to accumulate 126 _cov.load() 127 _cov.start() 128 except coverage.CoverageException: 129 print("WARNING: you have an older version of python-coverage that is not support. Please update to the version provided by 'easy_install coverage'", file=sys.stderr) 130 except ImportError: 131 print("""WARNING: cannot import python-coverage, coverage tests will not run. 132 To install coverage, run 'easy_install coverage'""", file=sys.stderr)
133 134
135 -def stop_coverage(packages, html=None):
136 """ 137 @param packages: list of packages to generate coverage reports for 138 @type packages: [str] 139 @param html: (optional) if not None, directory to generate html report to 140 @type html: str 141 """ 142 if _cov is None: 143 return 144 import os 145 import sys 146 try: 147 _cov.stop() 148 # accumulate results 149 _cov.save() 150 151 # - update our own .coverage-modules file list for 152 # coverage-html tool. The reason we read and rewrite instead 153 # of append is that this does a uniqueness check to keep the 154 # file from growing unbounded 155 if os.path.exists('.coverage-modules'): 156 with open('.coverage-modules', 'r') as f: 157 all_packages = set([x for x in f.read().split('\n') if x.strip()] + packages) 158 else: 159 all_packages = set(packages) 160 with open('.coverage-modules', 'w') as f: 161 f.write('\n'.join(all_packages)+'\n') 162 163 try: 164 # list of all modules for html report 165 all_mods = [] 166 167 # iterate over packages to generate per-package console reports 168 for package in packages: 169 __import__(package) 170 m = [v for v in sys.modules.values() if v and v.__name__.startswith(package)] 171 all_mods.extend(m) 172 173 # generate overall report and per module analysis 174 _cov.report(m, show_missing=0) 175 for mod in m: 176 res = _cov.analysis(mod) 177 print('\n%s:\nMissing lines: %s' % (res[0], res[3])) 178 179 if html: 180 181 print('=' * 80 + '\ngenerating html coverage report to %s\n' % html + '=' * 80) 182 _cov.html_report(all_mods, directory=html) 183 except ImportError: 184 print("WARNING: cannot import '%s', will not generate coverage report" % package, file=sys.stderr) 185 except ImportError: 186 print("""WARNING: cannot import python-coverage, coverage tests will not run. 187 To install coverage, run 'easy_install coverage'""", file=sys.stderr)
188