diff --git a/ChangeLog b/ChangeLog index fe86571..6a49066 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2008-03-10 Paul Pogonyshev + + * run-tests.py (TestProgram.runTests): Emphasize heavy + gc.collect() usage. + + * test/__common.py (NotifyTestCase.setUp): Remember number of + garbage-collectable objects before test. + (NotifyTestCase.tearDown): Check that the number doesn't change. + (NotifyTestCase.collect_garbage): Remove the only + argument (unused). Return number of garbage-collectable objects. + 2008-03-03 Paul Pogonyshev * version: Release 0.1.15. diff --git a/run-tests.py b/run-tests.py index f5fc5e3..5103107 100755 --- a/run-tests.py +++ b/run-tests.py @@ -93,7 +93,7 @@ class TestProgram (unittest.TestProgram): def runTests (self): _build_extensions () - print ('\nNote that most of the time is spent in gc.collect() calls, not in this package\n') + print ('\nNote that almost all time is spent in gc.collect() calls, not in this package\n') unittest.TestProgram.runTests (self) diff --git a/test/__common.py b/test/__common.py index d65ef30..31d82fa 100644 --- a/test/__common.py +++ b/test/__common.py @@ -75,15 +75,23 @@ def setUp (self): super (NotifyTestCase, self).setUp () gc.set_threshold (0, 0, 0) - self.__num_active_protections = AbstractGCProtector.default.num_active_protections + + self.__num_collectable_objects = self.collect_garbage () + self.__num_active_protections = AbstractGCProtector.default.num_active_protections # It is important to leave no garbage behind, since `AbstractGCProtector.default' is - # only assignable in 'fresh' state. + # only assignable in 'fresh' state. Tests also must be self-contained, therefore we + # check that tests don't leave new garbage-collectable objects or GC protections. + # Those almost certainly indicate a memory leak. def tearDown (self): super (NotifyTestCase, self).tearDown () - self.collect_garbage () + num_collectable_objects = self.collect_garbage () + if num_collectable_objects != self.__num_collectable_objects: + raise ValueError (('number of garbage-collectable objects before and after the test ' + 'differ: %d != %d') + % (self.__num_collectable_objects, num_collectable_objects)) if AbstractGCProtector.default.num_active_protections != self.__num_active_protections: raise ValueError (('number of active GC protections before and after the test differ: ' @@ -119,30 +127,27 @@ def assert_not_equal_thoroughly (self, value1, value2): # Note: hashes are _not_ required to be different, so don't test them. - def collect_garbage (self, times = None): - if times: - # This is the old way, not used now. We use a slower, but more robust way of - # 'collect while collects' below. - for k in range (times): - gc.collect () - else: - num_objects = self.__count_garbage_collectable_objects () - - # TODO: Account for 'statics' like notify.Condition.TRUE. Condition below is - # always false due to 'statics'. - if num_objects == 0: - return; - - num_passes = 0 - while num_passes < 20: - gc.collect () - num_objects_new = self.__count_garbage_collectable_objects () - - if num_objects_new < num_objects: - num_objects = num_objects_new - num_passes += 1 - else: - break + def collect_garbage (self): + num_objects = self.__count_garbage_collectable_objects () + + # TODO: Account for 'statics' like notify.Condition.TRUE. Condition below is + # always false due to these 'statics'. + if num_objects == 0: + return 0 + + num_passes = 0 + while num_passes < 20: + gc.collect () + num_objects_new = self.__count_garbage_collectable_objects () + + if num_objects_new < num_objects: + num_objects = num_objects_new + num_passes += 1 + else: + return num_objects + + # If we spent a lot of passes, something is probably wrong. + return -1 def __count_garbage_collectable_objects (): return len ([object for object in gc.get_objects ()