/[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 1601 by bh, Mon Aug 18 17:22:07 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  def thuban_dir():  def thuban_dir():
21      """Return the directory containing the Thuban package"""      """Return the directory containing the Thuban package"""
22      thisdir = os.path.dirname(__file__)      thisdir = os.path.dirname(__file__)
23      return os.path.join(thisdir, os.pardir)      return os.path.join(thisdir, os.pardir)
24    
25    def resource_dir():
26        return os.path.join(thuban_dir(), "Resources")
27    
28  def add_thuban_dir_to_path():  def add_thuban_dir_to_path():
29      """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 49  def initthuban():
49          import thubaninit          import thubaninit
50          _initthuban_done = 1          _initthuban_done = 1
51    
 def run_suite(suite):  
     """Run the test suite suite and return the result"""  
     runner = unittest.TextTestRunner(verbosity = 2)  
     return runner.run(suite)  
52    
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                    self.stream.writeln("  %s:" % reason)
103                    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    def execute_as_testsuite(callable, *args, **kw):
129        """Call callable  with args as if it were the entry point to the test suite
130    
131        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        """
144        try:
145            return callable(*args, **kw)
146        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    
151            # Print additional information
152            print_additional_summary()
153    
154    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    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    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    #
184    
185  def create_temp_dir():  def create_temp_dir():
186      """Create a temporary directory and return its name.      """Create a temporary directory and return its name.
# Line 83  class FileTestMixin: Line 213  class FileTestMixin:
213      def temp_dir(self):      def temp_dir(self):
214          """Return the name of the directory for the temporary files"""          """Return the name of the directory for the temporary files"""
215          return create_temp_dir()          return create_temp_dir()
216    
217    
218    
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    class FloatComparisonMixin:
263    
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        fp_inf = float('1e1000')   # FIXME: hack for infinite
273    
274        def assertFloatEqual(self, test, value, epsilon = None):
275            """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            if epsilon is None:
281                epsilon = self.fp_epsilon
282            if abs(test) == self.fp_inf:
283                self.assertEqual(test, value)
284            else:
285                self.assert_(epsilon > abs(test - value),
286                         "abs(%g - %g) >= %g" % (test, value, epsilon))
287    
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                self.assertFloatEqual(test[i], value[i], epsilon)
297    
298        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    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    

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26