Mercurial > repos > melissacline > ucsc_xena_platform
comparison python-daemon-2.0.5/test/scaffold.py @ 33:7ceb967147c3
start xena with no gui
add library files
author | jingchunzhu <jingchunzhu@gmail.com> |
---|---|
date | Wed, 22 Jul 2015 13:24:44 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
32:63b1ba1e3424 | 33:7ceb967147c3 |
---|---|
1 # -*- coding: utf-8 -*- | |
2 | |
3 # test/scaffold.py | |
4 # Part of ‘python-daemon’, an implementation of PEP 3143. | |
5 # | |
6 # Copyright © 2007–2015 Ben Finney <ben+python@benfinney.id.au> | |
7 # | |
8 # This is free software: you may copy, modify, and/or distribute this work | |
9 # under the terms of the Apache License, version 2.0 as published by the | |
10 # Apache Software Foundation. | |
11 # No warranty expressed or implied. See the file ‘LICENSE.ASF-2’ for details. | |
12 | |
13 """ Scaffolding for unit test modules. | |
14 """ | |
15 | |
16 from __future__ import (absolute_import, unicode_literals) | |
17 | |
18 import unittest | |
19 import doctest | |
20 import logging | |
21 import os | |
22 import sys | |
23 import operator | |
24 import textwrap | |
25 from copy import deepcopy | |
26 import functools | |
27 | |
28 try: | |
29 # Python 2 has both ‘str’ (bytes) and ‘unicode’ (text). | |
30 basestring = basestring | |
31 unicode = unicode | |
32 except NameError: | |
33 # Python 3 names the Unicode data type ‘str’. | |
34 basestring = str | |
35 unicode = str | |
36 | |
37 import testscenarios | |
38 import testtools.testcase | |
39 | |
40 | |
41 test_dir = os.path.dirname(os.path.abspath(__file__)) | |
42 parent_dir = os.path.dirname(test_dir) | |
43 if not test_dir in sys.path: | |
44 sys.path.insert(1, test_dir) | |
45 if not parent_dir in sys.path: | |
46 sys.path.insert(1, parent_dir) | |
47 | |
48 # Disable all but the most critical logging messages. | |
49 logging.disable(logging.CRITICAL) | |
50 | |
51 | |
52 def get_function_signature(func): | |
53 """ Get the function signature as a mapping of attributes. | |
54 | |
55 :param func: The function object to interrogate. | |
56 :return: A mapping of the components of a function signature. | |
57 | |
58 The signature is constructed as a mapping: | |
59 | |
60 * 'name': The function's defined name. | |
61 * 'arg_count': The number of arguments expected by the function. | |
62 * 'arg_names': A sequence of the argument names, as strings. | |
63 * 'arg_defaults': A sequence of the default values for the arguments. | |
64 * 'va_args': The name bound to remaining positional arguments. | |
65 * 'va_kw_args': The name bound to remaining keyword arguments. | |
66 | |
67 """ | |
68 try: | |
69 # Python 3 function attributes. | |
70 func_code = func.__code__ | |
71 func_defaults = func.__defaults__ | |
72 except AttributeError: | |
73 # Python 2 function attributes. | |
74 func_code = func.func_code | |
75 func_defaults = func.func_defaults | |
76 | |
77 arg_count = func_code.co_argcount | |
78 arg_names = func_code.co_varnames[:arg_count] | |
79 | |
80 arg_defaults = {} | |
81 if func_defaults is not None: | |
82 arg_defaults = dict( | |
83 (name, value) | |
84 for (name, value) in | |
85 zip(arg_names[::-1], func_defaults[::-1])) | |
86 | |
87 signature = { | |
88 'name': func.__name__, | |
89 'arg_count': arg_count, | |
90 'arg_names': arg_names, | |
91 'arg_defaults': arg_defaults, | |
92 } | |
93 | |
94 non_pos_names = list(func_code.co_varnames[arg_count:]) | |
95 COLLECTS_ARBITRARY_POSITIONAL_ARGS = 0x04 | |
96 if func_code.co_flags & COLLECTS_ARBITRARY_POSITIONAL_ARGS: | |
97 signature['var_args'] = non_pos_names.pop(0) | |
98 COLLECTS_ARBITRARY_KEYWORD_ARGS = 0x08 | |
99 if func_code.co_flags & COLLECTS_ARBITRARY_KEYWORD_ARGS: | |
100 signature['var_kw_args'] = non_pos_names.pop(0) | |
101 | |
102 return signature | |
103 | |
104 | |
105 def format_function_signature(func): | |
106 """ Format the function signature as printable text. | |
107 | |
108 :param func: The function object to interrogate. | |
109 :return: A formatted text representation of the function signature. | |
110 | |
111 The signature is rendered a text; for example:: | |
112 | |
113 foo(spam, eggs, ham=True, beans=None, *args, **kwargs) | |
114 | |
115 """ | |
116 signature = get_function_signature(func) | |
117 | |
118 args_text = [] | |
119 for arg_name in signature['arg_names']: | |
120 if arg_name in signature['arg_defaults']: | |
121 arg_text = "{name}={value!r}".format( | |
122 name=arg_name, value=signature['arg_defaults'][arg_name]) | |
123 else: | |
124 arg_text = "{name}".format( | |
125 name=arg_name) | |
126 args_text.append(arg_text) | |
127 if 'var_args' in signature: | |
128 args_text.append("*{var_args}".format(signature)) | |
129 if 'var_kw_args' in signature: | |
130 args_text.append("**{var_kw_args}".format(signature)) | |
131 signature_args_text = ", ".join(args_text) | |
132 | |
133 func_name = signature['name'] | |
134 signature_text = "{name}({args})".format( | |
135 name=func_name, args=signature_args_text) | |
136 | |
137 return signature_text | |
138 | |
139 | |
140 class TestCase(testtools.testcase.TestCase): | |
141 """ Test case behaviour. """ | |
142 | |
143 def failUnlessOutputCheckerMatch(self, want, got, msg=None): | |
144 """ Fail unless the specified string matches the expected. | |
145 | |
146 :param want: The desired output pattern. | |
147 :param got: The actual text to match. | |
148 :param msg: A message to prefix on the failure message. | |
149 :return: ``None``. | |
150 :raises self.failureException: If the text does not match. | |
151 | |
152 Fail the test unless ``want`` matches ``got``, as determined by | |
153 a ``doctest.OutputChecker`` instance. This is not an equality | |
154 check, but a pattern match according to the ``OutputChecker`` | |
155 rules. | |
156 | |
157 """ | |
158 checker = doctest.OutputChecker() | |
159 want = textwrap.dedent(want) | |
160 source = "" | |
161 example = doctest.Example(source, want) | |
162 got = textwrap.dedent(got) | |
163 checker_optionflags = functools.reduce(operator.or_, [ | |
164 doctest.ELLIPSIS, | |
165 ]) | |
166 if not checker.check_output(want, got, checker_optionflags): | |
167 if msg is None: | |
168 diff = checker.output_difference( | |
169 example, got, checker_optionflags) | |
170 msg = "\n".join([ | |
171 "Output received did not match expected output", | |
172 "{diff}", | |
173 ]).format( | |
174 diff=diff) | |
175 raise self.failureException(msg) | |
176 | |
177 assertOutputCheckerMatch = failUnlessOutputCheckerMatch | |
178 | |
179 def failUnlessFunctionInTraceback(self, traceback, function, msg=None): | |
180 """ Fail if the function is not in the traceback. | |
181 | |
182 :param traceback: The traceback object to interrogate. | |
183 :param function: The function object to match. | |
184 :param msg: A message to prefix on the failure message. | |
185 :return: ``None``. | |
186 | |
187 :raises self.failureException: If the function is not in the | |
188 traceback. | |
189 | |
190 Fail the test if the function ``function`` is not at any of the | |
191 levels in the traceback object ``traceback``. | |
192 | |
193 """ | |
194 func_in_traceback = False | |
195 expected_code = function.func_code | |
196 current_traceback = traceback | |
197 while current_traceback is not None: | |
198 if expected_code is current_traceback.tb_frame.f_code: | |
199 func_in_traceback = True | |
200 break | |
201 current_traceback = current_traceback.tb_next | |
202 | |
203 if not func_in_traceback: | |
204 if msg is None: | |
205 msg = ( | |
206 "Traceback did not lead to original function" | |
207 " {function}" | |
208 ).format( | |
209 function=function) | |
210 raise self.failureException(msg) | |
211 | |
212 assertFunctionInTraceback = failUnlessFunctionInTraceback | |
213 | |
214 def failUnlessFunctionSignatureMatch(self, first, second, msg=None): | |
215 """ Fail if the function signatures do not match. | |
216 | |
217 :param first: The first function to compare. | |
218 :param second: The second function to compare. | |
219 :param msg: A message to prefix to the failure message. | |
220 :return: ``None``. | |
221 | |
222 :raises self.failureException: If the function signatures do | |
223 not match. | |
224 | |
225 Fail the test if the function signature does not match between | |
226 the ``first`` function and the ``second`` function. | |
227 | |
228 The function signature includes: | |
229 | |
230 * function name, | |
231 | |
232 * count of named parameters, | |
233 | |
234 * sequence of named parameters, | |
235 | |
236 * default values of named parameters, | |
237 | |
238 * collector for arbitrary positional arguments, | |
239 | |
240 * collector for arbitrary keyword arguments. | |
241 | |
242 """ | |
243 first_signature = get_function_signature(first) | |
244 second_signature = get_function_signature(second) | |
245 | |
246 if first_signature != second_signature: | |
247 if msg is None: | |
248 first_signature_text = format_function_signature(first) | |
249 second_signature_text = format_function_signature(second) | |
250 msg = (textwrap.dedent("""\ | |
251 Function signatures do not match: | |
252 {first!r} != {second!r} | |
253 Expected: | |
254 {first_text} | |
255 Got: | |
256 {second_text}""") | |
257 ).format( | |
258 first=first_signature, | |
259 first_text=first_signature_text, | |
260 second=second_signature, | |
261 second_text=second_signature_text, | |
262 ) | |
263 raise self.failureException(msg) | |
264 | |
265 assertFunctionSignatureMatch = failUnlessFunctionSignatureMatch | |
266 | |
267 | |
268 class TestCaseWithScenarios(testscenarios.WithScenarios, TestCase): | |
269 """ Test cases run per scenario. """ | |
270 | |
271 | |
272 class Exception_TestCase(TestCaseWithScenarios): | |
273 """ Test cases for exception classes. """ | |
274 | |
275 def test_exception_instance(self): | |
276 """ Exception instance should be created. """ | |
277 self.assertIsNot(self.instance, None) | |
278 | |
279 def test_exception_types(self): | |
280 """ Exception instance should match expected types. """ | |
281 for match_type in self.types: | |
282 self.assertIsInstance(self.instance, match_type) | |
283 | |
284 | |
285 def make_exception_scenarios(scenarios): | |
286 """ Make test scenarios for exception classes. | |
287 | |
288 :param scenarios: Sequence of scenarios. | |
289 :return: List of scenarios with additional mapping entries. | |
290 | |
291 Use this with `testscenarios` to adapt `Exception_TestCase`_ for | |
292 any exceptions that need testing. | |
293 | |
294 Each scenario is a tuple (`name`, `map`) where `map` is a mapping | |
295 of attributes to be applied to each test case. Attributes map must | |
296 contain items for: | |
297 | |
298 :key exc_type: | |
299 The exception type to be tested. | |
300 :key min_args: | |
301 The minimum argument count for the exception instance | |
302 initialiser. | |
303 :key types: | |
304 Sequence of types that should be superclasses of each | |
305 instance of the exception type. | |
306 | |
307 """ | |
308 updated_scenarios = deepcopy(scenarios) | |
309 for (name, scenario) in updated_scenarios: | |
310 args = (None,) * scenario['min_args'] | |
311 scenario['args'] = args | |
312 instance = scenario['exc_type'](*args) | |
313 scenario['instance'] = instance | |
314 | |
315 return updated_scenarios | |
316 | |
317 | |
318 # Local variables: | |
319 # coding: utf-8 | |
320 # mode: python | |
321 # End: | |
322 # vim: fileencoding=utf-8 filetype=python : |