/[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 596 by bh, Thu Apr 3 11:37:01 2003 UTC revision 1736 by bh, Mon Sep 22 18:46:56 2003 UTC
# 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_tests():  
     """Frontend for unittest.main that prints some additional debug information  
63    
64      After calling unittest.main, run the garbage collector and print  #
65      uncollected objects. Also print any un-unsubscribed messages.  # 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    
119    class ThubanTestRunner(unittest.TextTestRunner):
120    
121        def _makeResult(self):
122            return ThubanTestResult(self.stream, self.descriptions, self.verbosity)
123    
124        def run(self, test):
125            result = unittest.TextTestRunner.run(self, test)
126            self.stream.writeln("skipped = %d" % result.count_skipped())
127            return result
128    
129    
130    class ThubanTestProgram(unittest.TestProgram):
131    
132        def runTests(self):
133            """Extend inherited method so that we use a ThubanTestRunner"""
134            self.testRunner = ThubanTestRunner(verbosity = self.verbosity)
135            unittest.TestProgram.runTests(self)
136    
137    
138    def execute_as_testsuite(callable, *args, **kw):
139        """Call callable  with args as if it were the entry point to the test suite
140    
141        Return watever callable returns.
142    
143        This is a helper function for run_tests and runtests.py. Call
144        callable in a try-finally block and run some cleanup and print some
145        additional information in the finally block.
146    
147        The additionaly information include:
148    
149         - A list of uncollected objects (after an explicit garbage
150           collector call)
151    
152         - any unsubscribed messages
153      """      """
154      try:      try:
155          unittest.main()          return callable(*args, **kw)
156      finally:      finally:
157          # This has to be in a finally clause because unittest.main()          # This has to be in a finally clause because unittest.main()
158          # ends with a sys.exit to make sure that the process exits with          # ends with a sys.exit to make sure that the process exits with
159          # an appropriate exit code          # an appropriate exit code
160          print_garbage_information()  
161            # Shutdown the postgis server if it's running
162            try:
163                postgissupport.shutdown_test_server()
164            except:
165                traceback.print_exc()
166    
167            # Print additional information
168            print_additional_summary()
169    
170    def run_tests():
171        """Frontend for unittest.main that prints some additional debug information
172    
173        After calling unittest.main, run the garbage collector and print
174        uncollected objects. Also print any un-unsubscribed messages.
175        """
176        execute_as_testsuite(ThubanTestProgram)
177    
178    
179    def print_additional_summary():
180        """Print some additional summary information after tests have been run"""
181        print_garbage_information()
182        import xmlsupport
183        xmlsupport.print_summary_message()
184    
185  def print_garbage_information():  def print_garbage_information():
186      """Print information about things that haven't been cleaned up.      """Print information about things that haven't been cleaned up.
# Line 66  def print_garbage_information(): Line 188  def print_garbage_information():
188      Run the garbage collector and print uncollected objects. Also print      Run the garbage collector and print uncollected objects. Also print
189      any un-unsubscribed messages.      any un-unsubscribed messages.
190      """      """
191        # this function may be called indirectly from test cases that test
192        # test support modules which do not use anything from thuban itself,
193        # so we call initthuban so that we can import the connector module
194        initthuban()
195      import gc, Thuban.Lib.connector      import gc, Thuban.Lib.connector
196      gc.collect()      gc.collect()
197      if gc.garbage:      if gc.garbage:
# Line 74  def print_garbage_information(): Line 200  def print_garbage_information():
200          print gc.garbage          print gc.garbage
201      Thuban.Lib.connector._the_connector.print_connections()      Thuban.Lib.connector._the_connector.print_connections()
202    
203    #
204    
205  def create_temp_dir():  def create_temp_dir():
206      """Create a temporary directory and return its name.      """Create a temporary directory and return its name.
# Line 108  class FileTestMixin: Line 235  class FileTestMixin:
235          return create_temp_dir()          return create_temp_dir()
236    
237    
238    
239    class FileLoadTestCase(unittest.TestCase, FileTestMixin):
240    
241        """Base class for test case that test loading files.
242    
243        This base class provides some common infrastructure for testing the
244        reading of files.
245    
246        Each test case should be its own class derived from this one. There
247        is one file associated with each class. The contents are defined by
248        the file_contents class attribute and its name by the filename
249        method.
250    
251        Derived classes usually only have to provide appropriate values for
252        the file_contents and file_extension class attributes.
253        """
254    
255        file_contents = None
256        file_extension = ""
257    
258        def filename(self):
259            """Return the name of the test file to use.
260    
261            The default implementation simply calls self.volatile_file_name
262            with a basename derived from the class name by stripping off a
263            leading 'test_' and appending self.file_extension.
264            """
265            name = self.__class__.__name__
266            if name.startswith("test_"):
267                name = name[5:]
268            return self.temp_file_name(name + self.file_extension)
269    
270        def setUp(self):
271            """Create the volatile file for the test.
272    
273            Write self.contents (which should be a string) to the file named
274            by self.filename().
275            """
276            filename = self.filename()
277            file = open(filename, "w")
278            file.write(self.file_contents)
279            file.close()
280    
281    
282  class FloatComparisonMixin:  class FloatComparisonMixin:
283    
284      """      """
# Line 118  class FloatComparisonMixin: Line 289  class FloatComparisonMixin:
289      """      """
290    
291      fp_epsilon = 1e-6      fp_epsilon = 1e-6
292            fp_inf = float('1e1000')   # FIXME: hack for infinite
293      def assertFloatEqual(self, test, value):  
294        def assertFloatEqual(self, test, value, epsilon = None):
295          """Assert equality of test and value with some tolerance.          """Assert equality of test and value with some tolerance.
296    
297          Assert that the absolute difference between test and value is          Assert that the absolute difference between test and value is
298          less than self.fp_epsilon.          less than self.fp_epsilon.
299          """          """
300          self.assert_(self.fp_epsilon > abs(test - value),          if epsilon is None:
301                       "abs(%g - %g) >= %g" % (test, value, self.fp_epsilon))              epsilon = self.fp_epsilon
302            if abs(test) == self.fp_inf:
303                self.assertEqual(test, value)
304            else:
305                self.assert_(epsilon > abs(test - value),
306                         "abs(%g - %g) >= %g" % (test, value, epsilon))
307    
308      def assertFloatSeqEqual(self, test, value, epsilon = None):      def assertFloatSeqEqual(self, test, value, epsilon = None):
309          """Assert equality of the sequences test and value with some tolerance.          """Assert equality of the sequences test and value with some tolerance.
# Line 135  class FloatComparisonMixin: Line 312  class FloatComparisonMixin:
312          value in test and value is less than the optional parameter          value in test and value is less than the optional parameter
313          epsilon. If epsilon is not given use self.fp_epsilon.          epsilon. If epsilon is not given use self.fp_epsilon.
314          """          """
         if epsilon is None:  
             epsilon = self.fp_epsilon  
315          for i in range(len(test)):          for i in range(len(test)):
316              self.assert_(epsilon > abs(test[i] - value[i]),              self.assertFloatEqual(test[i], value[i], epsilon)
317                           "abs(%g - %g) >= %g" % (test[i], value[i], epsilon))  
318        def assertPointListEquals(self, test, value):
319            """Assert equality of two lists of lists of tuples of float
320    
321            This assertion is usually used to compare the geometry of shapes
322            as returned by a Shape object's Points() method, hence the name.
323            """
324            for i in range(len(test)):
325                self.assertEquals(len(test[i]), len(value[i]))
326                for j in range(len(test[i])):
327                    self.assertFloatSeqEqual(test[i][j], value[i][j])
328    
329    
330  class SubscriberMixin:  class SubscriberMixin:
# Line 181  class SubscriberMixin: Line 366  class SubscriberMixin:
366      def check_messages(self, messages):      def check_messages(self, messages):
367          """Check whether the messages received match the list messages"""          """Check whether the messages received match the list messages"""
368          self.assertEquals(messages, self.received_messages)          self.assertEquals(messages, self.received_messages)
369    

Legend:
Removed from v.596  
changed lines
  Added in v.1736

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26