test_decorators.py
219 lines
| 5.4 KiB
| text/x-python
|
PythonLexer
Fernando Perez
|
r1721 | """Tests for the decorators we've created for IPython. | ||
""" | ||||
# Module imports | ||||
# Std lib | ||||
import inspect | ||||
import sys | ||||
Fernando Perez
|
r2368 | import unittest | ||
Fernando Perez
|
r1721 | |||
# Third party | ||||
import nose.tools as nt | ||||
# Our own | ||||
from IPython.testing import decorators as dec | ||||
Fernando Perez
|
r2368 | from IPython.testing.ipunittest import ParametricTestCase | ||
Fernando Perez
|
r1721 | |||
#----------------------------------------------------------------------------- | ||||
# Utilities | ||||
# Note: copied from OInspect, kept here so the testing stuff doesn't create | ||||
# circular dependencies and is easier to reuse. | ||||
def getargspec(obj): | ||||
"""Get the names and default values of a function's arguments. | ||||
A tuple of four things is returned: (args, varargs, varkw, defaults). | ||||
'args' is a list of the argument names (it may contain nested lists). | ||||
'varargs' and 'varkw' are the names of the * and ** arguments or None. | ||||
'defaults' is an n-tuple of the default values of the last n arguments. | ||||
Modified version of inspect.getargspec from the Python Standard | ||||
Library.""" | ||||
if inspect.isfunction(obj): | ||||
func_obj = obj | ||||
elif inspect.ismethod(obj): | ||||
func_obj = obj.im_func | ||||
else: | ||||
raise TypeError, 'arg is not a Python function' | ||||
args, varargs, varkw = inspect.getargs(func_obj.func_code) | ||||
return args, varargs, varkw, func_obj.func_defaults | ||||
#----------------------------------------------------------------------------- | ||||
# Testing functions | ||||
Fernando Perez
|
r2368 | @dec.as_unittest | ||
def trivial(): | ||||
"""A trivial test""" | ||||
pass | ||||
# Some examples of parametric tests. | ||||
def is_smaller(i,j): | ||||
assert i<j,"%s !< %s" % (i,j) | ||||
class Tester(ParametricTestCase): | ||||
def test_parametric(self): | ||||
yield is_smaller(3, 4) | ||||
x, y = 1, 2 | ||||
yield is_smaller(x, y) | ||||
@dec.parametric | ||||
def test_par_standalone(): | ||||
yield is_smaller(3, 4) | ||||
x, y = 1, 2 | ||||
yield is_smaller(x, y) | ||||
Fernando Perez
|
r1721 | @dec.skip | ||
def test_deliberately_broken(): | ||||
"""A deliberately broken test - we want to skip this one.""" | ||||
1/0 | ||||
Brian Granger
|
r1963 | @dec.skip('Testing the skip decorator') | ||
Fernando Perez
|
r1721 | def test_deliberately_broken2(): | ||
"""Another deliberately broken test - we want to skip this one.""" | ||||
1/0 | ||||
# Verify that we can correctly skip the doctest for a function at will, but | ||||
# that the docstring itself is NOT destroyed by the decorator. | ||||
@dec.skip_doctest | ||||
def doctest_bad(x,y=1,**k): | ||||
"""A function whose doctest we need to skip. | ||||
>>> 1+1 | ||||
3 | ||||
""" | ||||
print 'x:',x | ||||
print 'y:',y | ||||
print 'k:',k | ||||
def call_doctest_bad(): | ||||
"""Check that we can still call the decorated functions. | ||||
>>> doctest_bad(3,y=4) | ||||
x: 3 | ||||
y: 4 | ||||
k: {} | ||||
""" | ||||
pass | ||||
def test_skip_dt_decorator(): | ||||
"""Doctest-skipping decorator should preserve the docstring. | ||||
""" | ||||
# Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring! | ||||
check = """A function whose doctest we need to skip. | ||||
>>> 1+1 | ||||
3 | ||||
""" | ||||
# Fetch the docstring from doctest_bad after decoration. | ||||
val = doctest_bad.__doc__ | ||||
Fernando Perez
|
r2479 | nt.assert_equal(check,val,"doctest_bad docstrings don't match") | ||
Fernando Perez
|
r1721 | |||
# Doctest skipping should work for class methods too | ||||
Fernando Perez
|
r2479 | class FooClass(object): | ||
"""FooClass | ||||
Fernando Perez
|
r1721 | |||
Example: | ||||
>>> 1+1 | ||||
2 | ||||
""" | ||||
@dec.skip_doctest | ||||
def __init__(self,x): | ||||
Fernando Perez
|
r2479 | """Make a FooClass. | ||
Fernando Perez
|
r1721 | |||
Example: | ||||
Fernando Perez
|
r2479 | >>> f = FooClass(3) | ||
Fernando Perez
|
r1721 | junk | ||
""" | ||||
Fernando Perez
|
r2479 | print 'Making a FooClass.' | ||
Fernando Perez
|
r1721 | self.x = x | ||
@dec.skip_doctest | ||||
def bar(self,y): | ||||
"""Example: | ||||
Fernando Perez
|
r2479 | >>> ff = FooClass(3) | ||
>>> ff.bar(0) | ||||
Fernando Perez
|
r1721 | boom! | ||
>>> 1/0 | ||||
bam! | ||||
""" | ||||
return 1/y | ||||
def baz(self,y): | ||||
"""Example: | ||||
Fernando Perez
|
r2479 | >>> ff2 = FooClass(3) | ||
Making a FooClass. | ||||
>>> ff2.baz(3) | ||||
Fernando Perez
|
r1721 | True | ||
""" | ||||
return self.x==y | ||||
def test_skip_dt_decorator2(): | ||||
"""Doctest-skipping decorator should preserve function signature. | ||||
""" | ||||
# Hardcoded correct answer | ||||
dtargs = (['x', 'y'], None, 'k', (1,)) | ||||
# Introspect out the value | ||||
dtargsr = getargspec(doctest_bad) | ||||
assert dtargsr==dtargs, \ | ||||
"Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,) | ||||
@dec.skip_linux | ||||
def test_linux(): | ||||
nt.assert_not_equals(sys.platform,'linux2',"This test can't run under linux") | ||||
@dec.skip_win32 | ||||
def test_win32(): | ||||
nt.assert_not_equals(sys.platform,'win32',"This test can't run under windows") | ||||
@dec.skip_osx | ||||
def test_osx(): | ||||
nt.assert_not_equals(sys.platform,'darwin',"This test can't run under osx") | ||||
Fernando Perez
|
r2368 | |||
# Verify that the same decorators work for methods. | ||||
# Note: this code is identical to that in test_decorators_trial, but that one | ||||
# uses twisted's unittest, not the one from the stdlib, which we are using | ||||
# here. While somewhat redundant, we want to check both with the stdlib and | ||||
# with twisted, so the duplication is OK. | ||||
class TestDecoratorsTrial(unittest.TestCase): | ||||
@dec.skip() | ||||
def test_deliberately_broken(self): | ||||
"""A deliberately broken test - we want to skip this one.""" | ||||
1/0 | ||||
@dec.skip('Testing the skip decorator') | ||||
def test_deliberately_broken2(self): | ||||
"""Another deliberately broken test - we want to skip this one.""" | ||||
1/0 | ||||
@dec.skip_linux | ||||
def test_linux(self): | ||||
self.assertNotEquals(sys.platform, 'linux2', | ||||
"This test can't run under linux") | ||||
@dec.skip_win32 | ||||
def test_win32(self): | ||||
self.assertNotEquals(sys.platform, 'win32', | ||||
"This test can't run under windows") | ||||
@dec.skip_osx | ||||
def test_osx(self): | ||||
self.assertNotEquals(sys.platform, 'darwin', | ||||
"This test can't run under osx") | ||||