/[thuban]/branches/WIP-pyshapelib-bramz/test/support.py
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/test/support.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1601 - (hide annotations)
Mon Aug 18 17:22:07 2003 UTC (21 years, 6 months ago) by bh
Original Path: trunk/thuban/test/support.py
File MIME type: text/x-python
File size: 10937 byte(s)
* test/support.py (ThubanTestResult.printErrors): Indent the
reason for the skips in the output to make it a bit more readable.
(execute_as_testsuite): New helper function to run a test suite
and print some more information.
(run_tests): Use execute_as_testsuite to run the tests

* test/runtests.py (main): Use execute_as_testsuite to run the
tests

1 bh 596 # Copyright (c) 2002, 2003 by Intevation GmbH
2 bh 292 # Authors:
3     # Bernhard Herzog <[email protected]>
4     #
5     # This program is free software under the GPL (>=v2)
6     # Read the file COPYING coming with Thuban for details.
7    
8     """
9     Support classes and function for the test suite
10     """
11    
12     __version__ = "$Revision$"
13     # $Source$
14     # $Id$
15    
16     import os, sys
17     import unittest
18 bh 1601 import traceback
19 bh 292
20     def thuban_dir():
21     """Return the directory containing the Thuban package"""
22     thisdir = os.path.dirname(__file__)
23     return os.path.join(thisdir, os.pardir)
24    
25 bh 1245 def resource_dir():
26     return os.path.join(thuban_dir(), "Resources")
27 bh 292
28     def add_thuban_dir_to_path():
29     """Insert the Thuban directory at the beginning of the python path.
30    
31     If it's already part of the path, remove later occurrences.
32     """
33     dir = thuban_dir()
34     while 1:
35     try:
36     sys.path.remove(dir)
37     except ValueError:
38     break
39     sys.path.insert(0, dir)
40    
41    
42     _initthuban_done = 0
43     def initthuban():
44     """Initialize the interpreter for using Thuban modules
45     """
46     global _initthuban_done
47     if not _initthuban_done:
48     add_thuban_dir_to_path()
49     import thubaninit
50     _initthuban_done = 1
51    
52 bh 1555
53     #
54     # Special test runner and result that support skipping tests
55     #
56    
57     class SkipTest(Exception):
58     """Exception to raise in tests that are skipped for some reason
59    
60     For instance, since gdal support is optional, test cases that
61     require gdal raise this exception to indicate that they are skipped.
62     Skipped is different from failure or error in that it is expected
63     under certain circumstances.
64     """
65    
66     class ThubanTestResult(unittest._TextTestResult):
67    
68     def __init__(self, stream, descriptions, verbosity):
69     unittest._TextTestResult.__init__(self, stream, descriptions,
70     verbosity)
71     self.skipped_tests = {}
72    
73     def add_skipped_test(self, test, exc):
74     reason = str(exc)
75     self.skipped_tests.setdefault(reason, []).append(test)
76    
77     def count_skipped(self):
78     sum = 0
79     for tests in self.skipped_tests.values():
80     sum += len(tests)
81     return sum
82    
83     def addError(self, test, err):
84     """Extend inherited method to handle SkipTest exceptions specially
85     """
86     #print "addError", test, err
87     if isinstance(err[1], SkipTest):
88     self.add_skipped_test(test, err[1])
89     if self.showAll:
90     self.stream.writeln("skipped")
91     elif self.dots:
92     self.stream.write('S')
93     else:
94     unittest._TextTestResult.addError(self, test, err)
95    
96     def printErrors(self):
97     if self.skipped_tests:
98     if self.dots or self.showAll:
99     self.stream.writeln()
100     self.stream.writeln("Skipped tests:")
101     for reason, tests in self.skipped_tests.items():
102 bh 1601 self.stream.writeln(" %s:" % reason)
103 bh 1555 for test in tests:
104     self.stream.writeln(" " + test.id())
105     unittest._TextTestResult.printErrors(self)
106    
107    
108     class ThubanTestRunner(unittest.TextTestRunner):
109    
110     def _makeResult(self):
111     return ThubanTestResult(self.stream, self.descriptions, self.verbosity)
112    
113     def run(self, test):
114     result = unittest.TextTestRunner.run(self, test)
115     self.stream.writeln("skipped = %d" % result.count_skipped())
116     return result
117    
118    
119     class ThubanTestProgram(unittest.TestProgram):
120    
121     def runTests(self):
122     """Extend inherited method so that we use a ThubanTestRunner"""
123     print "ThubanTestProgram.runTests"
124     self.testRunner = ThubanTestRunner(verbosity = self.verbosity)
125     unittest.TestProgram.runTests(self)
126    
127    
128 bh 1601 def execute_as_testsuite(callable, *args, **kw):
129     """Call callable with args as if it were the entry point to the test suite
130 bh 292
131 bh 1601 Return watever callable returns.
132    
133     This is a helper function for run_tests and runtests.py. Call
134     callable in a try-finally block and run some cleanup and print some
135     additional information in the finally block.
136    
137     The additionaly information include:
138    
139     - A list of uncollected objects (after an explicit garbage
140     collector call)
141    
142     - any unsubscribed messages
143 bh 596 """
144     try:
145 bh 1601 return callable(*args, **kw)
146 bh 596 finally:
147     # This has to be in a finally clause because unittest.main()
148     # ends with a sys.exit to make sure that the process exits with
149     # an appropriate exit code
150 bh 1601
151     # Print additional information
152 bh 1245 print_additional_summary()
153 bh 292
154 bh 1601 def run_tests():
155     """Frontend for unittest.main that prints some additional debug information
156    
157     After calling unittest.main, run the garbage collector and print
158     uncollected objects. Also print any un-unsubscribed messages.
159     """
160     execute_as_testsuite(ThubanTestProgram)
161    
162    
163 bh 1245 def print_additional_summary():
164     """Print some additional summary information after tests have been run"""
165     print_garbage_information()
166     import xmlsupport
167     xmlsupport.print_summary_message()
168    
169 bh 596 def print_garbage_information():
170     """Print information about things that haven't been cleaned up.
171    
172     Run the garbage collector and print uncollected objects. Also print
173     any un-unsubscribed messages.
174     """
175     import gc, Thuban.Lib.connector
176     gc.collect()
177     if gc.garbage:
178     print
179     print "There are %d uncollected objects:" % len(gc.garbage)
180     print gc.garbage
181     Thuban.Lib.connector._the_connector.print_connections()
182    
183 bh 1555 #
184 bh 596
185 bh 292 def create_temp_dir():
186     """Create a temporary directory and return its name.
187    
188     The temporary directory is always called temp and is created in the
189     directory where support module is located.
190    
191     If the temp directory already exists, just return the name.
192     """
193     name = os.path.abspath(os.path.join(os.path.dirname(__file__), "temp"))
194    
195     # if the directory already exists, we're done
196     if os.path.isdir(name):
197     return name
198    
199     # create the directory
200     os.mkdir(name)
201     return name
202    
203    
204     class FileTestMixin:
205    
206     """Mixin class for tests that use files in the temporary directory
207     """
208    
209     def temp_file_name(self, basename):
210     """Return the full name of the file named basename in the temp. dir"""
211     return os.path.join(create_temp_dir(), basename)
212    
213     def temp_dir(self):
214     """Return the name of the directory for the temporary files"""
215     return create_temp_dir()
216 bh 324
217    
218 bh 956
219     class FileLoadTestCase(unittest.TestCase, FileTestMixin):
220    
221     """Base class for test case that test loading files.
222    
223     This base class provides some common infrastructure for testing the
224     reading of files.
225    
226     Each test case should be its own class derived from this one. There
227     is one file associated with each class. The contents are defined by
228     the file_contents class attribute and its name by the filename
229     method.
230    
231     Derived classes usually only have to provide appropriate values for
232     the file_contents and file_extension class attributes.
233     """
234    
235     file_contents = None
236     file_extension = ""
237    
238     def filename(self):
239     """Return the name of the test file to use.
240    
241     The default implementation simply calls self.volatile_file_name
242     with a basename derived from the class name by stripping off a
243     leading 'test_' and appending self.file_extension.
244     """
245     name = self.__class__.__name__
246     if name.startswith("test_"):
247     name = name[5:]
248     return self.temp_file_name(name + self.file_extension)
249    
250     def setUp(self):
251     """Create the volatile file for the test.
252    
253     Write self.contents (which should be a string) to the file named
254     by self.filename().
255     """
256     filename = self.filename()
257     file = open(filename, "w")
258     file.write(self.file_contents)
259     file.close()
260    
261    
262 bh 1421 class FloatComparisonMixin:
263 bh 324
264     """
265     Mixin class for tests comparing floating point numbers.
266    
267     This class provides a few methods for testing floating point
268     operations.
269     """
270    
271     fp_epsilon = 1e-6
272 jonathan 1263 fp_inf = float('1e1000') # FIXME: hack for infinite
273 bh 1574
274 jonathan 1397 def assertFloatEqual(self, test, value, epsilon = None):
275 bh 324 """Assert equality of test and value with some tolerance.
276    
277     Assert that the absolute difference between test and value is
278     less than self.fp_epsilon.
279     """
280 jonathan 1397 if epsilon is None:
281     epsilon = self.fp_epsilon
282 jonathan 1263 if abs(test) == self.fp_inf:
283     self.assertEqual(test, value)
284     else:
285 jonathan 1397 self.assert_(epsilon > abs(test - value),
286     "abs(%g - %g) >= %g" % (test, value, epsilon))
287 bh 324
288     def assertFloatSeqEqual(self, test, value, epsilon = None):
289     """Assert equality of the sequences test and value with some tolerance.
290    
291     Assert that the absolute difference between each corresponding
292     value in test and value is less than the optional parameter
293     epsilon. If epsilon is not given use self.fp_epsilon.
294     """
295     for i in range(len(test)):
296 jonathan 1397 self.assertFloatEqual(test[i], value[i], epsilon)
297 bh 324
298 bh 1574 def assertPointListEquals(self, test, value):
299     """Assert equality of two lists of lists of tuples of float
300    
301     This assertion is usually used to compare the geometry of shapes
302     as returned by a Shape object's Points() method, hence the name.
303     """
304     for i in range(len(test)):
305     self.assertEquals(len(test[i]), len(value[i]))
306     for j in range(len(test[i])):
307     self.assertFloatSeqEqual(test[i][j], value[i][j])
308    
309    
310 bh 324 class SubscriberMixin:
311    
312     """Mixin class for tests for messages sent through the Connector
313    
314     The SubscriberMixin has some methods that can be used as subscribers
315     of events that when called append information about the message into
316     a list of messages received.
317    
318     A derived class should call the clear_messages() method in both its
319     setUp and tearDown methods to clear the list of messages received.
320     """
321    
322     def clear_messages(self):
323     """Clear the list of received messages.
324    
325     Call this at least in the tests setUp and tearDown methods. It's
326     important to do it in tearDown too because otherwise there may
327     be cyclic references.
328     """
329     self.received_messages = []
330    
331     def subscribe_no_params(self):
332     """Method for subscriptions without parameters.
333    
334     Add an empty tuple to the list of received messages.
335     """
336     self.received_messages.append(())
337    
338     def subscribe_with_params(self, *args):
339     """Method for subscriptions with parameters.
340    
341     Append the tuple will all arguments to this function (except for
342     the self argument) to the list of received messages.
343     """
344     self.received_messages.append(args)
345    
346     def check_messages(self, messages):
347     """Check whether the messages received match the list messages"""
348     self.assertEquals(messages, self.received_messages)
349 jonathan 904

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26