##// END OF EJS Templates
skip tests when display variable is not set
Paul Ivanov -
Show More
@@ -1,80 +1,82 b''
1 # Standard library imports
1 # Standard library imports
2 import unittest
2 import unittest
3
3
4 # System library imports
4 # System library imports
5 from IPython.external.qt import QtCore, QtGui
5 from IPython.external.qt import QtCore, QtGui
6
6
7 # Local imports
7 # Local imports
8 from IPython.qt.console.console_widget import ConsoleWidget
8 from IPython.qt.console.console_widget import ConsoleWidget
9 import IPython.testing.decorators as dec
9
10
11 setup = dec.skip_file_no_x11(__name__)
10
12
11 class TestConsoleWidget(unittest.TestCase):
13 class TestConsoleWidget(unittest.TestCase):
12
14
13 @classmethod
15 @classmethod
14 def setUpClass(cls):
16 def setUpClass(cls):
15 """ Create the application for the test case.
17 """ Create the application for the test case.
16 """
18 """
17 cls._app = QtGui.QApplication.instance()
19 cls._app = QtGui.QApplication.instance()
18 if cls._app is None:
20 if cls._app is None:
19 cls._app = QtGui.QApplication([])
21 cls._app = QtGui.QApplication([])
20 cls._app.setQuitOnLastWindowClosed(False)
22 cls._app.setQuitOnLastWindowClosed(False)
21
23
22 @classmethod
24 @classmethod
23 def tearDownClass(cls):
25 def tearDownClass(cls):
24 """ Exit the application.
26 """ Exit the application.
25 """
27 """
26 QtGui.QApplication.quit()
28 QtGui.QApplication.quit()
27
29
28 def test_special_characters(self):
30 def test_special_characters(self):
29 """ Are special characters displayed correctly?
31 """ Are special characters displayed correctly?
30 """
32 """
31 w = ConsoleWidget()
33 w = ConsoleWidget()
32 cursor = w._get_prompt_cursor()
34 cursor = w._get_prompt_cursor()
33
35
34 test_inputs = ['xyz\b\b=\n', 'foo\b\nbar\n', 'foo\b\nbar\r\n', 'abc\rxyz\b\b=']
36 test_inputs = ['xyz\b\b=\n', 'foo\b\nbar\n', 'foo\b\nbar\r\n', 'abc\rxyz\b\b=']
35 expected_outputs = [u'x=z\u2029', u'foo\u2029bar\u2029', u'foo\u2029bar\u2029', 'x=z']
37 expected_outputs = [u'x=z\u2029', u'foo\u2029bar\u2029', u'foo\u2029bar\u2029', 'x=z']
36 for i, text in enumerate(test_inputs):
38 for i, text in enumerate(test_inputs):
37 w._insert_plain_text(cursor, text)
39 w._insert_plain_text(cursor, text)
38 cursor.select(cursor.Document)
40 cursor.select(cursor.Document)
39 selection = cursor.selectedText()
41 selection = cursor.selectedText()
40 self.assertEqual(expected_outputs[i], selection)
42 self.assertEqual(expected_outputs[i], selection)
41 # clear all the text
43 # clear all the text
42 cursor.insertText('')
44 cursor.insertText('')
43
45
44 def test_link_handling(self):
46 def test_link_handling(self):
45 noKeys = QtCore.Qt
47 noKeys = QtCore.Qt
46 noButton = QtCore.Qt.MouseButton(0)
48 noButton = QtCore.Qt.MouseButton(0)
47 noButtons = QtCore.Qt.MouseButtons(0)
49 noButtons = QtCore.Qt.MouseButtons(0)
48 noModifiers = QtCore.Qt.KeyboardModifiers(0)
50 noModifiers = QtCore.Qt.KeyboardModifiers(0)
49 MouseMove = QtCore.QEvent.MouseMove
51 MouseMove = QtCore.QEvent.MouseMove
50 QMouseEvent = QtGui.QMouseEvent
52 QMouseEvent = QtGui.QMouseEvent
51
53
52 w = ConsoleWidget()
54 w = ConsoleWidget()
53 cursor = w._get_prompt_cursor()
55 cursor = w._get_prompt_cursor()
54 w._insert_html(cursor, '<a href="http://python.org">written in</a>')
56 w._insert_html(cursor, '<a href="http://python.org">written in</a>')
55 obj = w._control
57 obj = w._control
56 tip = QtGui.QToolTip
58 tip = QtGui.QToolTip
57 self.assertEqual(tip.text(), u'')
59 self.assertEqual(tip.text(), u'')
58
60
59 # should be somewhere else
61 # should be somewhere else
60 elsewhereEvent = QMouseEvent(MouseMove, QtCore.QPoint(50,50),
62 elsewhereEvent = QMouseEvent(MouseMove, QtCore.QPoint(50,50),
61 noButton, noButtons, noModifiers)
63 noButton, noButtons, noModifiers)
62 w.eventFilter(obj, elsewhereEvent)
64 w.eventFilter(obj, elsewhereEvent)
63 self.assertEqual(tip.isVisible(), False)
65 self.assertEqual(tip.isVisible(), False)
64 self.assertEqual(tip.text(), u'')
66 self.assertEqual(tip.text(), u'')
65
67
66 #self.assertEqual(tip.text(), u'')
68 #self.assertEqual(tip.text(), u'')
67 # should be over text
69 # should be over text
68 overTextEvent = QMouseEvent(MouseMove, QtCore.QPoint(1,5),
70 overTextEvent = QMouseEvent(MouseMove, QtCore.QPoint(1,5),
69 noButton, noButtons, noModifiers)
71 noButton, noButtons, noModifiers)
70 w.eventFilter(obj, overTextEvent)
72 w.eventFilter(obj, overTextEvent)
71 self.assertEqual(tip.isVisible(), True)
73 self.assertEqual(tip.isVisible(), True)
72 self.assertEqual(tip.text(), "http://python.org")
74 self.assertEqual(tip.text(), "http://python.org")
73
75
74 # should still be over text
76 # should still be over text
75 stillOverTextEvent = QMouseEvent(MouseMove, QtCore.QPoint(1,5),
77 stillOverTextEvent = QMouseEvent(MouseMove, QtCore.QPoint(1,5),
76 noButton, noButtons, noModifiers)
78 noButton, noButtons, noModifiers)
77 w.eventFilter(obj, stillOverTextEvent)
79 w.eventFilter(obj, stillOverTextEvent)
78 self.assertEqual(tip.isVisible(), True)
80 self.assertEqual(tip.isVisible(), True)
79 self.assertEqual(tip.text(), "http://python.org")
81 self.assertEqual(tip.text(), "http://python.org")
80
82
@@ -1,85 +1,87 b''
1 # Standard library imports
1 # Standard library imports
2 import unittest
2 import unittest
3
3
4 # System library imports
4 # System library imports
5 from IPython.external.qt import QtGui
5 from IPython.external.qt import QtGui
6
6
7 # Local imports
7 # Local imports
8 from IPython.qt.console.kill_ring import KillRing, QtKillRing
8 from IPython.qt.console.kill_ring import KillRing, QtKillRing
9 import IPython.testing.decorators as dec
9
10
11 setup = dec.skip_file_no_x11(__name__)
10
12
11 class TestKillRing(unittest.TestCase):
13 class TestKillRing(unittest.TestCase):
12
14
13 @classmethod
15 @classmethod
14 def setUpClass(cls):
16 def setUpClass(cls):
15 """ Create the application for the test case.
17 """ Create the application for the test case.
16 """
18 """
17 cls._app = QtGui.QApplication.instance()
19 cls._app = QtGui.QApplication.instance()
18 if cls._app is None:
20 if cls._app is None:
19 cls._app = QtGui.QApplication([])
21 cls._app = QtGui.QApplication([])
20 cls._app.setQuitOnLastWindowClosed(False)
22 cls._app.setQuitOnLastWindowClosed(False)
21
23
22 @classmethod
24 @classmethod
23 def tearDownClass(cls):
25 def tearDownClass(cls):
24 """ Exit the application.
26 """ Exit the application.
25 """
27 """
26 QtGui.QApplication.quit()
28 QtGui.QApplication.quit()
27
29
28 def test_generic(self):
30 def test_generic(self):
29 """ Does the generic kill ring work?
31 """ Does the generic kill ring work?
30 """
32 """
31 ring = KillRing()
33 ring = KillRing()
32 self.assertTrue(ring.yank() is None)
34 self.assertTrue(ring.yank() is None)
33 self.assertTrue(ring.rotate() is None)
35 self.assertTrue(ring.rotate() is None)
34
36
35 ring.kill('foo')
37 ring.kill('foo')
36 self.assertEqual(ring.yank(), 'foo')
38 self.assertEqual(ring.yank(), 'foo')
37 self.assertTrue(ring.rotate() is None)
39 self.assertTrue(ring.rotate() is None)
38 self.assertEqual(ring.yank(), 'foo')
40 self.assertEqual(ring.yank(), 'foo')
39
41
40 ring.kill('bar')
42 ring.kill('bar')
41 self.assertEqual(ring.yank(), 'bar')
43 self.assertEqual(ring.yank(), 'bar')
42 self.assertEqual(ring.rotate(), 'foo')
44 self.assertEqual(ring.rotate(), 'foo')
43
45
44 ring.clear()
46 ring.clear()
45 self.assertTrue(ring.yank() is None)
47 self.assertTrue(ring.yank() is None)
46 self.assertTrue(ring.rotate() is None)
48 self.assertTrue(ring.rotate() is None)
47
49
48 def test_qt_basic(self):
50 def test_qt_basic(self):
49 """ Does the Qt kill ring work?
51 """ Does the Qt kill ring work?
50 """
52 """
51 text_edit = QtGui.QPlainTextEdit()
53 text_edit = QtGui.QPlainTextEdit()
52 ring = QtKillRing(text_edit)
54 ring = QtKillRing(text_edit)
53
55
54 ring.kill('foo')
56 ring.kill('foo')
55 ring.kill('bar')
57 ring.kill('bar')
56 ring.yank()
58 ring.yank()
57 ring.rotate()
59 ring.rotate()
58 ring.yank()
60 ring.yank()
59 self.assertEqual(text_edit.toPlainText(), 'foobar')
61 self.assertEqual(text_edit.toPlainText(), 'foobar')
60
62
61 text_edit.clear()
63 text_edit.clear()
62 ring.kill('baz')
64 ring.kill('baz')
63 ring.yank()
65 ring.yank()
64 ring.rotate()
66 ring.rotate()
65 ring.rotate()
67 ring.rotate()
66 ring.rotate()
68 ring.rotate()
67 self.assertEqual(text_edit.toPlainText(), 'foo')
69 self.assertEqual(text_edit.toPlainText(), 'foo')
68
70
69 def test_qt_cursor(self):
71 def test_qt_cursor(self):
70 """ Does the Qt kill ring maintain state with cursor movement?
72 """ Does the Qt kill ring maintain state with cursor movement?
71 """
73 """
72 text_edit = QtGui.QPlainTextEdit()
74 text_edit = QtGui.QPlainTextEdit()
73 ring = QtKillRing(text_edit)
75 ring = QtKillRing(text_edit)
74
76
75 ring.kill('foo')
77 ring.kill('foo')
76 ring.kill('bar')
78 ring.kill('bar')
77 ring.yank()
79 ring.yank()
78 text_edit.moveCursor(QtGui.QTextCursor.Left)
80 text_edit.moveCursor(QtGui.QTextCursor.Left)
79 ring.rotate()
81 ring.rotate()
80 self.assertEqual(text_edit.toPlainText(), 'bar')
82 self.assertEqual(text_edit.toPlainText(), 'bar')
81
83
82
84
83 if __name__ == '__main__':
85 if __name__ == '__main__':
84 import nose
86 import nose
85 nose.main()
87 nose.main()
@@ -1,366 +1,391 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Decorators for labeling test objects.
2 """Decorators for labeling test objects.
3
3
4 Decorators that merely return a modified version of the original function
4 Decorators that merely return a modified version of the original function
5 object are straightforward. Decorators that return a new function object need
5 object are straightforward. Decorators that return a new function object need
6 to use nose.tools.make_decorator(original_function)(decorator) in returning the
6 to use nose.tools.make_decorator(original_function)(decorator) in returning the
7 decorator, in order to preserve metadata such as function name, setup and
7 decorator, in order to preserve metadata such as function name, setup and
8 teardown functions and so on - see nose.tools for more information.
8 teardown functions and so on - see nose.tools for more information.
9
9
10 This module provides a set of useful decorators meant to be ready to use in
10 This module provides a set of useful decorators meant to be ready to use in
11 your own tests. See the bottom of the file for the ready-made ones, and if you
11 your own tests. See the bottom of the file for the ready-made ones, and if you
12 find yourself writing a new one that may be of generic use, add it here.
12 find yourself writing a new one that may be of generic use, add it here.
13
13
14 Included decorators:
14 Included decorators:
15
15
16
16
17 Lightweight testing that remains unittest-compatible.
17 Lightweight testing that remains unittest-compatible.
18
18
19 - @parametric, for parametric test support that is vastly easier to use than
19 - @parametric, for parametric test support that is vastly easier to use than
20 nose's for debugging. With ours, if a test fails, the stack under inspection
20 nose's for debugging. With ours, if a test fails, the stack under inspection
21 is that of the test and not that of the test framework.
21 is that of the test and not that of the test framework.
22
22
23 - An @as_unittest decorator can be used to tag any normal parameter-less
23 - An @as_unittest decorator can be used to tag any normal parameter-less
24 function as a unittest TestCase. Then, both nose and normal unittest will
24 function as a unittest TestCase. Then, both nose and normal unittest will
25 recognize it as such. This will make it easier to migrate away from Nose if
25 recognize it as such. This will make it easier to migrate away from Nose if
26 we ever need/want to while maintaining very lightweight tests.
26 we ever need/want to while maintaining very lightweight tests.
27
27
28 NOTE: This file contains IPython-specific decorators. Using the machinery in
28 NOTE: This file contains IPython-specific decorators. Using the machinery in
29 IPython.external.decorators, we import either numpy.testing.decorators if numpy is
29 IPython.external.decorators, we import either numpy.testing.decorators if numpy is
30 available, OR use equivalent code in IPython.external._decorators, which
30 available, OR use equivalent code in IPython.external._decorators, which
31 we've copied verbatim from numpy.
31 we've copied verbatim from numpy.
32
32
33 Authors
33 Authors
34 -------
34 -------
35
35
36 - Fernando Perez <Fernando.Perez@berkeley.edu>
36 - Fernando Perez <Fernando.Perez@berkeley.edu>
37 """
37 """
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # Copyright (C) 2009-2011 The IPython Development Team
40 # Copyright (C) 2009-2011 The IPython Development Team
41 #
41 #
42 # Distributed under the terms of the BSD License. The full license is in
42 # Distributed under the terms of the BSD License. The full license is in
43 # the file COPYING, distributed as part of this software.
43 # the file COPYING, distributed as part of this software.
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Imports
47 # Imports
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49
49
50 # Stdlib imports
50 # Stdlib imports
51 import sys
51 import sys
52 import os
52 import tempfile
53 import tempfile
53 import unittest
54 import unittest
54
55
55 # Third-party imports
56 # Third-party imports
56
57
57 # This is Michele Simionato's decorator module, kept verbatim.
58 # This is Michele Simionato's decorator module, kept verbatim.
58 from IPython.external.decorator import decorator
59 from IPython.external.decorator import decorator
59
60
60 # We already have python3-compliant code for parametric tests
61 # We already have python3-compliant code for parametric tests
61 if sys.version[0]=='2':
62 if sys.version[0]=='2':
62 from _paramtestpy2 import parametric
63 from _paramtestpy2 import parametric
63 else:
64 else:
64 from _paramtestpy3 import parametric
65 from _paramtestpy3 import parametric
65
66
66 # Expose the unittest-driven decorators
67 # Expose the unittest-driven decorators
67 from ipunittest import ipdoctest, ipdocstring
68 from ipunittest import ipdoctest, ipdocstring
68
69
69 # Grab the numpy-specific decorators which we keep in a file that we
70 # Grab the numpy-specific decorators which we keep in a file that we
70 # occasionally update from upstream: decorators.py is a copy of
71 # occasionally update from upstream: decorators.py is a copy of
71 # numpy.testing.decorators, we expose all of it here.
72 # numpy.testing.decorators, we expose all of it here.
72 from IPython.external.decorators import *
73 from IPython.external.decorators import *
73
74
74 # For onlyif_cmd_exists decorator
75 # For onlyif_cmd_exists decorator
75 from IPython.utils.process import is_cmd_found
76 from IPython.utils.process import is_cmd_found
76
77
77 #-----------------------------------------------------------------------------
78 #-----------------------------------------------------------------------------
78 # Classes and functions
79 # Classes and functions
79 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
80
81
81 # Simple example of the basic idea
82 # Simple example of the basic idea
82 def as_unittest(func):
83 def as_unittest(func):
83 """Decorator to make a simple function into a normal test via unittest."""
84 """Decorator to make a simple function into a normal test via unittest."""
84 class Tester(unittest.TestCase):
85 class Tester(unittest.TestCase):
85 def test(self):
86 def test(self):
86 func()
87 func()
87
88
88 Tester.__name__ = func.__name__
89 Tester.__name__ = func.__name__
89
90
90 return Tester
91 return Tester
91
92
92 # Utility functions
93 # Utility functions
93
94
94 def apply_wrapper(wrapper,func):
95 def apply_wrapper(wrapper,func):
95 """Apply a wrapper to a function for decoration.
96 """Apply a wrapper to a function for decoration.
96
97
97 This mixes Michele Simionato's decorator tool with nose's make_decorator,
98 This mixes Michele Simionato's decorator tool with nose's make_decorator,
98 to apply a wrapper in a decorator so that all nose attributes, as well as
99 to apply a wrapper in a decorator so that all nose attributes, as well as
99 function signature and other properties, survive the decoration cleanly.
100 function signature and other properties, survive the decoration cleanly.
100 This will ensure that wrapped functions can still be well introspected via
101 This will ensure that wrapped functions can still be well introspected via
101 IPython, for example.
102 IPython, for example.
102 """
103 """
103 import nose.tools
104 import nose.tools
104
105
105 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
106 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
106
107
107
108
108 def make_label_dec(label,ds=None):
109 def make_label_dec(label,ds=None):
109 """Factory function to create a decorator that applies one or more labels.
110 """Factory function to create a decorator that applies one or more labels.
110
111
111 Parameters
112 Parameters
112 ----------
113 ----------
113 label : string or sequence
114 label : string or sequence
114 One or more labels that will be applied by the decorator to the functions
115 One or more labels that will be applied by the decorator to the functions
115 it decorates. Labels are attributes of the decorated function with their
116 it decorates. Labels are attributes of the decorated function with their
116 value set to True.
117 value set to True.
117
118
118 ds : string
119 ds : string
119 An optional docstring for the resulting decorator. If not given, a
120 An optional docstring for the resulting decorator. If not given, a
120 default docstring is auto-generated.
121 default docstring is auto-generated.
121
122
122 Returns
123 Returns
123 -------
124 -------
124 A decorator.
125 A decorator.
125
126
126 Examples
127 Examples
127 --------
128 --------
128
129
129 A simple labeling decorator:
130 A simple labeling decorator:
130
131
131 >>> slow = make_label_dec('slow')
132 >>> slow = make_label_dec('slow')
132 >>> slow.__doc__
133 >>> slow.__doc__
133 "Labels a test as 'slow'."
134 "Labels a test as 'slow'."
134
135
135 And one that uses multiple labels and a custom docstring:
136 And one that uses multiple labels and a custom docstring:
136
137
137 >>> rare = make_label_dec(['slow','hard'],
138 >>> rare = make_label_dec(['slow','hard'],
138 ... "Mix labels 'slow' and 'hard' for rare tests.")
139 ... "Mix labels 'slow' and 'hard' for rare tests.")
139 >>> rare.__doc__
140 >>> rare.__doc__
140 "Mix labels 'slow' and 'hard' for rare tests."
141 "Mix labels 'slow' and 'hard' for rare tests."
141
142
142 Now, let's test using this one:
143 Now, let's test using this one:
143 >>> @rare
144 >>> @rare
144 ... def f(): pass
145 ... def f(): pass
145 ...
146 ...
146 >>>
147 >>>
147 >>> f.slow
148 >>> f.slow
148 True
149 True
149 >>> f.hard
150 >>> f.hard
150 True
151 True
151 """
152 """
152
153
153 if isinstance(label,basestring):
154 if isinstance(label,basestring):
154 labels = [label]
155 labels = [label]
155 else:
156 else:
156 labels = label
157 labels = label
157
158
158 # Validate that the given label(s) are OK for use in setattr() by doing a
159 # Validate that the given label(s) are OK for use in setattr() by doing a
159 # dry run on a dummy function.
160 # dry run on a dummy function.
160 tmp = lambda : None
161 tmp = lambda : None
161 for label in labels:
162 for label in labels:
162 setattr(tmp,label,True)
163 setattr(tmp,label,True)
163
164
164 # This is the actual decorator we'll return
165 # This is the actual decorator we'll return
165 def decor(f):
166 def decor(f):
166 for label in labels:
167 for label in labels:
167 setattr(f,label,True)
168 setattr(f,label,True)
168 return f
169 return f
169
170
170 # Apply the user's docstring, or autogenerate a basic one
171 # Apply the user's docstring, or autogenerate a basic one
171 if ds is None:
172 if ds is None:
172 ds = "Labels a test as %r." % label
173 ds = "Labels a test as %r." % label
173 decor.__doc__ = ds
174 decor.__doc__ = ds
174
175
175 return decor
176 return decor
176
177
177
178
178 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
179 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
179 # preserve function metadata better and allows the skip condition to be a
180 # preserve function metadata better and allows the skip condition to be a
180 # callable.
181 # callable.
181 def skipif(skip_condition, msg=None):
182 def skipif(skip_condition, msg=None):
182 ''' Make function raise SkipTest exception if skip_condition is true
183 ''' Make function raise SkipTest exception if skip_condition is true
183
184
184 Parameters
185 Parameters
185 ----------
186 ----------
186 skip_condition : bool or callable.
187 skip_condition : bool or callable.
187 Flag to determine whether to skip test. If the condition is a
188 Flag to determine whether to skip test. If the condition is a
188 callable, it is used at runtime to dynamically make the decision. This
189 callable, it is used at runtime to dynamically make the decision. This
189 is useful for tests that may require costly imports, to delay the cost
190 is useful for tests that may require costly imports, to delay the cost
190 until the test suite is actually executed.
191 until the test suite is actually executed.
191 msg : string
192 msg : string
192 Message to give on raising a SkipTest exception
193 Message to give on raising a SkipTest exception
193
194
194 Returns
195 Returns
195 -------
196 -------
196 decorator : function
197 decorator : function
197 Decorator, which, when applied to a function, causes SkipTest
198 Decorator, which, when applied to a function, causes SkipTest
198 to be raised when the skip_condition was True, and the function
199 to be raised when the skip_condition was True, and the function
199 to be called normally otherwise.
200 to be called normally otherwise.
200
201
201 Notes
202 Notes
202 -----
203 -----
203 You will see from the code that we had to further decorate the
204 You will see from the code that we had to further decorate the
204 decorator with the nose.tools.make_decorator function in order to
205 decorator with the nose.tools.make_decorator function in order to
205 transmit function name, and various other metadata.
206 transmit function name, and various other metadata.
206 '''
207 '''
207
208
208 def skip_decorator(f):
209 def skip_decorator(f):
209 # Local import to avoid a hard nose dependency and only incur the
210 # Local import to avoid a hard nose dependency and only incur the
210 # import time overhead at actual test-time.
211 # import time overhead at actual test-time.
211 import nose
212 import nose
212
213
213 # Allow for both boolean or callable skip conditions.
214 # Allow for both boolean or callable skip conditions.
214 if callable(skip_condition):
215 if callable(skip_condition):
215 skip_val = skip_condition
216 skip_val = skip_condition
216 else:
217 else:
217 skip_val = lambda : skip_condition
218 skip_val = lambda : skip_condition
218
219
219 def get_msg(func,msg=None):
220 def get_msg(func,msg=None):
220 """Skip message with information about function being skipped."""
221 """Skip message with information about function being skipped."""
221 if msg is None: out = 'Test skipped due to test condition.'
222 if msg is None: out = 'Test skipped due to test condition.'
222 else: out = msg
223 else: out = msg
223 return "Skipping test: %s. %s" % (func.__name__,out)
224 return "Skipping test: %s. %s" % (func.__name__,out)
224
225
225 # We need to define *two* skippers because Python doesn't allow both
226 # We need to define *two* skippers because Python doesn't allow both
226 # return with value and yield inside the same function.
227 # return with value and yield inside the same function.
227 def skipper_func(*args, **kwargs):
228 def skipper_func(*args, **kwargs):
228 """Skipper for normal test functions."""
229 """Skipper for normal test functions."""
229 if skip_val():
230 if skip_val():
230 raise nose.SkipTest(get_msg(f,msg))
231 raise nose.SkipTest(get_msg(f,msg))
231 else:
232 else:
232 return f(*args, **kwargs)
233 return f(*args, **kwargs)
233
234
234 def skipper_gen(*args, **kwargs):
235 def skipper_gen(*args, **kwargs):
235 """Skipper for test generators."""
236 """Skipper for test generators."""
236 if skip_val():
237 if skip_val():
237 raise nose.SkipTest(get_msg(f,msg))
238 raise nose.SkipTest(get_msg(f,msg))
238 else:
239 else:
239 for x in f(*args, **kwargs):
240 for x in f(*args, **kwargs):
240 yield x
241 yield x
241
242
242 # Choose the right skipper to use when building the actual generator.
243 # Choose the right skipper to use when building the actual generator.
243 if nose.util.isgenerator(f):
244 if nose.util.isgenerator(f):
244 skipper = skipper_gen
245 skipper = skipper_gen
245 else:
246 else:
246 skipper = skipper_func
247 skipper = skipper_func
247
248
248 return nose.tools.make_decorator(f)(skipper)
249 return nose.tools.make_decorator(f)(skipper)
249
250
250 return skip_decorator
251 return skip_decorator
251
252
252 # A version with the condition set to true, common case just to attach a message
253 # A version with the condition set to true, common case just to attach a message
253 # to a skip decorator
254 # to a skip decorator
254 def skip(msg=None):
255 def skip(msg=None):
255 """Decorator factory - mark a test function for skipping from test suite.
256 """Decorator factory - mark a test function for skipping from test suite.
256
257
257 Parameters
258 Parameters
258 ----------
259 ----------
259 msg : string
260 msg : string
260 Optional message to be added.
261 Optional message to be added.
261
262
262 Returns
263 Returns
263 -------
264 -------
264 decorator : function
265 decorator : function
265 Decorator, which, when applied to a function, causes SkipTest
266 Decorator, which, when applied to a function, causes SkipTest
266 to be raised, with the optional message added.
267 to be raised, with the optional message added.
267 """
268 """
268
269
269 return skipif(True,msg)
270 return skipif(True,msg)
270
271
271
272
272 def onlyif(condition, msg):
273 def onlyif(condition, msg):
273 """The reverse from skipif, see skipif for details."""
274 """The reverse from skipif, see skipif for details."""
274
275
275 if callable(condition):
276 if callable(condition):
276 skip_condition = lambda : not condition()
277 skip_condition = lambda : not condition()
277 else:
278 else:
278 skip_condition = lambda : not condition
279 skip_condition = lambda : not condition
279
280
280 return skipif(skip_condition, msg)
281 return skipif(skip_condition, msg)
281
282
282 #-----------------------------------------------------------------------------
283 #-----------------------------------------------------------------------------
283 # Utility functions for decorators
284 # Utility functions for decorators
284 def module_not_available(module):
285 def module_not_available(module):
285 """Can module be imported? Returns true if module does NOT import.
286 """Can module be imported? Returns true if module does NOT import.
286
287
287 This is used to make a decorator to skip tests that require module to be
288 This is used to make a decorator to skip tests that require module to be
288 available, but delay the 'import numpy' to test execution time.
289 available, but delay the 'import numpy' to test execution time.
289 """
290 """
290 try:
291 try:
291 mod = __import__(module)
292 mod = __import__(module)
292 mod_not_avail = False
293 mod_not_avail = False
293 except ImportError:
294 except ImportError:
294 mod_not_avail = True
295 mod_not_avail = True
295
296
296 return mod_not_avail
297 return mod_not_avail
297
298
299
300 def decorated_dummy(dec, name):
301 """Return a dummy function decorated with dec, with the given name.
302
303 Examples
304 --------
305 import IPython.testing.decorators as dec
306 setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
307 """
308 dummy = lambda: None
309 dummy.__name__ = name
310 return dec(dummy)
311
298 #-----------------------------------------------------------------------------
312 #-----------------------------------------------------------------------------
299 # Decorators for public use
313 # Decorators for public use
300
314
301 # Decorators to skip certain tests on specific platforms.
315 # Decorators to skip certain tests on specific platforms.
302 skip_win32 = skipif(sys.platform == 'win32',
316 skip_win32 = skipif(sys.platform == 'win32',
303 "This test does not run under Windows")
317 "This test does not run under Windows")
304 skip_linux = skipif(sys.platform.startswith('linux'),
318 skip_linux = skipif(sys.platform.startswith('linux'),
305 "This test does not run under Linux")
319 "This test does not run under Linux")
306 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
320 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
307
321
308
322
309 # Decorators to skip tests if not on specific platforms.
323 # Decorators to skip tests if not on specific platforms.
310 skip_if_not_win32 = skipif(sys.platform != 'win32',
324 skip_if_not_win32 = skipif(sys.platform != 'win32',
311 "This test only runs under Windows")
325 "This test only runs under Windows")
312 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
326 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
313 "This test only runs under Linux")
327 "This test only runs under Linux")
314 skip_if_not_osx = skipif(sys.platform != 'darwin',
328 skip_if_not_osx = skipif(sys.platform != 'darwin',
315 "This test only runs under OSX")
329 "This test only runs under OSX")
316
330
331
332 _x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
333 os.environ['DISPLAY']=='')
334 _x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
335
336 skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
337
338 # not a decorator itself, returns a dummy function to be used as setup
339 def skip_file_no_x11(name):
340 return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
341
317 # Other skip decorators
342 # Other skip decorators
318
343
319 # generic skip without module
344 # generic skip without module
320 skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
345 skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
321
346
322 skipif_not_numpy = skip_without('numpy')
347 skipif_not_numpy = skip_without('numpy')
323
348
324 skipif_not_matplotlib = skip_without('matplotlib')
349 skipif_not_matplotlib = skip_without('matplotlib')
325
350
326 skipif_not_sympy = skip_without('sympy')
351 skipif_not_sympy = skip_without('sympy')
327
352
328 skip_known_failure = knownfailureif(True,'This test is known to fail')
353 skip_known_failure = knownfailureif(True,'This test is known to fail')
329
354
330 known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
355 known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
331 'This test is known to fail on Python 3.')
356 'This test is known to fail on Python 3.')
332
357
333 # A null 'decorator', useful to make more readable code that needs to pick
358 # A null 'decorator', useful to make more readable code that needs to pick
334 # between different decorators based on OS or other conditions
359 # between different decorators based on OS or other conditions
335 null_deco = lambda f: f
360 null_deco = lambda f: f
336
361
337 # Some tests only run where we can use unicode paths. Note that we can't just
362 # Some tests only run where we can use unicode paths. Note that we can't just
338 # check os.path.supports_unicode_filenames, which is always False on Linux.
363 # check os.path.supports_unicode_filenames, which is always False on Linux.
339 try:
364 try:
340 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
365 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
341 except UnicodeEncodeError:
366 except UnicodeEncodeError:
342 unicode_paths = False
367 unicode_paths = False
343 else:
368 else:
344 unicode_paths = True
369 unicode_paths = True
345 f.close()
370 f.close()
346
371
347 onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
372 onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
348 "where we can use unicode in filenames."))
373 "where we can use unicode in filenames."))
349
374
350
375
351 def onlyif_cmds_exist(*commands):
376 def onlyif_cmds_exist(*commands):
352 """
377 """
353 Decorator to skip test when at least one of `commands` is not found.
378 Decorator to skip test when at least one of `commands` is not found.
354 """
379 """
355 for cmd in commands:
380 for cmd in commands:
356 try:
381 try:
357 if not is_cmd_found(cmd):
382 if not is_cmd_found(cmd):
358 return skip("This test runs only if command '{0}' "
383 return skip("This test runs only if command '{0}' "
359 "is installed".format(cmd))
384 "is installed".format(cmd))
360 except ImportError as e:
385 except ImportError as e:
361 # is_cmd_found uses pywin32 on windows, which might not be available
386 # is_cmd_found uses pywin32 on windows, which might not be available
362 if sys.platform == 'win32' and 'pywin32' in e.message:
387 if sys.platform == 'win32' and 'pywin32' in e.message:
363 return skip("This test runs only if pywin32 and command '{0}' "
388 return skip("This test runs only if pywin32 and command '{0}' "
364 "is installed".format(cmd))
389 "is installed".format(cmd))
365 raise e
390 raise e
366 return null_deco
391 return null_deco
General Comments 0
You need to be logged in to leave comments. Login now