#!/usr/bin/env python
# vim: sw=4

# Test the GObject stuff with regards to references.

import sys
sys.path.insert(0, '.libs')
import unittest
import gobject, weakref, gc

class MyObject (gobject.GObject):
    __gsignals__ = {
	'my_signal': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
		      (gobject.TYPE_INT,))
    }

    def __init__(self):
	self.__gobject_init__()

    def do_my_signal(self, arg, *args):
	print 'do_my_signal(' + str(self) + ', ' + str(arg) + ')'
	print '		extra args:', args

    def signal_handler1(self, arg):
	print 'signal_handler1', self, arg

    def signal_handler2(self, arg1, arg2):
	print 'signal_handler2', self, arg1, arg2

gobject.type_register (MyObject)

gobject_ref = sys.getrefcount(gobject.GObject)

class ObjectTestCase(unittest.TestCase):

    def testClassesInGeneral1(self):
	class A:
	    def my_method(self):
		pass
	self.failUnlessEqual (sys.getrefcount(A), 2)
	self.failUnlessEqual (sys.getrefcount(A.my_method), 1)

    def testClassesInGeneral2(self):
	class B:
	    def my_method1(self):
		pass
	    def my_method2(self):
		pass
	    def my_method3(self):
		pass

	self.failUnlessEqual (sys.getrefcount(B), 2)
	self.failUnlessEqual (sys.getrefcount(B.my_method1), 1)
	self.failUnlessEqual (sys.getrefcount(B.my_method2), 1)
	self.failUnlessEqual (sys.getrefcount(B.my_method3), 1)

    def testClassesInGeneral3(self):
	class A:
	    def my_method(self):
		pass

	class C(A):
	    def my_method1(self):
		pass

	self.failUnlessEqual(sys.getrefcount(C), 2)
	self.failUnlessEqual(sys.getrefcount(C.my_method), 1)
	self.failUnlessEqual(sys.getrefcount(C.my_method1), 1)

	# An extra reference is created to C...
	c = C()
	self.failUnlessEqual(sys.getrefcount(c), 2)
	self.failUnlessEqual(sys.getrefcount(c.my_method), 1)
	self.failUnlessEqual(sys.getrefcount(c.my_method1), 1)
	self.failUnlessEqual(sys.getrefcount(C), 3)
	self.failUnlessEqual(sys.getrefcount(C.my_method), 1)
	self.failUnlessEqual(sys.getrefcount(C.my_method1), 1)
	
	# A reference is added to c and C...
	f = c.my_method
	self.failUnlessEqual(sys.getrefcount(c), 3)
	self.failUnlessEqual(sys.getrefcount(c.my_method), 1)
	self.failUnlessEqual(sys.getrefcount(c.my_method1), 1)
	self.failUnlessEqual(sys.getrefcount(C), 4)
	self.failUnlessEqual(sys.getrefcount(C.my_method), 1)
	self.failUnlessEqual(sys.getrefcount(C.my_method1), 1)

    def testClassesInGeneral4(self):
	global gobject_ref
	self.failUnlessEqual(sys.getrefcount(gobject.GObject), gobject_ref)
	r = sys.getrefcount(gobject.GObject)
	class D(gobject.GObject):
	    def my_method(self):
		pass

	self.failUnlessEqual(sys.getrefcount(D), 3)
	self.failUnlessEqual(sys.getrefcount(gobject.GObject), r + 3) # ???
	self.failUnlessEqual(sys.getrefcount(D.my_method), 1)

	gobject.type_register(D)
	self.failUnlessEqual(sys.getrefcount(D), 4)
	self.failUnlessEqual(sys.getrefcount(gobject.GObject), r + 3) # ???
	self.failUnlessEqual(sys.getrefcount(D.my_method), 1)
	
	gobject_ref += 3

    def testClassesInGeneral5(self):
	global gobject_ref
	self.failUnlessEqual(sys.getrefcount(gobject.GObject), gobject_ref)
	r = sys.getrefcount(gobject.GObject)
	class E(gobject.GObject):
	    __gproperties__ = {
		'foo': (gobject.TYPE_STRING, 'foo property',
			'the foo of the object',
			'bar', gobject.PARAM_READWRITE),
		'boolprop': (gobject.TYPE_BOOLEAN, 'bool prop',
			     'a test boolean prop',
			     0, gobject.PARAM_READABLE),
	    }

	    def my_method(self):
		pass

	self.failUnlessEqual (sys.getrefcount(E), 3)
	self.failUnlessEqual (sys.getrefcount(gobject.GObject), gobject_ref + 3)
	self.failUnlessEqual (sys.getrefcount(E.my_method), 1)

	gobject.type_register (E)
	self.failUnlessEqual (sys.getrefcount(E), 4)
	self.failUnlessEqual (sys.getrefcount(gobject.GObject), gobject_ref + 3)
	self.failUnlessEqual (sys.getrefcount(E.my_method), 1)

    def testConstruction (self):
	self.failUnlessEqual (sys.getrefcount(MyObject), 4)
	i = MyObject()
	self.failUnlessEqual (sys.getrefcount(MyObject), 5)
	self.failUnlessEqual (sys.getrefcount(i), 2)
	self.failUnlessEqual (i.__grefcount__, 1)
	self.failUnless (isinstance (i, MyObject))
	w_i = weakref.ref (i)
	del i
	self.failIf (w_i(), 'Object not freed')

    def testExtraAttributes (self):
	i = MyObject()
	self.failUnlessEqual (sys.getrefcount(i), 2)
	self.failUnlessEqual (i.__grefcount__, 1)
	self.failUnless (isinstance (i, MyObject))
	i.dummy = 'a'
	self.failUnlessEqual (sys.getrefcount(i), 2)
	self.failUnlessEqual (i.__grefcount__, 1)
	x = MyObject()
	self.failUnlessEqual (sys.getrefcount(x), 2)
	i.dummy = x
	self.failUnlessEqual (sys.getrefcount(x), 3)
	w_i = weakref.ref (i)
	del i
	self.failUnlessEqual (sys.getrefcount(x), 2)
	self.failIf (w_i(), 'Object not freed')

    def testNotifyWithClassMethod(self):
	self.failUnlessEqual (sys.getrefcount(MyObject), 4)
	i = MyObject()
	self.failUnlessEqual (sys.getrefcount(MyObject), 5)
	self.failUnlessEqual (sys.getrefcount(MyObject.signal_handler1), 1)
	self.failUnlessEqual (sys.getrefcount(i), 2)
	self.failUnlessEqual (i.__grefcount__, 1)
	# Add an extra reference to MyObject
	i.connect('my_signal', MyObject.signal_handler1)
	self.failUnlessEqual (sys.getrefcount(MyObject), 6)
	self.failUnlessEqual (sys.getrefcount(MyObject.signal_handler1), 1)
	self.failUnlessEqual (sys.getrefcount(i), 2)
	self.failUnlessEqual (i.__grefcount__, 1)
	i.emit('my_signal', 1)
	self.failUnlessEqual (sys.getrefcount(MyObject), 6)
	self.failUnlessEqual (sys.getrefcount(MyObject.signal_handler1), 1)
	self.failUnlessEqual (sys.getrefcount(i), 2)
	self.failUnlessEqual (i.__grefcount__, 1)
	i.emit('my_signal', 1)
	self.failUnlessEqual (sys.getrefcount(MyObject), 6)
	self.failUnlessEqual (sys.getrefcount(MyObject.signal_handler1), 1)
	self.failUnlessEqual (sys.getrefcount(i), 2)
	self.failUnlessEqual (i.__grefcount__, 1)
	w_i = weakref.ref(i)
	del i
	self.failIf (w_i(), 'Object not freed')
	self.failUnlessEqual (sys.getrefcount(MyObject), 4)

    def testNotifyWithObjectInstance(self):
	self.failUnlessEqual (sys.getrefcount(MyObject), 4)
	self.failUnlessEqual (sys.getrefcount(MyObject.signal_handler2), 1)

	i = MyObject()
	self.failUnlessEqual (sys.getrefcount(i), 2)
	self.failUnlessEqual (i.__grefcount__, 1)

	i.emit('my_signal', 2)
	self.failUnlessEqual (sys.getrefcount(MyObject), 5)
	self.failUnlessEqual (sys.getrefcount(MyObject.signal_handler2), 1)
	self.failUnlessEqual (sys.getrefcount(i), 2)
	self.failUnlessEqual (i.__grefcount__, 1)

	handlerid = i.connect('my_signal', i.signal_handler2)
	self.failUnlessEqual (sys.getrefcount(MyObject), 6)
	self.failUnlessEqual (sys.getrefcount(MyObject.signal_handler2), 1)
	self.failUnlessEqual (sys.getrefcount(i), 3)
	self.failUnlessEqual (i.__grefcount__, 1)

	i.emit('my_signal', 2)
	self.failUnlessEqual (sys.getrefcount(MyObject), 6)
	self.failUnlessEqual (sys.getrefcount(MyObject.signal_handler2), 1)
	self.failUnlessEqual (sys.getrefcount(i), 3)
	self.failUnlessEqual (i.__grefcount__, 1)

	i.disconnect(handlerid)
	self.failUnlessEqual (sys.getrefcount(MyObject), 5)
	self.failUnlessEqual (sys.getrefcount(MyObject.signal_handler2), 1)
	self.failUnlessEqual (sys.getrefcount(i), 2)
	self.failUnlessEqual (i.__grefcount__, 1)
	w_i = weakref.ref(i)
	self.failUnlessEqual (sys.getrefcount(i), 2)
	self.failUnlessEqual (i.__grefcount__, 1)
	del i
	#gc.collect()
	self.failUnlessEqual (sys.getrefcount(MyObject), 4)
	self.failIf (w_i(), 'Object not freed')

    def testNotifyWithObjectInstanceGC(self):
	self.failUnlessEqual (sys.getrefcount(MyObject), 4)
	self.failUnlessEqual (sys.getrefcount(MyObject.signal_handler2), 1)

	i = MyObject()
	self.failUnlessEqual (sys.getrefcount(i), 2)
	self.failUnlessEqual (i.__grefcount__, 1)

	i.emit('my_signal', 2)
	self.failUnlessEqual (sys.getrefcount(MyObject), 5)
	self.failUnlessEqual (sys.getrefcount(MyObject.signal_handler2), 1)
	self.failUnlessEqual (sys.getrefcount(i), 2)
	self.failUnlessEqual (i.__grefcount__, 1)

	handlerid = i.connect('my_signal', i.signal_handler2)
	self.failUnlessEqual (sys.getrefcount(MyObject), 6)
	self.failUnlessEqual (sys.getrefcount(MyObject.signal_handler2), 1)
	self.failUnlessEqual (sys.getrefcount(i), 3)
	self.failUnlessEqual (i.__grefcount__, 1)

	i.emit('my_signal', 2)
	self.failUnlessEqual (sys.getrefcount(MyObject), 6)
	self.failUnlessEqual (sys.getrefcount(MyObject.signal_handler2), 1)
	self.failUnlessEqual (sys.getrefcount(i), 3)
	self.failUnlessEqual (i.__grefcount__, 1)

	w_i = weakref.ref(i)
	self.failUnlessEqual (sys.getrefcount(i), 3)
	self.failUnlessEqual (i.__grefcount__, 1)
	del i
	gc.collect()
	self.failUnlessEqual (sys.getrefcount(MyObject), 4) # !!!!
	#self.failUnlessEqual (sys.getrefcount(w_i()), 2) # !!!
	#self.failUnlessEqual (w_i(.__grefcount__), 1) # !!!
	self.failIf (w_i(), 'Object not freed')

if __name__ == '__main__':
    unittest.main()
