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: pyunit.py 13649 2011-04-12 18:05:44Z kwc $ 
 34   
 35  """ 
 36  Wrapper for running Python unittest within rosunit/rostest framework. 
 37  """ 
 38  from __future__ import with_statement 
 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 coverage_packages: list of Python package to compute coverage results for. Defaults to package 61 @type coverage_packages: [str] 62 @param sysargs: (optional) alternate sys.argv 63 @type sysargs: [str] 64 """ 65 if sysargs is None: 66 # lazy-init sys args 67 import sys 68 sysargs = sys.argv 69 70 import unittest 71 72 if coverage_packages is None: 73 coverage_packages = [package] 74 75 #parse sysargs 76 result_file = None 77 for arg in sysargs: 78 if arg.startswith(XML_OUTPUT_FLAG): 79 result_file = arg[len(XML_OUTPUT_FLAG):] 80 text_mode = '--text' in sysargs 81 82 coverage_mode = '--cov' in sysargs or '--covhtml' in sysargs 83 if coverage_mode: 84 start_coverage(coverage_packages) 85 86 # create and run unittest suite with our xmllrunner wrapper 87 suite = unittest.TestLoader().loadTestsFromTestCase(test) 88 if text_mode: 89 result = unittest.TextTestRunner(verbosity=2).run(suite) 90 else: 91 result = create_xml_runner(package, test_name, result_file).run(suite) 92 if coverage_mode: 93 cov_html_dir = 'covhtml' if '--covhtml' in sysargs else None 94 stop_coverage(coverage_packages, html=cov_html_dir) 95 96 # test over, summarize results and exit appropriately 97 print_unittest_summary(result) 98 99 if not result.wasSuccessful(): 100 import sys 101 sys.exit(1)
102 103 # coverage instance 104 _cov = None
105 -def start_coverage(packages):
106 global _cov 107 try: 108 import coverage 109 try: 110 _cov = coverage.coverage() 111 # load previous results as we need to accumulate 112 _cov.load() 113 _cov.start() 114 except coverage.CoverageException: 115 print >> sys.stderr, "WARNING: you have an older version of python-coverage that is not support. Please update to the version provided by 'easy_install coverage'" 116 except ImportError, e: 117 print >> sys.stderr, """WARNING: cannot import python-coverage, coverage tests will not run. 118 To install coverage, run 'easy_install coverage'"""
119
120 -def stop_coverage(packages, html=None):
121 """ 122 @param packages: list of packages to generate coverage reports for 123 @type packages: [str] 124 @param html: (optional) if not None, directory to generate html report to 125 @type html: str 126 """ 127 if _cov is None: 128 return 129 import sys, os 130 try: 131 _cov.stop() 132 # accumulate results 133 _cov.save() 134 135 # - update our own .coverage-modules file list for 136 # coverage-html tool. The reason we read and rewrite instead 137 # of append is that this does a uniqueness check to keep the 138 # file from growing unbounded 139 if os.path.exists('.coverage-modules'): 140 with open('.coverage-modules','r') as f: 141 all_packages = set([x for x in f.read().split('\n') if x.strip()] + packages) 142 else: 143 all_packages = set(packages) 144 with open('.coverage-modules','w') as f: 145 f.write('\n'.join(all_packages)+'\n') 146 147 try: 148 # list of all modules for html report 149 all_mods = [] 150 151 # iterate over packages to generate per-package console reports 152 for package in packages: 153 pkg = __import__(package) 154 m = [v for v in sys.modules.values() if v and v.__name__.startswith(package)] 155 all_mods.extend(m) 156 157 # generate overall report and per module analysis 158 _cov.report(m, show_missing=0) 159 for mod in m: 160 res = _cov.analysis(mod) 161 print "\n%s:\nMissing lines: %s"%(res[0], res[3]) 162 163 if html: 164 165 print "="*80+"\ngenerating html coverage report to %s\n"%html+"="*80 166 _cov.html_report(all_mods, directory=html) 167 except ImportError, e: 168 print >> sys.stderr, "WARNING: cannot import '%s', will not generate coverage report"%package 169 except ImportError, e: 170 print >> sys.stderr, """WARNING: cannot import python-coverage, coverage tests will not run. 171 To install coverage, run 'easy_install coverage'"""
172