##// END OF EJS Templates
Merging in Fernando's test decorator work.
Brian Granger -
r1722:82252d15 merge
parent child Browse files
Show More
@@ -0,0 +1,161 b''
1 """Tests for the decorators we've created for IPython.
2 """
3
4 # Module imports
5 # Std lib
6 import inspect
7 import sys
8
9 # Third party
10 import nose.tools as nt
11
12 # Our own
13 from IPython.testing import decorators as dec
14
15
16 #-----------------------------------------------------------------------------
17 # Utilities
18
19 # Note: copied from OInspect, kept here so the testing stuff doesn't create
20 # circular dependencies and is easier to reuse.
21 def getargspec(obj):
22 """Get the names and default values of a function's arguments.
23
24 A tuple of four things is returned: (args, varargs, varkw, defaults).
25 'args' is a list of the argument names (it may contain nested lists).
26 'varargs' and 'varkw' are the names of the * and ** arguments or None.
27 'defaults' is an n-tuple of the default values of the last n arguments.
28
29 Modified version of inspect.getargspec from the Python Standard
30 Library."""
31
32 if inspect.isfunction(obj):
33 func_obj = obj
34 elif inspect.ismethod(obj):
35 func_obj = obj.im_func
36 else:
37 raise TypeError, 'arg is not a Python function'
38 args, varargs, varkw = inspect.getargs(func_obj.func_code)
39 return args, varargs, varkw, func_obj.func_defaults
40
41 #-----------------------------------------------------------------------------
42 # Testing functions
43
44 @dec.skip
45 def test_deliberately_broken():
46 """A deliberately broken test - we want to skip this one."""
47 1/0
48
49 @dec.skip('foo')
50 def test_deliberately_broken2():
51 """Another deliberately broken test - we want to skip this one."""
52 1/0
53
54
55 # Verify that we can correctly skip the doctest for a function at will, but
56 # that the docstring itself is NOT destroyed by the decorator.
57 @dec.skip_doctest
58 def doctest_bad(x,y=1,**k):
59 """A function whose doctest we need to skip.
60
61 >>> 1+1
62 3
63 """
64 print 'x:',x
65 print 'y:',y
66 print 'k:',k
67
68
69 def call_doctest_bad():
70 """Check that we can still call the decorated functions.
71
72 >>> doctest_bad(3,y=4)
73 x: 3
74 y: 4
75 k: {}
76 """
77 pass
78
79
80 def test_skip_dt_decorator():
81 """Doctest-skipping decorator should preserve the docstring.
82 """
83 # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring!
84 check = """A function whose doctest we need to skip.
85
86 >>> 1+1
87 3
88 """
89 # Fetch the docstring from doctest_bad after decoration.
90 val = doctest_bad.__doc__
91
92 assert check==val,"doctest_bad docstrings don't match"
93
94 # Doctest skipping should work for class methods too
95 class foo(object):
96 """Foo
97
98 Example:
99
100 >>> 1+1
101 2
102 """
103
104 @dec.skip_doctest
105 def __init__(self,x):
106 """Make a foo.
107
108 Example:
109
110 >>> f = foo(3)
111 junk
112 """
113 print 'Making a foo.'
114 self.x = x
115
116 @dec.skip_doctest
117 def bar(self,y):
118 """Example:
119
120 >>> f = foo(3)
121 >>> f.bar(0)
122 boom!
123 >>> 1/0
124 bam!
125 """
126 return 1/y
127
128 def baz(self,y):
129 """Example:
130
131 >>> f = foo(3)
132 Making a foo.
133 >>> f.baz(3)
134 True
135 """
136 return self.x==y
137
138
139
140 def test_skip_dt_decorator2():
141 """Doctest-skipping decorator should preserve function signature.
142 """
143 # Hardcoded correct answer
144 dtargs = (['x', 'y'], None, 'k', (1,))
145 # Introspect out the value
146 dtargsr = getargspec(doctest_bad)
147 assert dtargsr==dtargs, \
148 "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,)
149
150
151 @dec.skip_linux
152 def test_linux():
153 nt.assert_not_equals(sys.platform,'linux2',"This test can't run under linux")
154
155 @dec.skip_win32
156 def test_win32():
157 nt.assert_not_equals(sys.platform,'win32',"This test can't run under windows")
158
159 @dec.skip_osx
160 def test_osx():
161 nt.assert_not_equals(sys.platform,'darwin',"This test can't run under osx")
@@ -1,68 +1,70 b''
1 1 # encoding: utf-8
2 2 """
3 3 Test the output capture at the OS level, using file descriptors.
4 4 """
5 5
6 6 __docformat__ = "restructuredtext en"
7 7
8 8 #-------------------------------------------------------------------------------
9 9 # Copyright (C) 2008 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is
12 12 # in the file COPYING, distributed as part of this software.
13 13 #-------------------------------------------------------------------------------
14 14
15 15
16 # Stdlib imports
16 17 import os
17 18 from cStringIO import StringIO
18 19
19 # FIXME:
20 import nose
21 import sys
22 if sys.platform == 'win32':
23 raise nose.SkipTest("These tests are not reliable under windows")
20 # Our own imports
21 from IPython.testing import decorators as dec
24 22
23 #-----------------------------------------------------------------------------
24 # Test functions
25
26 @dec.skip_win32
25 27 def test_redirector():
26 28 """ Checks that the redirector can be used to do synchronous capture.
27 29 """
28 30 from IPython.kernel.core.fd_redirector import FDRedirector
29 31 r = FDRedirector()
30 32 out = StringIO()
31 33 try:
32 34 r.start()
33 35 for i in range(10):
34 36 os.system('echo %ic' % i)
35 37 print >>out, r.getvalue(),
36 38 print >>out, i
37 39 except:
38 40 r.stop()
39 41 raise
40 42 r.stop()
41 43 result1 = out.getvalue()
42 44 result2 = "".join("%ic\n%i\n" %(i, i) for i in range(10))
43 45 assert result1 == result2
44 46
47
48 @dec.skip_win32
45 49 def test_redirector_output_trap():
46 50 """ This test check not only that the redirector_output_trap does
47 51 trap the output, but also that it does it in a gready way, that
48 52 is by calling the callback ASAP.
49 53 """
50 54 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
51 55 out = StringIO()
52 56 trap = RedirectorOutputTrap(out.write, out.write)
53 57 try:
54 58 trap.set()
55 59 for i in range(10):
56 60 os.system('echo %ic' % i)
57 61 print "%ip" % i
58 62 print >>out, i
59 63 except:
60 64 trap.unset()
61 65 raise
62 66 trap.unset()
63 67 result1 = out.getvalue()
64 68 result2 = "".join("%ic\n%ip\n%i\n" %(i, i, i) for i in range(10))
65 69 assert result1 == result2
66
67 70
68
@@ -1,147 +1,160 b''
1 1 """Decorators for labeling test objects.
2 2
3 3 Decorators that merely return a modified version of the original
4 4 function object are straightforward. Decorators that return a new
5 5 function object need to use
6 6 nose.tools.make_decorator(original_function)(decorator) in returning
7 7 the decorator, in order to preserve metadata such as function name,
8 8 setup and teardown functions and so on - see nose.tools for more
9 9 information.
10 10
11 This module provides a set of useful decorators meant to be ready to use in
12 your own tests. See the bottom of the file for the ready-made ones, and if you
13 find yourself writing a new one that may be of generic use, add it here.
14
11 15 NOTE: This file contains IPython-specific decorators and imports the
12 16 numpy.testing.decorators file, which we've copied verbatim. Any of our own
13 17 code will be added at the bottom if we end up extending this.
14 18 """
15 19
16 20 # Stdlib imports
17 21 import inspect
22 import sys
18 23
19 24 # Third-party imports
20 25
21 26 # This is Michele Simionato's decorator module, also kept verbatim.
22 27 from decorator_msim import decorator, update_wrapper
23 28
24 29 # Grab the numpy-specific decorators which we keep in a file that we
25 30 # occasionally update from upstream: decorators_numpy.py is an IDENTICAL copy
26 31 # of numpy.testing.decorators.
27 32 from decorators_numpy import *
28 33
29 34 ##############################################################################
30 35 # Local code begins
31 36
32 37 # Utility functions
33 38
34 39 def apply_wrapper(wrapper,func):
35 40 """Apply a wrapper to a function for decoration.
36 41
37 42 This mixes Michele Simionato's decorator tool with nose's make_decorator,
38 43 to apply a wrapper in a decorator so that all nose attributes, as well as
39 44 function signature and other properties, survive the decoration cleanly.
40 45 This will ensure that wrapped functions can still be well introspected via
41 46 IPython, for example.
42 47 """
43 48 import nose.tools
44 49
45 50 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
46 51
47 52
48 53 def make_label_dec(label,ds=None):
49 54 """Factory function to create a decorator that applies one or more labels.
50 55
51 56 :Parameters:
52 57 label : string or sequence
53 58 One or more labels that will be applied by the decorator to the functions
54 59 it decorates. Labels are attributes of the decorated function with their
55 60 value set to True.
56 61
57 62 :Keywords:
58 63 ds : string
59 64 An optional docstring for the resulting decorator. If not given, a
60 65 default docstring is auto-generated.
61 66
62 67 :Returns:
63 68 A decorator.
64 69
65 70 :Examples:
66 71
67 72 A simple labeling decorator:
68 73 >>> slow = make_label_dec('slow')
69 74 >>> print slow.__doc__
70 75 Labels a test as 'slow'.
71 76
72 77 And one that uses multiple labels and a custom docstring:
73 78 >>> rare = make_label_dec(['slow','hard'],
74 79 ... "Mix labels 'slow' and 'hard' for rare tests.")
75 80 >>> print rare.__doc__
76 81 Mix labels 'slow' and 'hard' for rare tests.
77 82
78 83 Now, let's test using this one:
79 84 >>> @rare
80 85 ... def f(): pass
81 86 ...
82 87 >>>
83 88 >>> f.slow
84 89 True
85 90 >>> f.hard
86 91 True
87 92 """
88 93
89 94 if isinstance(label,basestring):
90 95 labels = [label]
91 96 else:
92 97 labels = label
93 98
94 99 # Validate that the given label(s) are OK for use in setattr() by doing a
95 100 # dry run on a dummy function.
96 101 tmp = lambda : None
97 102 for label in labels:
98 103 setattr(tmp,label,True)
99 104
100 105 # This is the actual decorator we'll return
101 106 def decor(f):
102 107 for label in labels:
103 108 setattr(f,label,True)
104 109 return f
105 110
106 111 # Apply the user's docstring, or autogenerate a basic one
107 112 if ds is None:
108 113 ds = "Labels a test as %r." % label
109 114 decor.__doc__ = ds
110 115
111 116 return decor
112 117
113 118 #-----------------------------------------------------------------------------
114 119 # Decorators for public use
115 120
116 121 skip_doctest = make_label_dec('skip_doctest',
117 122 """Decorator - mark a function or method for skipping its doctest.
118 123
119 124 This decorator allows you to mark a function whose docstring you wish to
120 125 omit from testing, while preserving the docstring for introspection, help,
121 126 etc.""")
122 127
123 128 def skip(msg=''):
124 129 """Decorator - mark a test function for skipping from test suite.
125 130
131 This function *is* already a decorator, it is not a factory like
132 make_label_dec or some of those in decorators_numpy.
133
126 134 :Parameters:
127 135
128 136 func : function
129 137 Test function to be skipped
130 138
131 139 msg : string
132 140 Optional message to be added.
133 141 """
134 142
135 143 import nose
136 144
137 145 def inner(func):
138 146
139 147 def wrapper(*a,**k):
140 148 if msg: out = '\n'+msg
141 149 else: out = ''
142 150 raise nose.SkipTest("Skipping test for function: %s%s" %
143 151 (func.__name__,out))
144 152
145 153 return apply_wrapper(wrapper,func)
146 154
147 155 return inner
156
157 # Decorators to skip certain tests on specific platforms.
158 skip_win32 = skipif(sys.platform=='win32',"This test does not run under Windows")
159 skip_linux = skipif(sys.platform=='linux2',"This test does not run under Linux")
160 skip_osx = skipif(sys.platform=='darwin',"This test does not run under OSX")
@@ -1,185 +1,51 b''
1 """Some simple tests for the plugin while running scripts.
2 """
1 3 # Module imports
2 4 # Std lib
3 5 import inspect
4 6
5 # Third party
6
7 7 # Our own
8 8 from IPython.testing import decorators as dec
9 9
10 10 #-----------------------------------------------------------------------------
11 # Utilities
12
13 # Note: copied from OInspect, kept here so the testing stuff doesn't create
14 # circular dependencies and is easier to reuse.
15 def getargspec(obj):
16 """Get the names and default values of a function's arguments.
17
18 A tuple of four things is returned: (args, varargs, varkw, defaults).
19 'args' is a list of the argument names (it may contain nested lists).
20 'varargs' and 'varkw' are the names of the * and ** arguments or None.
21 'defaults' is an n-tuple of the default values of the last n arguments.
22
23 Modified version of inspect.getargspec from the Python Standard
24 Library."""
25
26 if inspect.isfunction(obj):
27 func_obj = obj
28 elif inspect.ismethod(obj):
29 func_obj = obj.im_func
30 else:
31 raise TypeError, 'arg is not a Python function'
32 args, varargs, varkw = inspect.getargs(func_obj.func_code)
33 return args, varargs, varkw, func_obj.func_defaults
34
35 #-----------------------------------------------------------------------------
36 11 # Testing functions
37 12
38 13 def test_trivial():
39 14 """A trivial passing test."""
40 15 pass
41 16
42
43 @dec.skip
44 def test_deliberately_broken():
45 """A deliberately broken test - we want to skip this one."""
46 1/0
47
48 @dec.skip('foo')
49 def test_deliberately_broken2():
50 """Another deliberately broken test - we want to skip this one."""
51 1/0
52
53
54 # Verify that we can correctly skip the doctest for a function at will, but
55 # that the docstring itself is NOT destroyed by the decorator.
56 @dec.skip_doctest
57 def doctest_bad(x,y=1,**k):
58 """A function whose doctest we need to skip.
59
60 >>> 1+1
61 3
62 """
63 print 'x:',x
64 print 'y:',y
65 print 'k:',k
66
67
68 def call_doctest_bad():
69 """Check that we can still call the decorated functions.
70
71 >>> doctest_bad(3,y=4)
72 x: 3
73 y: 4
74 k: {}
75 """
76 pass
77
78
79 # Doctest skipping should work for class methods too
80 class foo(object):
81 """Foo
82
83 Example:
84
85 >>> 1+1
86 2
87 """
88
89 @dec.skip_doctest
90 def __init__(self,x):
91 """Make a foo.
92
93 Example:
94
95 >>> f = foo(3)
96 junk
97 """
98 print 'Making a foo.'
99 self.x = x
100
101 @dec.skip_doctest
102 def bar(self,y):
103 """Example:
104
105 >>> f = foo(3)
106 >>> f.bar(0)
107 boom!
108 >>> 1/0
109 bam!
110 """
111 return 1/y
112
113 def baz(self,y):
114 """Example:
115
116 >>> f = foo(3)
117 Making a foo.
118 >>> f.baz(3)
119 True
120 """
121 return self.x==y
122
123
124 def test_skip_dt_decorator():
125 """Doctest-skipping decorator should preserve the docstring.
126 """
127 # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring!
128 check = """A function whose doctest we need to skip.
129
130 >>> 1+1
131 3
132 """
133 # Fetch the docstring from doctest_bad after decoration.
134 val = doctest_bad.__doc__
135
136 assert check==val,"doctest_bad docstrings don't match"
137
138
139 def test_skip_dt_decorator2():
140 """Doctest-skipping decorator should preserve function signature.
141 """
142 # Hardcoded correct answer
143 dtargs = (['x', 'y'], None, 'k', (1,))
144 # Introspect out the value
145 dtargsr = getargspec(doctest_bad)
146 assert dtargsr==dtargs, \
147 "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,)
148
149
150 17 def doctest_run():
151 18 """Test running a trivial script.
152 19
153 20 In [13]: run simplevars.py
154 21 x is: 1
155 22 """
156 23
157 #@dec.skip_doctest
158 24 def doctest_runvars():
159 25 """Test that variables defined in scripts get loaded correcly via %run.
160 26
161 27 In [13]: run simplevars.py
162 28 x is: 1
163 29
164 30 In [14]: x
165 31 Out[14]: 1
166 32 """
167 33
168 34 def doctest_ivars():
169 35 """Test that variables defined interactively are picked up.
170 36 In [5]: zz=1
171 37
172 38 In [6]: zz
173 39 Out[6]: 1
174 40 """
175 41
176 42 @dec.skip_doctest
177 43 def doctest_refs():
178 44 """DocTest reference holding issues when running scripts.
179 45
180 46 In [32]: run show_refs.py
181 47 c referrers: [<type 'dict'>]
182 48
183 49 In [33]: map(type,gc.get_referrers(c))
184 50 Out[33]: [<type 'dict'>]
185 51 """
General Comments 0
You need to be logged in to leave comments. Login now