##// END OF EJS Templates
suppress warnings in ipexec tests...
Min RK -
Show More
@@ -1,495 +1,498 b''
1 """Generic testing tools.
1 """Generic testing tools.
2
2
3 Authors
3 Authors
4 -------
4 -------
5 - Fernando Perez <Fernando.Perez@berkeley.edu>
5 - Fernando Perez <Fernando.Perez@berkeley.edu>
6 """
6 """
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2009 The IPython Development Team
11 # Copyright (C) 2009 The IPython Development Team
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 import os
21 import os
22 import re
22 import re
23 import sys
23 import sys
24 import tempfile
24 import tempfile
25
25
26 from contextlib import contextmanager
26 from contextlib import contextmanager
27 from io import StringIO
27 from io import StringIO
28 from subprocess import Popen, PIPE
28 from subprocess import Popen, PIPE
29
29
30 try:
30 try:
31 # These tools are used by parts of the runtime, so we make the nose
31 # These tools are used by parts of the runtime, so we make the nose
32 # dependency optional at this point. Nose is a hard dependency to run the
32 # dependency optional at this point. Nose is a hard dependency to run the
33 # test suite, but NOT to use ipython itself.
33 # test suite, but NOT to use ipython itself.
34 import nose.tools as nt
34 import nose.tools as nt
35 has_nose = True
35 has_nose = True
36 except ImportError:
36 except ImportError:
37 has_nose = False
37 has_nose = False
38
38
39 from IPython.config.loader import Config
39 from IPython.config.loader import Config
40 from IPython.utils.process import get_output_error_code
40 from IPython.utils.process import get_output_error_code
41 from IPython.utils.text import list_strings
41 from IPython.utils.text import list_strings
42 from IPython.utils.io import temp_pyfile, Tee
42 from IPython.utils.io import temp_pyfile, Tee
43 from IPython.utils import py3compat
43 from IPython.utils import py3compat
44 from IPython.utils.encoding import DEFAULT_ENCODING
44 from IPython.utils.encoding import DEFAULT_ENCODING
45
45
46 from . import decorators as dec
46 from . import decorators as dec
47 from . import skipdoctest
47 from . import skipdoctest
48
48
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50 # Functions and classes
50 # Functions and classes
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52
52
53 # The docstring for full_path doctests differently on win32 (different path
53 # The docstring for full_path doctests differently on win32 (different path
54 # separator) so just skip the doctest there. The example remains informative.
54 # separator) so just skip the doctest there. The example remains informative.
55 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
55 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
56
56
57 @doctest_deco
57 @doctest_deco
58 def full_path(startPath,files):
58 def full_path(startPath,files):
59 """Make full paths for all the listed files, based on startPath.
59 """Make full paths for all the listed files, based on startPath.
60
60
61 Only the base part of startPath is kept, since this routine is typically
61 Only the base part of startPath is kept, since this routine is typically
62 used with a script's ``__file__`` variable as startPath. The base of startPath
62 used with a script's ``__file__`` variable as startPath. The base of startPath
63 is then prepended to all the listed files, forming the output list.
63 is then prepended to all the listed files, forming the output list.
64
64
65 Parameters
65 Parameters
66 ----------
66 ----------
67 startPath : string
67 startPath : string
68 Initial path to use as the base for the results. This path is split
68 Initial path to use as the base for the results. This path is split
69 using os.path.split() and only its first component is kept.
69 using os.path.split() and only its first component is kept.
70
70
71 files : string or list
71 files : string or list
72 One or more files.
72 One or more files.
73
73
74 Examples
74 Examples
75 --------
75 --------
76
76
77 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
77 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
78 ['/foo/a.txt', '/foo/b.txt']
78 ['/foo/a.txt', '/foo/b.txt']
79
79
80 >>> full_path('/foo',['a.txt','b.txt'])
80 >>> full_path('/foo',['a.txt','b.txt'])
81 ['/a.txt', '/b.txt']
81 ['/a.txt', '/b.txt']
82
82
83 If a single file is given, the output is still a list::
83 If a single file is given, the output is still a list::
84
84
85 >>> full_path('/foo','a.txt')
85 >>> full_path('/foo','a.txt')
86 ['/a.txt']
86 ['/a.txt']
87 """
87 """
88
88
89 files = list_strings(files)
89 files = list_strings(files)
90 base = os.path.split(startPath)[0]
90 base = os.path.split(startPath)[0]
91 return [ os.path.join(base,f) for f in files ]
91 return [ os.path.join(base,f) for f in files ]
92
92
93
93
94 def parse_test_output(txt):
94 def parse_test_output(txt):
95 """Parse the output of a test run and return errors, failures.
95 """Parse the output of a test run and return errors, failures.
96
96
97 Parameters
97 Parameters
98 ----------
98 ----------
99 txt : str
99 txt : str
100 Text output of a test run, assumed to contain a line of one of the
100 Text output of a test run, assumed to contain a line of one of the
101 following forms::
101 following forms::
102
102
103 'FAILED (errors=1)'
103 'FAILED (errors=1)'
104 'FAILED (failures=1)'
104 'FAILED (failures=1)'
105 'FAILED (errors=1, failures=1)'
105 'FAILED (errors=1, failures=1)'
106
106
107 Returns
107 Returns
108 -------
108 -------
109 nerr, nfail
109 nerr, nfail
110 number of errors and failures.
110 number of errors and failures.
111 """
111 """
112
112
113 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
113 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
114 if err_m:
114 if err_m:
115 nerr = int(err_m.group(1))
115 nerr = int(err_m.group(1))
116 nfail = 0
116 nfail = 0
117 return nerr, nfail
117 return nerr, nfail
118
118
119 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
119 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
120 if fail_m:
120 if fail_m:
121 nerr = 0
121 nerr = 0
122 nfail = int(fail_m.group(1))
122 nfail = int(fail_m.group(1))
123 return nerr, nfail
123 return nerr, nfail
124
124
125 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
125 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
126 re.MULTILINE)
126 re.MULTILINE)
127 if both_m:
127 if both_m:
128 nerr = int(both_m.group(1))
128 nerr = int(both_m.group(1))
129 nfail = int(both_m.group(2))
129 nfail = int(both_m.group(2))
130 return nerr, nfail
130 return nerr, nfail
131
131
132 # If the input didn't match any of these forms, assume no error/failures
132 # If the input didn't match any of these forms, assume no error/failures
133 return 0, 0
133 return 0, 0
134
134
135
135
136 # So nose doesn't think this is a test
136 # So nose doesn't think this is a test
137 parse_test_output.__test__ = False
137 parse_test_output.__test__ = False
138
138
139
139
140 def default_argv():
140 def default_argv():
141 """Return a valid default argv for creating testing instances of ipython"""
141 """Return a valid default argv for creating testing instances of ipython"""
142
142
143 return ['--quick', # so no config file is loaded
143 return ['--quick', # so no config file is loaded
144 # Other defaults to minimize side effects on stdout
144 # Other defaults to minimize side effects on stdout
145 '--colors=NoColor', '--no-term-title','--no-banner',
145 '--colors=NoColor', '--no-term-title','--no-banner',
146 '--autocall=0']
146 '--autocall=0']
147
147
148
148
149 def default_config():
149 def default_config():
150 """Return a config object with good defaults for testing."""
150 """Return a config object with good defaults for testing."""
151 config = Config()
151 config = Config()
152 config.TerminalInteractiveShell.colors = 'NoColor'
152 config.TerminalInteractiveShell.colors = 'NoColor'
153 config.TerminalTerminalInteractiveShell.term_title = False,
153 config.TerminalTerminalInteractiveShell.term_title = False,
154 config.TerminalInteractiveShell.autocall = 0
154 config.TerminalInteractiveShell.autocall = 0
155 f = tempfile.NamedTemporaryFile(suffix=u'test_hist.sqlite', delete=False)
155 f = tempfile.NamedTemporaryFile(suffix=u'test_hist.sqlite', delete=False)
156 config.HistoryManager.hist_file = f.name
156 config.HistoryManager.hist_file = f.name
157 f.close()
157 f.close()
158 config.HistoryManager.db_cache_size = 10000
158 config.HistoryManager.db_cache_size = 10000
159 return config
159 return config
160
160
161
161
162 def get_ipython_cmd(as_string=False):
162 def get_ipython_cmd(as_string=False):
163 """
163 """
164 Return appropriate IPython command line name. By default, this will return
164 Return appropriate IPython command line name. By default, this will return
165 a list that can be used with subprocess.Popen, for example, but passing
165 a list that can be used with subprocess.Popen, for example, but passing
166 `as_string=True` allows for returning the IPython command as a string.
166 `as_string=True` allows for returning the IPython command as a string.
167
167
168 Parameters
168 Parameters
169 ----------
169 ----------
170 as_string: bool
170 as_string: bool
171 Flag to allow to return the command as a string.
171 Flag to allow to return the command as a string.
172 """
172 """
173 ipython_cmd = [sys.executable, "-m", "IPython"]
173 ipython_cmd = [sys.executable, "-m", "IPython"]
174
174
175 if as_string:
175 if as_string:
176 ipython_cmd = " ".join(ipython_cmd)
176 ipython_cmd = " ".join(ipython_cmd)
177
177
178 return ipython_cmd
178 return ipython_cmd
179
179
180 def ipexec(fname, options=None, commands=()):
180 def ipexec(fname, options=None, commands=()):
181 """Utility to call 'ipython filename'.
181 """Utility to call 'ipython filename'.
182
182
183 Starts IPython with a minimal and safe configuration to make startup as fast
183 Starts IPython with a minimal and safe configuration to make startup as fast
184 as possible.
184 as possible.
185
185
186 Note that this starts IPython in a subprocess!
186 Note that this starts IPython in a subprocess!
187
187
188 Parameters
188 Parameters
189 ----------
189 ----------
190 fname : str
190 fname : str
191 Name of file to be executed (should have .py or .ipy extension).
191 Name of file to be executed (should have .py or .ipy extension).
192
192
193 options : optional, list
193 options : optional, list
194 Extra command-line flags to be passed to IPython.
194 Extra command-line flags to be passed to IPython.
195
195
196 commands : optional, list
196 commands : optional, list
197 Commands to send in on stdin
197 Commands to send in on stdin
198
198
199 Returns
199 Returns
200 -------
200 -------
201 (stdout, stderr) of ipython subprocess.
201 (stdout, stderr) of ipython subprocess.
202 """
202 """
203 if options is None: options = []
203 if options is None: options = []
204
204
205 # For these subprocess calls, eliminate all prompt printing so we only see
205 # For these subprocess calls, eliminate all prompt printing so we only see
206 # output from script execution
206 # output from script execution
207 prompt_opts = [ '--PromptManager.in_template=""',
207 prompt_opts = [ '--PromptManager.in_template=""',
208 '--PromptManager.in2_template=""',
208 '--PromptManager.in2_template=""',
209 '--PromptManager.out_template=""'
209 '--PromptManager.out_template=""'
210 ]
210 ]
211 cmdargs = default_argv() + prompt_opts + options
211 cmdargs = default_argv() + prompt_opts + options
212
212
213 test_dir = os.path.dirname(__file__)
213 test_dir = os.path.dirname(__file__)
214
214
215 ipython_cmd = get_ipython_cmd()
215 ipython_cmd = get_ipython_cmd()
216 # Absolute path for filename
216 # Absolute path for filename
217 full_fname = os.path.join(test_dir, fname)
217 full_fname = os.path.join(test_dir, fname)
218 full_cmd = ipython_cmd + cmdargs + [full_fname]
218 full_cmd = ipython_cmd + cmdargs + [full_fname]
219 env = os.environ.copy()
219 env = os.environ.copy()
220 env.pop('PYTHONWARNINGS', None) # Avoid extraneous warnings appearing on stderr
220 # FIXME: ignore all warnings in ipexec while we have shims
221 # should we keep suppressing warnings here, even after removing shims?
222 env['PYTHONWARNINGS'] = 'ignore'
223 # env.pop('PYTHONWARNINGS', None) # Avoid extraneous warnings appearing on stderr
221 for k, v in env.items():
224 for k, v in env.items():
222 # Debug a bizarre failure we've seen on Windows:
225 # Debug a bizarre failure we've seen on Windows:
223 # TypeError: environment can only contain strings
226 # TypeError: environment can only contain strings
224 if not isinstance(v, str):
227 if not isinstance(v, str):
225 print(k, v)
228 print(k, v)
226 p = Popen(full_cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE, env=env)
229 p = Popen(full_cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE, env=env)
227 out, err = p.communicate(input=py3compat.str_to_bytes('\n'.join(commands)) or None)
230 out, err = p.communicate(input=py3compat.str_to_bytes('\n'.join(commands)) or None)
228 out, err = py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
231 out, err = py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
229 # `import readline` causes 'ESC[?1034h' to be output sometimes,
232 # `import readline` causes 'ESC[?1034h' to be output sometimes,
230 # so strip that out before doing comparisons
233 # so strip that out before doing comparisons
231 if out:
234 if out:
232 out = re.sub(r'\x1b\[[^h]+h', '', out)
235 out = re.sub(r'\x1b\[[^h]+h', '', out)
233 return out, err
236 return out, err
234
237
235
238
236 def ipexec_validate(fname, expected_out, expected_err='',
239 def ipexec_validate(fname, expected_out, expected_err='',
237 options=None, commands=()):
240 options=None, commands=()):
238 """Utility to call 'ipython filename' and validate output/error.
241 """Utility to call 'ipython filename' and validate output/error.
239
242
240 This function raises an AssertionError if the validation fails.
243 This function raises an AssertionError if the validation fails.
241
244
242 Note that this starts IPython in a subprocess!
245 Note that this starts IPython in a subprocess!
243
246
244 Parameters
247 Parameters
245 ----------
248 ----------
246 fname : str
249 fname : str
247 Name of the file to be executed (should have .py or .ipy extension).
250 Name of the file to be executed (should have .py or .ipy extension).
248
251
249 expected_out : str
252 expected_out : str
250 Expected stdout of the process.
253 Expected stdout of the process.
251
254
252 expected_err : optional, str
255 expected_err : optional, str
253 Expected stderr of the process.
256 Expected stderr of the process.
254
257
255 options : optional, list
258 options : optional, list
256 Extra command-line flags to be passed to IPython.
259 Extra command-line flags to be passed to IPython.
257
260
258 Returns
261 Returns
259 -------
262 -------
260 None
263 None
261 """
264 """
262
265
263 import nose.tools as nt
266 import nose.tools as nt
264
267
265 out, err = ipexec(fname, options, commands)
268 out, err = ipexec(fname, options, commands)
266 #print 'OUT', out # dbg
269 #print 'OUT', out # dbg
267 #print 'ERR', err # dbg
270 #print 'ERR', err # dbg
268 # If there are any errors, we must check those befor stdout, as they may be
271 # If there are any errors, we must check those befor stdout, as they may be
269 # more informative than simply having an empty stdout.
272 # more informative than simply having an empty stdout.
270 if err:
273 if err:
271 if expected_err:
274 if expected_err:
272 nt.assert_equal("\n".join(err.strip().splitlines()), "\n".join(expected_err.strip().splitlines()))
275 nt.assert_equal("\n".join(err.strip().splitlines()), "\n".join(expected_err.strip().splitlines()))
273 else:
276 else:
274 raise ValueError('Running file %r produced error: %r' %
277 raise ValueError('Running file %r produced error: %r' %
275 (fname, err))
278 (fname, err))
276 # If no errors or output on stderr was expected, match stdout
279 # If no errors or output on stderr was expected, match stdout
277 nt.assert_equal("\n".join(out.strip().splitlines()), "\n".join(expected_out.strip().splitlines()))
280 nt.assert_equal("\n".join(out.strip().splitlines()), "\n".join(expected_out.strip().splitlines()))
278
281
279
282
280 class TempFileMixin(object):
283 class TempFileMixin(object):
281 """Utility class to create temporary Python/IPython files.
284 """Utility class to create temporary Python/IPython files.
282
285
283 Meant as a mixin class for test cases."""
286 Meant as a mixin class for test cases."""
284
287
285 def mktmp(self, src, ext='.py'):
288 def mktmp(self, src, ext='.py'):
286 """Make a valid python temp file."""
289 """Make a valid python temp file."""
287 fname, f = temp_pyfile(src, ext)
290 fname, f = temp_pyfile(src, ext)
288 self.tmpfile = f
291 self.tmpfile = f
289 self.fname = fname
292 self.fname = fname
290
293
291 def tearDown(self):
294 def tearDown(self):
292 if hasattr(self, 'tmpfile'):
295 if hasattr(self, 'tmpfile'):
293 # If the tmpfile wasn't made because of skipped tests, like in
296 # If the tmpfile wasn't made because of skipped tests, like in
294 # win32, there's nothing to cleanup.
297 # win32, there's nothing to cleanup.
295 self.tmpfile.close()
298 self.tmpfile.close()
296 try:
299 try:
297 os.unlink(self.fname)
300 os.unlink(self.fname)
298 except:
301 except:
299 # On Windows, even though we close the file, we still can't
302 # On Windows, even though we close the file, we still can't
300 # delete it. I have no clue why
303 # delete it. I have no clue why
301 pass
304 pass
302
305
303 pair_fail_msg = ("Testing {0}\n\n"
306 pair_fail_msg = ("Testing {0}\n\n"
304 "In:\n"
307 "In:\n"
305 " {1!r}\n"
308 " {1!r}\n"
306 "Expected:\n"
309 "Expected:\n"
307 " {2!r}\n"
310 " {2!r}\n"
308 "Got:\n"
311 "Got:\n"
309 " {3!r}\n")
312 " {3!r}\n")
310 def check_pairs(func, pairs):
313 def check_pairs(func, pairs):
311 """Utility function for the common case of checking a function with a
314 """Utility function for the common case of checking a function with a
312 sequence of input/output pairs.
315 sequence of input/output pairs.
313
316
314 Parameters
317 Parameters
315 ----------
318 ----------
316 func : callable
319 func : callable
317 The function to be tested. Should accept a single argument.
320 The function to be tested. Should accept a single argument.
318 pairs : iterable
321 pairs : iterable
319 A list of (input, expected_output) tuples.
322 A list of (input, expected_output) tuples.
320
323
321 Returns
324 Returns
322 -------
325 -------
323 None. Raises an AssertionError if any output does not match the expected
326 None. Raises an AssertionError if any output does not match the expected
324 value.
327 value.
325 """
328 """
326 name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
329 name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
327 for inp, expected in pairs:
330 for inp, expected in pairs:
328 out = func(inp)
331 out = func(inp)
329 assert out == expected, pair_fail_msg.format(name, inp, expected, out)
332 assert out == expected, pair_fail_msg.format(name, inp, expected, out)
330
333
331
334
332 if py3compat.PY3:
335 if py3compat.PY3:
333 MyStringIO = StringIO
336 MyStringIO = StringIO
334 else:
337 else:
335 # In Python 2, stdout/stderr can have either bytes or unicode written to them,
338 # In Python 2, stdout/stderr can have either bytes or unicode written to them,
336 # so we need a class that can handle both.
339 # so we need a class that can handle both.
337 class MyStringIO(StringIO):
340 class MyStringIO(StringIO):
338 def write(self, s):
341 def write(self, s):
339 s = py3compat.cast_unicode(s, encoding=DEFAULT_ENCODING)
342 s = py3compat.cast_unicode(s, encoding=DEFAULT_ENCODING)
340 super(MyStringIO, self).write(s)
343 super(MyStringIO, self).write(s)
341
344
342 _re_type = type(re.compile(r''))
345 _re_type = type(re.compile(r''))
343
346
344 notprinted_msg = """Did not find {0!r} in printed output (on {1}):
347 notprinted_msg = """Did not find {0!r} in printed output (on {1}):
345 -------
348 -------
346 {2!s}
349 {2!s}
347 -------
350 -------
348 """
351 """
349
352
350 class AssertPrints(object):
353 class AssertPrints(object):
351 """Context manager for testing that code prints certain text.
354 """Context manager for testing that code prints certain text.
352
355
353 Examples
356 Examples
354 --------
357 --------
355 >>> with AssertPrints("abc", suppress=False):
358 >>> with AssertPrints("abc", suppress=False):
356 ... print("abcd")
359 ... print("abcd")
357 ... print("def")
360 ... print("def")
358 ...
361 ...
359 abcd
362 abcd
360 def
363 def
361 """
364 """
362 def __init__(self, s, channel='stdout', suppress=True):
365 def __init__(self, s, channel='stdout', suppress=True):
363 self.s = s
366 self.s = s
364 if isinstance(self.s, (py3compat.string_types, _re_type)):
367 if isinstance(self.s, (py3compat.string_types, _re_type)):
365 self.s = [self.s]
368 self.s = [self.s]
366 self.channel = channel
369 self.channel = channel
367 self.suppress = suppress
370 self.suppress = suppress
368
371
369 def __enter__(self):
372 def __enter__(self):
370 self.orig_stream = getattr(sys, self.channel)
373 self.orig_stream = getattr(sys, self.channel)
371 self.buffer = MyStringIO()
374 self.buffer = MyStringIO()
372 self.tee = Tee(self.buffer, channel=self.channel)
375 self.tee = Tee(self.buffer, channel=self.channel)
373 setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
376 setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
374
377
375 def __exit__(self, etype, value, traceback):
378 def __exit__(self, etype, value, traceback):
376 try:
379 try:
377 if value is not None:
380 if value is not None:
378 # If an error was raised, don't check anything else
381 # If an error was raised, don't check anything else
379 return False
382 return False
380 self.tee.flush()
383 self.tee.flush()
381 setattr(sys, self.channel, self.orig_stream)
384 setattr(sys, self.channel, self.orig_stream)
382 printed = self.buffer.getvalue()
385 printed = self.buffer.getvalue()
383 for s in self.s:
386 for s in self.s:
384 if isinstance(s, _re_type):
387 if isinstance(s, _re_type):
385 assert s.search(printed), notprinted_msg.format(s.pattern, self.channel, printed)
388 assert s.search(printed), notprinted_msg.format(s.pattern, self.channel, printed)
386 else:
389 else:
387 assert s in printed, notprinted_msg.format(s, self.channel, printed)
390 assert s in printed, notprinted_msg.format(s, self.channel, printed)
388 return False
391 return False
389 finally:
392 finally:
390 self.tee.close()
393 self.tee.close()
391
394
392 printed_msg = """Found {0!r} in printed output (on {1}):
395 printed_msg = """Found {0!r} in printed output (on {1}):
393 -------
396 -------
394 {2!s}
397 {2!s}
395 -------
398 -------
396 """
399 """
397
400
398 class AssertNotPrints(AssertPrints):
401 class AssertNotPrints(AssertPrints):
399 """Context manager for checking that certain output *isn't* produced.
402 """Context manager for checking that certain output *isn't* produced.
400
403
401 Counterpart of AssertPrints"""
404 Counterpart of AssertPrints"""
402 def __exit__(self, etype, value, traceback):
405 def __exit__(self, etype, value, traceback):
403 try:
406 try:
404 if value is not None:
407 if value is not None:
405 # If an error was raised, don't check anything else
408 # If an error was raised, don't check anything else
406 self.tee.close()
409 self.tee.close()
407 return False
410 return False
408 self.tee.flush()
411 self.tee.flush()
409 setattr(sys, self.channel, self.orig_stream)
412 setattr(sys, self.channel, self.orig_stream)
410 printed = self.buffer.getvalue()
413 printed = self.buffer.getvalue()
411 for s in self.s:
414 for s in self.s:
412 if isinstance(s, _re_type):
415 if isinstance(s, _re_type):
413 assert not s.search(printed),printed_msg.format(
416 assert not s.search(printed),printed_msg.format(
414 s.pattern, self.channel, printed)
417 s.pattern, self.channel, printed)
415 else:
418 else:
416 assert s not in printed, printed_msg.format(
419 assert s not in printed, printed_msg.format(
417 s, self.channel, printed)
420 s, self.channel, printed)
418 return False
421 return False
419 finally:
422 finally:
420 self.tee.close()
423 self.tee.close()
421
424
422 @contextmanager
425 @contextmanager
423 def mute_warn():
426 def mute_warn():
424 from IPython.utils import warn
427 from IPython.utils import warn
425 save_warn = warn.warn
428 save_warn = warn.warn
426 warn.warn = lambda *a, **kw: None
429 warn.warn = lambda *a, **kw: None
427 try:
430 try:
428 yield
431 yield
429 finally:
432 finally:
430 warn.warn = save_warn
433 warn.warn = save_warn
431
434
432 @contextmanager
435 @contextmanager
433 def make_tempfile(name):
436 def make_tempfile(name):
434 """ Create an empty, named, temporary file for the duration of the context.
437 """ Create an empty, named, temporary file for the duration of the context.
435 """
438 """
436 f = open(name, 'w')
439 f = open(name, 'w')
437 f.close()
440 f.close()
438 try:
441 try:
439 yield
442 yield
440 finally:
443 finally:
441 os.unlink(name)
444 os.unlink(name)
442
445
443
446
444 @contextmanager
447 @contextmanager
445 def monkeypatch(obj, name, attr):
448 def monkeypatch(obj, name, attr):
446 """
449 """
447 Context manager to replace attribute named `name` in `obj` with `attr`.
450 Context manager to replace attribute named `name` in `obj` with `attr`.
448 """
451 """
449 orig = getattr(obj, name)
452 orig = getattr(obj, name)
450 setattr(obj, name, attr)
453 setattr(obj, name, attr)
451 yield
454 yield
452 setattr(obj, name, orig)
455 setattr(obj, name, orig)
453
456
454
457
455 def help_output_test(subcommand=''):
458 def help_output_test(subcommand=''):
456 """test that `ipython [subcommand] -h` works"""
459 """test that `ipython [subcommand] -h` works"""
457 cmd = get_ipython_cmd() + [subcommand, '-h']
460 cmd = get_ipython_cmd() + [subcommand, '-h']
458 out, err, rc = get_output_error_code(cmd)
461 out, err, rc = get_output_error_code(cmd)
459 nt.assert_equal(rc, 0, err)
462 nt.assert_equal(rc, 0, err)
460 nt.assert_not_in("Traceback", err)
463 nt.assert_not_in("Traceback", err)
461 nt.assert_in("Options", out)
464 nt.assert_in("Options", out)
462 nt.assert_in("--help-all", out)
465 nt.assert_in("--help-all", out)
463 return out, err
466 return out, err
464
467
465
468
466 def help_all_output_test(subcommand=''):
469 def help_all_output_test(subcommand=''):
467 """test that `ipython [subcommand] --help-all` works"""
470 """test that `ipython [subcommand] --help-all` works"""
468 cmd = get_ipython_cmd() + [subcommand, '--help-all']
471 cmd = get_ipython_cmd() + [subcommand, '--help-all']
469 out, err, rc = get_output_error_code(cmd)
472 out, err, rc = get_output_error_code(cmd)
470 nt.assert_equal(rc, 0, err)
473 nt.assert_equal(rc, 0, err)
471 nt.assert_not_in("Traceback", err)
474 nt.assert_not_in("Traceback", err)
472 nt.assert_in("Options", out)
475 nt.assert_in("Options", out)
473 nt.assert_in("Class parameters", out)
476 nt.assert_in("Class parameters", out)
474 return out, err
477 return out, err
475
478
476 def assert_big_text_equal(a, b, chunk_size=80):
479 def assert_big_text_equal(a, b, chunk_size=80):
477 """assert that large strings are equal
480 """assert that large strings are equal
478
481
479 Zooms in on first chunk that differs,
482 Zooms in on first chunk that differs,
480 to give better info than vanilla assertEqual for large text blobs.
483 to give better info than vanilla assertEqual for large text blobs.
481 """
484 """
482 for i in range(0, len(a), chunk_size):
485 for i in range(0, len(a), chunk_size):
483 chunk_a = a[i:i + chunk_size]
486 chunk_a = a[i:i + chunk_size]
484 chunk_b = b[i:i + chunk_size]
487 chunk_b = b[i:i + chunk_size]
485 nt.assert_equal(chunk_a, chunk_b, "[offset: %i]\n%r != \n%r" % (
488 nt.assert_equal(chunk_a, chunk_b, "[offset: %i]\n%r != \n%r" % (
486 i, chunk_a, chunk_b))
489 i, chunk_a, chunk_b))
487
490
488 if len(a) > len(b):
491 if len(a) > len(b):
489 nt.fail("Length doesn't match (%i > %i). Extra text:\n%r" % (
492 nt.fail("Length doesn't match (%i > %i). Extra text:\n%r" % (
490 len(a), len(b), a[len(b):]
493 len(a), len(b), a[len(b):]
491 ))
494 ))
492 elif len(a) < len(b):
495 elif len(a) < len(b):
493 nt.fail("Length doesn't match (%i < %i). Extra text:\n%r" % (
496 nt.fail("Length doesn't match (%i < %i). Extra text:\n%r" % (
494 len(a), len(b), b[len(a):]
497 len(a), len(b), b[len(a):]
495 ))
498 ))
General Comments 0
You need to be logged in to leave comments. Login now