1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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
69 import sys
70 sysargs = sys.argv
71
72 import unittest
73
74 if coverage_packages is None:
75 coverage_packages = [package]
76
77
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
89 suite = None
90 if isinstance(test, str):
91 suite = unittest.TestLoader().loadTestsFromName(test)
92 else:
93
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
105 print_unittest_summary(result)
106
107 if not result.wasSuccessful():
108 import sys
109 sys.exit(1)
110
111
112 _cov = None
114 global _cov
115 try:
116 import coverage
117 try:
118 _cov = coverage.coverage()
119
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
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
141 _cov.save()
142
143
144
145
146
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
157 all_mods = []
158
159
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
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