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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.292  
changed lines
  Added in v.1605

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26