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 with_statement, print_function 
 39   
 40  import sys 
 41   
 42  from .core import create_xml_runner, XML_OUTPUT_FLAG 
 43  from .baretest import print_unittest_summary 
 44   
45 -def unitrun(package, test_name, test, sysargs=None, coverage_packages=None):
46 """ 47 Wrapper routine from running python unitttests with 48 JUnit-compatible XML output. This is meant for unittests that do 49 not not need a running ROS graph (i.e. offline tests only). 50 51 This enables JUnit-compatible test reporting so that 52 test results can be reported to higher-level tools. 53 54 WARNING: unitrun() will trigger a sys.exit() on test failure in 55 order to properly exit with an error code. This routine is meant 56 to be used as a main() routine, not as a library. 57 58 @param package: name of ROS package that is running the test 59 @type package: str 60 @param test: a test case instance or a name resolving to a test case or suite 61 @type test: unittest.TestCase, or string 62 @param coverage_packages: list of Python package to compute coverage results for. Defaults to package 63 @type coverage_packages: [str] 64 @param sysargs: (optional) alternate sys.argv 65 @type sysargs: [str] 66 """ 67 if sysargs is None: 68 # lazy-init sys args 69 import sys 70 sysargs = sys.argv 71 72 import unittest 73 74 if coverage_packages is None: 75 coverage_packages = [package] 76 77 #parse sysargs 78 result_file = None 79 for arg in sysargs: 80 if arg.startswith(XML_OUTPUT_FLAG): 81 result_file = arg[len(XML_OUTPUT_FLAG):] 82 text_mode = '--text' in sysargs 83 84 coverage_mode = '--cov' in sysargs or '--covhtml' in sysargs 85 if coverage_mode: 86 start_coverage(coverage_packages) 87 88 # create and run unittest suite with our xmllrunner wrapper 89 suite = None 90 if isinstance(test, str): 91 suite = unittest.TestLoader().loadTestsFromName(test) 92 else: 93 # some callers pass a TestCase type (instead of an instance) 94 suite = unittest.TestLoader().loadTestsFromTestCase(test) 95 96 if text_mode: 97 result = unittest.TextTestRunner(verbosity=2).run(suite) 98 else: 99 result = create_xml_runner(package, test_name, result_file).run(suite) 100 if coverage_mode: 101 cov_html_dir = 'covhtml' if '--covhtml' in sysargs else None 102 stop_coverage(coverage_packages, html=cov_html_dir) 103 104 # test over, summarize results and exit appropriately 105 print_unittest_summary(result) 106 107 if not result.wasSuccessful(): 108 import sys 109 sys.exit(1)
110 111 # coverage instance 112 _cov = None
113 -def start_coverage(packages):
114 global _cov 115 try: 116 import coverage 117 try: 118 _cov = coverage.coverage() 119 # load previous results as we need to accumulate 120 _cov.load() 121 _cov.start() 122 except coverage.CoverageException: 123 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) 124 except ImportError as e: 125 print("""WARNING: cannot import python-coverage, coverage tests will not run. 126 To install coverage, run 'easy_install coverage'""", file=sys.stderr)
127
128 -def stop_coverage(packages, html=None):
129 """ 130 @param packages: list of packages to generate coverage reports for 131 @type packages: [str] 132 @param html: (optional) if not None, directory to generate html report to 133 @type html: str 134 """ 135 if _cov is None: 136 return 137 import sys, os 138 try: 139 _cov.stop() 140 # accumulate results 141 _cov.save() 142 143 # - update our own .coverage-modules file list for 144 # coverage-html tool. The reason we read and rewrite instead 145 # of append is that this does a uniqueness check to keep the 146 # file from growing unbounded 147 if os.path.exists('.coverage-modules'): 148 with open('.coverage-modules','r') as f: 149 all_packages = set([x for x in f.read().split('\n') if x.strip()] + packages) 150 else: 151 all_packages = set(packages) 152 with open('.coverage-modules','w') as f: 153 f.write('\n'.join(all_packages)+'\n') 154 155 try: 156 # list of all modules for html report 157 all_mods = [] 158 159 # iterate over packages to generate per-package console reports 160 for package in packages: 161 pkg = __import__(package) 162 m = [v for v in sys.modules.values() if v and v.__name__.startswith(package)] 163 all_mods.extend(m) 164 165 # generate overall report and per module analysis 166 _cov.report(m, show_missing=0) 167 for mod in m: 168 res = _cov.analysis(mod) 169 print("\n%s:\nMissing lines: %s"%(res[0], res[3])) 170 171 if html: 172 173 print("="*80+"\ngenerating html coverage report to %s\n"%html+"="*80) 174 _cov.html_report(all_mods, directory=html) 175 except ImportError as e: 176 print("WARNING: cannot import '%s', will not generate coverage report"%package, file=sys.stderr) 177 except ImportError as e: 178 print("""WARNING: cannot import python-coverage, coverage tests will not run. 179 To install coverage, run 'easy_install coverage'""", file=sys.stderr)
180