1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
|
'''
These tests that the event handling mechanism does not produce memory leaks.
This could in principle happen, since it introduces a cyclic dependency that
might prevent garbage collection.
'''
import weakref
import gc
from obsub import event
def test_memory_leak():
# Define a test class and an event handler
class A(object):
@event
def on_blubb(self):
pass
def handler(self):
pass
# Instantiate and attach event handler
a = A()
a.on_blubb += handler
# Weak reference for testing
wr = weakref.ref(a)
# At first, weak reference exists
assert wr() is not None
# (implicitly) delete the A-instance by reassigning the only hard-ref.
# This is equivalent to `del a` but serves the purpose to demonstrate
# that there are very subtle ways to delete an instance:
a = None
# Trigger the garbage collection manually
gc.collect()
# after deletion it should be dead
assert wr() is None
def test_object_stays_alive_during_handler_execution():
# Define a test class and event handlers
class A(object):
@event
def on_blubb(self):
pass
deleted = False
class B(object):
def __init__(self, a):
# capture the only hard-ref on the A-instance:
self.a = a
self.a.on_blubb += self.handler
def handler(self, a):
# delete the A-instance
del self.a
a.deleted = True
del a
gc.collect()
def handler(a):
# We want a valid reference to the handled object, ...
assert a is not None
# ..., even if the deletion handler has already been called:
assert a.deleted
# Instantiate and attach event handler
b = B(A())
b.a.on_blubb += handler
wr = weakref.ref(b.a)
b.a.on_blubb()
# Trigger the garbage collection manually
gc.collect()
# make sure, b.a has been deleted after event handling
assert wr() is None
|