from ctypes import *
import unittest

class SimpleTestCase(unittest.TestCase):
    def test_cint(self):
        x = c_int()
        # a simple object has an empty _objects dict, if uninitialized
        self.assertEquals(x._objects, None)
        # setting the value populates the dict
        x.value = 42
        self.assertEquals(x._objects, None)

        x = c_int(99)
        self.assertEquals(x._objects, None)

    def test_ccharp(self):
        x = c_char_p()
        # a simple object has an empty _objects dict, if uninitialized
        self.assertEquals(x._objects, None)
        # setting the value populates the dict
        x.value = "abc"
        self.assertEquals(x._objects, "abc")

        x = c_char_p("spam")
        self.assertEquals(x._objects, "spam")

class StructureTestCase(unittest.TestCase):
    def test_cint_struct(self):
        class X(Structure):
            _fields_ = [("a", c_int),
                        ("b", c_int)]

        x = X()
        self.assertEquals(x._objects, None)

        x.a = 42
        x.b = 99
        self.assertEquals(x._objects, {"1": None, "2": None})

    def test_ccharp_struct(self):
        class X(Structure):
            _fields_ = [("a", c_char_p),
                        ("b", c_char_p)]
        x = X()
        self.assertEquals(x._objects, None)

        x.a = "spam"
        x.b = "foo"
        self.assertEquals(x._objects, {"1": "spam", "2": "foo"})

    def test_struct_struct(self):
        class POINT(Structure):
            _fields_ = [("x", c_int), ("y", c_int)]
        class RECT(Structure):
            _fields_ = [("ul", POINT), ("lr", POINT)]

        r = RECT()
        r.ul.x = 0
        r.ul.y = 1
        r.lr.x = 2
        r.lr.y = 3
        self.assertEquals(r._objects,
                          {'11': None, '12': None, '21': None, '22': None})

        r = RECT()
        r.ul = POINT(1, 2)
        self.assertEquals(r._objects, {'1': {'1': None, '2': None}})
        r.ul.x = 22
        r.ul.y = 44
        # The current solution retains unneeded objects as well:
        self.assertEquals(r._objects,
                          {'1': {'1': None, '2': None}, # r.ul = POINT(1, 2)
                           '11': None,  # r.ul.x = 22
                           '21': None}) # r.ul.x = 44
        # The entry marked '<-' above is no longer needed, it refers to the
        # POINT we have assigned, but the coords are already overwritten.
        # But, oh well...

class ArrayTestCase(unittest.TestCase):
    def test_cint_array(self):
        INTARR = c_int * 3

        ia = INTARR()
        self.assertEquals(ia._objects, None)
        ia[0] = 1
        ia[1] = 2
        ia[2] = 3
        self.assertEquals(ia._objects, {"1": None, "2": None, "3": None})

        class X(Structure):
            _fields_ = [("x", c_int),
                        ("a", INTARR)]

        x = X()
        x.x = 1000
        x.a[0] = 42
        x.a[1] = 96
        self.assertEquals(x._objects, {"1": None, "12": None, "22": None})

        x.a = ia
        self.assertEquals(x._objects,
                          {'1': None,
                           '2': {'1': None, '2': None, '3': None},
                           '12': None,
                           '22': None})
        # See above, some entries unneeded.

class PointerTestCase(unittest.TestCase):
    def X_test_p_cint(self):
        x = pointer(c_int(42))
        print x._objects

class DeletePointerTestCase(unittest.TestCase):
    def X_test(self):
        class X(Structure):
            _fields_ = [("p", POINTER(c_char_p))]
        x = X()
        i = c_char_p("abc def")
        from sys import getrefcount as grc
        print "2?", grc(i)
        x.p = pointer(i)
        print "3?", grc(i)
        for i in range(320):
            c_int(99)
            x.p[0]
        print x.p[0]
##        del x
##        print "2?", grc(i)
##        del i
        import gc
        gc.collect()
        for i in range(320):
            c_int(99)
            x.p[0]
        print x.p[0]
        print x.p.contents
##        print x._objects

        x.p[0] = "spam spam"
##        print x.p[0]
        print "+" * 42
        print x._objects

##class PointerToStructure(unittest.TestCase):
##    def test(self):
##        class POINT(Structure):
##            _fields_ = [("x", c_int), ("y", c_int)]
##        class RECT(Structure):
##            _fields_ = [("a", POINTER(POINT)),
##                        ("b", POINTER(POINT))]
##        r = RECT()
##        p1 = POINT(1, 2)
##        p2 = POINT(3, 4)
    
##        r.a = pointer(p1)
##        r.a[0].x = 42
##        r.a[0].y = 99

##        r.b = pointer(p2)

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