1from PyObjCTools.TestSupport import *
2
3import objc
4import sys
5from PyObjCTest.instanceVariables import ClassWithVariables
6
7NSObject = objc.lookUpClass('NSObject')
8NSAutoreleasePool = objc.lookUpClass('NSAutoreleasePool')
9
10class Base (object):
11    def __init__(self, ondel):
12        self.ondel = ondel
13
14    def __del__ (self):
15        self.ondel()
16
17class OCBase (NSObject):
18    def init_(self, ondel):
19        self.ondel = ondel
20
21    def __del__ (self):
22        self.ondel()
23
24class TestClass (NSObject):
25    idVar = objc.ivar('idVar')
26    idVar2 = objc.ivar('idVar2', b'@')
27    intVar = objc.ivar('intVar', objc._C_INT)
28    doubleVar = objc.ivar('doubleVar', objc._C_DBL)
29
30
31class TestInstanceVariables(TestCase):
32    def setUp(self):
33        self.object = TestClass.alloc().init()
34
35    def testID(self):
36        # Check that we can set and query attributes of type 'id'
37        self.assertEquals(self.object.idVar, None)
38        self.assertEquals(self.object.idVar2, None)
39
40        o = NSObject.alloc().init()
41
42        self.object.idVar = o
43        self.object.idVar2 = o
44
45        self.assertIs(self.object.idVar, o)
46        self.assertIs(self.object.idVar2, o)
47
48        self.object.idVar = u"hello"
49        self.assertEquals(self.object.idVar, u"hello")
50
51    def testInt(self):
52        # Check that we can set and query attributes of type 'int'
53        self.assertEquals(self.object.intVar, 0)
54
55        self.assertRaises(ValueError, lambda x: setattr(self.object, 'intVar', x), "h")
56
57        self.object.intVar = 42
58        self.assertEquals(self.object.intVar, 42)
59
60    def testDouble(self):
61        # Check that we can set and query attributes of type 'double'
62
63        # Can't rely on this for doubles...
64        #self.assertEquals(self.object.doubleVar, 0.0)
65        self.assertRaises(ValueError, lambda x: setattr(self.object, 'doubleVar', x), u"h")
66        self.object.doubleVar = 42.0
67        self.assertAlmostEquals(self.object.doubleVar, 42.0)
68
69    def testLeak(self):
70        # Check that plain python objects are correctly released when
71        # they are no longer the value of an attribute
72        pool = NSAutoreleasePool.alloc().init()
73        self.deleted = 0
74        self.object.idVar = Base(lambda : setattr(self, 'deleted', 1))
75        self.object.idVar = None
76        del pool
77        self.assertEquals(self.deleted, 1)
78
79    def testLeak2(self):
80
81        self.deleted = 0
82
83        pool = NSAutoreleasePool.alloc().init()
84
85        self.object.idVar = Base(lambda : setattr(self, 'deleted', 1))
86        del self.object
87        del pool
88        self.assertEquals(self.deleted, 1)
89
90    def testOCLeak(self):
91        # Check that Objective-C objects are correctly released when
92        # they are no longer the value of an attribute
93        pool = NSAutoreleasePool.alloc().init()
94        self.deleted = 0
95        self.object.idVar = OCBase.alloc().init_(lambda : setattr(self, 'deleted', 1))
96        self.object.idVar = None
97        del pool
98        self.assertEquals(self.deleted, 1)
99
100    def testOCLeak2(self):
101        pool = NSAutoreleasePool.alloc().init()
102        self.deleted = 0
103        self.object.idVar = OCBase.alloc().init_(lambda : setattr(self, 'deleted', 1))
104        del self.object
105        del pool
106        self.assertEquals(self.deleted, 1)
107
108    def testDelete(self):
109        self.assertRaises(TypeError, delattr, self.object.idVar)
110
111
112class TestAllInstanceVariables (TestCase):
113    # Some tests for accessing any instance variable, even those not
114    # declared in python.
115
116    def testReading(self):
117        obj = ClassWithVariables.alloc().init()
118
119        getter = objc.getInstanceVariable
120
121        cls = getter(obj, 'isa')
122        self.assertIs(cls, type(obj))
123
124        self.assertEquals(getter(obj, 'intValue'), 42)
125        self.assertIsInstance(getter(obj, 'intValue'), int)
126
127        self.assertEquals(getter(obj, 'floatValue'), -10.055)
128        self.assertIsInstance(getter(obj, 'floatValue'), float)
129
130        self.assertEquals(getter(obj, 'charValue'), ord('a'))
131        self.assertIsInstance(getter(obj, 'charValue'), int)
132
133        self.assertEquals(getter(obj, 'strValue'), b"hello world")
134        self.assertIsInstance(getter(obj, 'strValue'), bytes)
135
136        self.assertIsInstance(getter(obj, 'objValue'), NSObject)
137
138        self.assertIsNone(getter(obj, 'nilValue'))
139
140        self.assertEquals(getter(obj, 'pyValue'), slice(1, 10, 4))
141        self.assertIsInstance(getter(obj, 'pyValue'), slice)
142
143        self.assertEquals(getter(obj, 'rectValue'), ((1, 2), (3, 4)))
144
145        self.assertRaises(AttributeError, getter, obj, "noSuchMember")
146
147    def testWriting(self):
148        obj = ClassWithVariables.alloc().init()
149
150        getter = objc.getInstanceVariable
151        setter = objc.setInstanceVariable
152
153        self.assertEquals(getter(obj, 'intValue'), 42)
154        setter(obj, 'intValue', 99)
155        self.assertEquals(getter(obj, 'intValue'), 99)
156
157        self.assertEquals(getter(obj, 'floatValue'), -10.055)
158        setter(obj, 'floatValue', 0.5)
159        self.assertEquals(getter(obj, 'floatValue'), 0.5)
160
161        self.assertEquals(getter(obj, 'charValue'), ord('a'))
162        setter(obj, 'charValue', b'b')
163        self.assertEquals(getter(obj, 'charValue'), ord('b'))
164        setter(obj, 'charValue', 10)
165        self.assertEquals(getter(obj, 'charValue'), 10)
166
167        self.assertEquals(getter(obj, 'strValue'), b"hello world")
168        setter(obj, 'strValue', b"foo bar")
169        self.assertEquals(getter(obj, 'strValue'), b"foo bar")
170        setter(obj, 'strValue', None)
171        self.assertEquals(getter(obj, 'strValue'), None)
172
173        o = NSObject.new()
174        self.assertIsNot(getter(obj, 'objValue'), o)
175        self.assertRaises(TypeError, setter, 'objValue', o)
176        self.assertIsNot(getter(obj, 'objValue'), o)
177        setter(obj, 'objValue', o, True)
178        self.assertIs(getter(obj, 'objValue'), o)
179
180        o2 = NSObject.new()
181        o2.retain()
182        self.assertIsNot(getter(obj, 'objValue'), o2)
183        setter(obj, 'objValue', o2, False)
184        self.assertIs(getter(obj, 'objValue'), o2)
185
186        self.assertEquals(getter(obj, 'pyValue'), slice(1, 10, 4))
187        setter(obj, 'pyValue', [1,2,3])
188        self.assertEquals(getter(obj, 'pyValue'), [1,2,3])
189
190        self.assertEquals(getter(obj, 'rectValue'), ((1, 2), (3, 4)))
191        setter(obj, 'rectValue', ((-4, -8), (2, 7)))
192        self.assertEquals(getter(obj, 'rectValue'), ((-4, -8), (2, 7)))
193
194        self.assertRaises(AttributeError, setter, obj, "noSuchMember", 'foo')
195
196    def testClassMod(self):
197        # It's scary as hell, but updating the class of an object does "work"
198        # (for some perverted interpretation of the word)
199
200        class DummyClass (NSObject):
201            __slots__ = ()
202
203        o = NSObject.alloc().init()
204        self.assertIsInstance(o, NSObject)
205        self.assertIsNotInstance(o, DummyClass)
206
207        objc.setInstanceVariable(o, "isa", DummyClass)
208        self.assertIsInstance(o, DummyClass)
209
210    def testDir(self):
211        obj = ClassWithVariables.alloc().init()
212
213        # Note: cannot check the exact contents of dir(), who knows
214        # what NSObject defines...
215        v = objc.listInstanceVariables(obj)
216        self.assertIn(('charValue', objc._C_CHR), v)
217        self.assertIn(('intValue', objc._C_INT), v)
218        self.assertIn(('isa', objc._C_CLASS), v)
219
220
221    def testAnonymousIvar(self):
222
223        class AnonIvarClass (NSObject):
224
225            var = objc.ivar()
226            var2 = objc.ivar(type=objc._C_DBL)
227
228            outlet = objc.IBOutlet()
229
230        o = AnonIvarClass.alloc().init()
231        o.var = NSObject.alloc().init()
232
233        self.assertIsInstance(o.var, NSObject)
234
235        o.var2 = 4
236        self.assertIsInstance(o.var2, float)
237
238
239if __name__ == '__main__':
240    main()
241