349eded3ff9da37e35bf8c818dda1051ab707ff9
[ejpi] / src / libraries / recipes / test_utils.py
1 #!/usr/bin/env python
2
3
4 from __future__ import with_statement
5
6 import inspect
7 import contextlib
8 import functools
9
10
11 def TODO(func):
12         """
13         unittest test method decorator that ignores
14         exceptions raised by test
15
16         Used to annotate test methods for code that may
17         not be written yet.  Ignores failures in the
18         annotated test method; fails if the text
19         unexpectedly succeeds.
20         !author http://kbyanc.blogspot.com/2007/06/pythons-unittest-module-aint-that-bad.html
21
22         Example:
23         >>> import unittest
24         >>> class ExampleTestCase(unittest.TestCase):
25         ...     @TODO
26         ...     def testToDo(self):
27         ...             MyModule.DoesNotExistYet('boo')
28         ...
29         """
30
31         @functools.wraps(func)
32         def wrapper(*args, **kw):
33                 try:
34                         func(*args, **kw)
35                         succeeded = True
36                 except:
37                         succeeded = False
38                 assert succeeded is False, \
39                         "%s marked TODO but passed" % func.__name__
40         return wrapper
41
42
43 def PlatformSpecific(platformList):
44         """
45         unittest test method decorator that only
46         runs test method if os.name is in the
47         given list of platforms
48         !author http://kbyanc.blogspot.com/2007/06/pythons-unittest-module-aint-that-bad.html
49         Example:
50         >>> import unittest
51         >>> class ExampleTestCase(unittest.TestCase):
52         ...     @PlatformSpecific(('mac', ))
53         ...     def testMacOnly(self):
54         ...             MyModule.SomeMacSpecificFunction()
55         ...
56         """
57
58         def decorator(func):
59                 import os
60
61                 @functools.wraps(func)
62                 def wrapper(*args, **kw):
63                         if os.name in platformList:
64                                 return func(*args, **kw)
65                 return wrapper
66         return decorator
67
68
69 def CheckReferences(func):
70         """
71         !author http://kbyanc.blogspot.com/2007/06/pythons-unittest-module-aint-that-bad.html
72         """
73
74         @functools.wraps(func)
75         def wrapper(*args, **kw):
76                 refCounts = []
77                 for i in range(5):
78                         func(*args, **kw)
79                         refCounts.append(XXXGetRefCount())
80                 assert min(refCounts) != max(refCounts), "Reference counts changed - %r" % refCounts
81
82         return wrapper
83
84
85 class expected(object):
86         """
87         >>> with expected(ZeroDivisionError):
88         ...     1 / 0
89         >>> with expected(AssertionError("expected ZeroDivisionError to have been thrown")):
90         ...     with expected(ZeroDivisionError):
91         ...             1 / 2
92         Traceback (most recent call last):
93                 File "/usr/lib/python2.5/doctest.py", line 1228, in __run
94                         compileflags, 1) in test.globs
95                 File "<doctest libraries.recipes.context.expected[1]>", line 3, in <module>
96                         1 / 2
97                 File "/media/data/Personal/Development/bzr/Recollection-trunk/src/libraries/recipes/context.py", line 139, in __exit__
98                         assert t is not None, ("expected {0:%s} to have been thrown" % (self._t.__name__))
99         AssertionError: expected {0:ZeroDivisionError} to have been thrown
100         >>> with expected(Exception("foo")):
101         ...     raise Exception("foo")
102         >>> with expected(Exception("bar")):
103         ...     with expected(Exception("foo")): # this won't catch it
104         ...             raise Exception("bar")
105         ...     assert False, "should not see me"
106         >>> with expected(Exception("can specify")):
107         ...     raise Exception("can specify prefixes")
108         >>> with expected(Exception("Base class fun")):
109         ...     raise IndexError("Base class fun")
110         """
111
112         def __init__(self, e):
113                 if isinstance(e, Exception):
114                         self._t, self._v = type(e), str(e)
115                 elif isinstance(e, type):
116                         self._t, self._v = e, ""
117                 else:
118                         raise Exception("usage: with expected(Exception): ... or "
119                                                         "with expected(Exception(\"text\")): ...")
120
121         def __enter__(self):
122                 try:
123                         pass
124                 except:
125                         pass # this is a Python 3000 way of saying sys.exc_clear()
126
127         def __exit__(self, t, v, tb):
128                 assert t is not None, ("expected {0:%s} to have been thrown" % (self._t.__name__))
129                 return self._t in inspect.getmro(t) and str(v).startswith(self._v)