/[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 342 by bh, Fri Oct 18 17:28:46 2002 UTC revision 1839 by bh, Tue Oct 21 09:58:51 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 42  def initthuban(): Line 48  def initthuban():
48      """      """
49      global _initthuban_done      global _initthuban_done
50      if not _initthuban_done:      if not _initthuban_done:
51            # Thuban uses gettext to translate some strings. Some of these
52            # strings are tested for equality in some test cases. So we
53            # unset any LANG environment setting to make sure only the
54            # untranslated messages are used.
55            try:
56                del os.environ["LANG"]
57            except KeyError:
58                pass
59          add_thuban_dir_to_path()          add_thuban_dir_to_path()
60          import thubaninit          import thubaninit
61          _initthuban_done = 1          _initthuban_done = 1
62    
 def run_suite(suite):  
     """Run the test suite suite and return the result"""  
     runner = unittest.TextTestRunner(verbosity = 2)  
     return runner.run(suite)  
63    
64    #
65    # Special test runner and result that support skipping tests
66    #
67    
68    class SkipTest(Exception):
69        """Exception to raise in tests that are skipped for some reason
70    
71        For instance, since gdal support is optional, test cases that
72        require gdal raise this exception to indicate that they are skipped.
73        Skipped is different from failure or error in that it is expected
74        under certain circumstances.
75        """
76    
77    class ThubanTestResult(unittest._TextTestResult):
78    
79        def __init__(self, stream, descriptions, verbosity):
80            unittest._TextTestResult.__init__(self, stream, descriptions,
81                                              verbosity)
82            self.skipped_tests = {}
83    
84        def add_skipped_test(self, test, exc):
85            reason = str(exc)
86            self.skipped_tests.setdefault(reason, []).append(test)
87    
88        def count_skipped(self):
89            sum = 0
90            for tests in self.skipped_tests.values():
91                sum += len(tests)
92            return sum
93    
94        def addError(self, test, err):
95            """Extend inherited method to handle SkipTest exceptions specially
96            """
97            #print "addError", test, err
98            if isinstance(err[1], SkipTest):
99                self.add_skipped_test(test, err[1])
100                if self.showAll:
101                    self.stream.writeln("skipped")
102                elif self.dots:
103                    self.stream.write('S')
104            else:
105                unittest._TextTestResult.addError(self, test, err)
106    
107        def printErrors(self):
108            if self.skipped_tests:
109                if self.dots or self.showAll:
110                    self.stream.writeln()
111                self.stream.writeln("Skipped tests:")
112                for reason, tests in self.skipped_tests.items():
113                    self.stream.writeln("  %s:" % reason)
114                    for test in tests:
115                        self.stream.writeln("    " + test.id())
116            unittest._TextTestResult.printErrors(self)
117    
118        def getDescription(self, test):
119            return test.id()
120    
121    
122    class ThubanTestRunner(unittest.TextTestRunner):
123    
124        def _makeResult(self):
125            return ThubanTestResult(self.stream, self.descriptions, self.verbosity)
126    
127        def run(self, test):
128            result = unittest.TextTestRunner.run(self, test)
129            self.stream.writeln("skipped = %d" % result.count_skipped())
130            return result
131    
132    
133    class ThubanTestProgram(unittest.TestProgram):
134    
135        def runTests(self):
136            """Extend inherited method so that we use a ThubanTestRunner"""
137            self.testRunner = ThubanTestRunner(verbosity = self.verbosity)
138            unittest.TestProgram.runTests(self)
139    
140    
141    def execute_as_testsuite(callable, *args, **kw):
142        """Call callable  with args as if it were the entry point to the test suite
143    
144        Return watever callable returns.
145    
146        This is a helper function for run_tests and runtests.py. Call
147        callable in a try-finally block and run some cleanup and print some
148        additional information in the finally block.
149    
150        The additionaly information include:
151    
152         - A list of uncollected objects (after an explicit garbage
153           collector call)
154    
155         - any unsubscribed messages
156        """
157        try:
158            return callable(*args, **kw)
159        finally:
160            # This has to be in a finally clause because unittest.main()
161            # ends with a sys.exit to make sure that the process exits with
162            # an appropriate exit code
163    
164            # Shutdown the postgis server if it's running
165            try:
166                postgissupport.shutdown_test_server()
167            except:
168                traceback.print_exc()
169    
170            # Print additional information
171            print_additional_summary()
172    
173    def run_tests():
174        """Frontend for unittest.main that prints some additional debug information
175    
176        After calling unittest.main, run the garbage collector and print
177        uncollected objects. Also print any un-unsubscribed messages.
178        """
179        execute_as_testsuite(ThubanTestProgram)
180    
181    
182    def print_additional_summary():
183        """Print some additional summary information after tests have been run"""
184        print_garbage_information()
185        import xmlsupport
186        xmlsupport.print_summary_message()
187    
188    def print_garbage_information():
189        """Print information about things that haven't been cleaned up.
190    
191        Run the garbage collector and print uncollected objects. Also print
192        any un-unsubscribed messages.
193        """
194        # this function may be called indirectly from test cases that test
195        # test support modules which do not use anything from thuban itself,
196        # so we call initthuban so that we can import the connector module
197        initthuban()
198        import gc, Thuban.Lib.connector
199        gc.collect()
200        if gc.garbage:
201            print
202            print "There are %d uncollected objects:" % len(gc.garbage)
203            print gc.garbage
204        Thuban.Lib.connector._the_connector.print_connections()
205    
206    #
207    
208  def create_temp_dir():  def create_temp_dir():
209      """Create a temporary directory and return its name.      """Create a temporary directory and return its name.
# Line 85  class FileTestMixin: Line 238  class FileTestMixin:
238          return create_temp_dir()          return create_temp_dir()
239    
240    
241    
242    class FileLoadTestCase(unittest.TestCase, FileTestMixin):
243    
244        """Base class for test case that test loading files.
245    
246        This base class provides some common infrastructure for testing the
247        reading of files.
248    
249        Each test case should be its own class derived from this one. There
250        is one file associated with each class. The contents are defined by
251        the file_contents class attribute and its name by the filename
252        method.
253    
254        Derived classes usually only have to provide appropriate values for
255        the file_contents and file_extension class attributes.
256        """
257    
258        file_contents = None
259        file_extension = ""
260    
261        def filename(self):
262            """Return the name of the test file to use.
263    
264            The default implementation simply calls self.volatile_file_name
265            with a basename derived from the class name by stripping off a
266            leading 'test_' and appending self.file_extension.
267            """
268            name = self.__class__.__name__
269            if name.startswith("test_"):
270                name = name[5:]
271            return self.temp_file_name(name + self.file_extension)
272    
273        def setUp(self):
274            """Create the volatile file for the test.
275    
276            Write self.contents (which should be a string) to the file named
277            by self.filename().
278            """
279            filename = self.filename()
280            file = open(filename, "w")
281            file.write(self.file_contents)
282            file.close()
283    
284    
285  class FloatComparisonMixin:  class FloatComparisonMixin:
286    
287      """      """
# Line 95  class FloatComparisonMixin: Line 292  class FloatComparisonMixin:
292      """      """
293    
294      fp_epsilon = 1e-6      fp_epsilon = 1e-6
295            fp_inf = float('1e1000')   # FIXME: hack for infinite
296      def assertFloatEqual(self, test, value):  
297        def assertFloatEqual(self, test, value, epsilon = None):
298          """Assert equality of test and value with some tolerance.          """Assert equality of test and value with some tolerance.
299    
300          Assert that the absolute difference between test and value is          Assert that the absolute difference between test and value is
301          less than self.fp_epsilon.          less than self.fp_epsilon.
302          """          """
303          self.assert_(self.fp_epsilon > abs(test - value),          if epsilon is None:
304                       "abs(%g - %g) >= %g" % (test, value, self.fp_epsilon))              epsilon = self.fp_epsilon
305            if abs(test) == self.fp_inf:
306                self.assertEqual(test, value)
307            else:
308                self.assert_(epsilon > abs(test - value),
309                         "abs(%g - %g) >= %g" % (test, value, epsilon))
310    
311      def assertFloatSeqEqual(self, test, value, epsilon = None):      def assertFloatSeqEqual(self, test, value, epsilon = None):
312          """Assert equality of the sequences test and value with some tolerance.          """Assert equality of the sequences test and value with some tolerance.
# Line 112  class FloatComparisonMixin: Line 315  class FloatComparisonMixin:
315          value in test and value is less than the optional parameter          value in test and value is less than the optional parameter
316          epsilon. If epsilon is not given use self.fp_epsilon.          epsilon. If epsilon is not given use self.fp_epsilon.
317          """          """
318          if epsilon is None:          self.assertEquals(len(test), len(value))
319              epsilon = self.fp_epsilon          for i in range(len(test)):
320                self.assertFloatEqual(test[i], value[i], epsilon)
321    
322        def assertPointListEquals(self, test, value):
323            """Assert equality of two lists of lists of tuples of float
324    
325            This assertion is usually used to compare the geometry of shapes
326            as returned by a Shape object's Points() method, hence the name.
327            """
328          for i in range(len(test)):          for i in range(len(test)):
329              self.assert_(epsilon > abs(test[i] - value[i]),              self.assertEquals(len(test[i]), len(value[i]))
330                           "abs(%g - %g) >= %g" % (test[i], value[i], epsilon))              for j in range(len(test[i])):
331                    self.assertFloatSeqEqual(test[i][j], value[i][j])
332    
333    
334  class SubscriberMixin:  class SubscriberMixin:
# Line 158  class SubscriberMixin: Line 370  class SubscriberMixin:
370      def check_messages(self, messages):      def check_messages(self, messages):
371          """Check whether the messages received match the list messages"""          """Check whether the messages received match the list messages"""
372          self.assertEquals(messages, self.received_messages)          self.assertEquals(messages, self.received_messages)
373    

Legend:
Removed from v.342  
changed lines
  Added in v.1839

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26