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 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
72 import sys
73 sysargs = sys.argv
74
75 import unittest
76
77 if coverage_packages is None:
78 coverage_packages = [package]
79
80
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
92 suite = None
93 if isinstance(test, str):
94 suite = unittest.TestLoader().loadTestsFromName(test)
95 else:
96
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
108 print_unittest_summary(result)
109
110 if not result.wasSuccessful():
111 import sys
112 sys.exit(1)
113
114
115
116 _cov = None
117
118
120 global _cov
121 try:
122 import coverage
123 try:
124 _cov = coverage.coverage()
125
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
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
149 _cov.save()
150
151
152
153
154
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
165 all_mods = []
166
167
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
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