1from __future__ import unicode_literals 2from PyObjCTools.TestSupport import * 3 4import objc 5import sys 6from PyObjCTest.instanceVariables import ClassWithVariables 7 8NSObject = objc.lookUpClass('NSObject') 9NSAutoreleasePool = objc.lookUpClass('NSAutoreleasePool') 10 11class Base (object): 12 def __init__(self, ondel): 13 self.ondel = ondel 14 15 def __del__ (self): 16 self.ondel() 17 18class OCBase (NSObject): 19 def init_(self, ondel): 20 self.ondel = ondel 21 22 def __del__ (self): 23 self.ondel() 24 25class TestClass (NSObject): 26 idVar = objc.ivar('idVar') 27 idVar2 = objc.ivar('idVar2', b'@') 28 intVar = objc.ivar('intVar', objc._C_INT) 29 doubleVar = objc.ivar('doubleVar', objc._C_DBL) 30 31 32class TestInstanceVariables(TestCase): 33 def setUp(self): 34 self.object = TestClass.alloc().init() 35 36 def testID(self): 37 # Check that we can set and query attributes of type 'id' 38 self.assertEqual(self.object.idVar, None) 39 self.assertEqual(self.object.idVar2, None) 40 41 o = NSObject.alloc().init() 42 43 self.object.idVar = o 44 self.object.idVar2 = o 45 46 self.assertIs(self.object.idVar, o) 47 self.assertIs(self.object.idVar2, o) 48 49 self.object.idVar = "hello" 50 self.assertEqual(self.object.idVar, "hello") 51 52 def testInt(self): 53 # Check that we can set and query attributes of type 'int' 54 self.assertEqual(self.object.intVar, 0) 55 56 self.assertRaises(ValueError, lambda x: setattr(self.object, 'intVar', x), "h") 57 58 self.object.intVar = 42 59 self.assertEqual(self.object.intVar, 42) 60 61 def testDouble(self): 62 # Check that we can set and query attributes of type 'double' 63 64 # Can't rely on this for doubles... 65 #self.assertEqual(self.object.doubleVar, 0.0) 66 self.assertRaises(ValueError, lambda x: setattr(self.object, 'doubleVar', x), "h") 67 self.object.doubleVar = 42.0 68 self.assertAlmostEqual(self.object.doubleVar, 42.0) 69 70 def testLeak(self): 71 # Check that plain python objects are correctly released when 72 # they are no longer the value of an attribute 73 pool = NSAutoreleasePool.alloc().init() 74 self.deleted = 0 75 self.object.idVar = Base(lambda : setattr(self, 'deleted', 1)) 76 self.object.idVar = None 77 del pool 78 self.assertEqual(self.deleted, 1) 79 80 def testLeak2(self): 81 82 self.deleted = 0 83 84 pool = NSAutoreleasePool.alloc().init() 85 86 self.object.idVar = Base(lambda : setattr(self, 'deleted', 1)) 87 del self.object 88 del pool 89 self.assertEqual(self.deleted, 1) 90 91 def testOCLeak(self): 92 # Check that Objective-C objects are correctly released when 93 # they are no longer the value of an attribute 94 pool = NSAutoreleasePool.alloc().init() 95 self.deleted = 0 96 self.object.idVar = OCBase.alloc().init_(lambda : setattr(self, 'deleted', 1)) 97 self.object.idVar = None 98 del pool 99 self.assertEqual(self.deleted, 1) 100 101 def testOCLeak2(self): 102 pool = NSAutoreleasePool.alloc().init() 103 self.deleted = 0 104 self.object.idVar = OCBase.alloc().init_(lambda : setattr(self, 'deleted', 1)) 105 del self.object 106 del pool 107 self.assertEqual(self.deleted, 1) 108 109 def testDelete(self): 110 self.assertRaises(TypeError, delattr, self.object.idVar) 111 112 113class TestAllInstanceVariables (TestCase): 114 # Some tests for accessing any instance variable, even those not 115 # declared in python. 116 117 def testReading(self): 118 obj = ClassWithVariables.alloc().init() 119 120 getter = objc.getInstanceVariable 121 122 cls = getter(obj, 'isa') 123 self.assertIs(cls, type(obj)) 124 125 self.assertEqual(getter(obj, 'intValue'), 42) 126 self.assertIsInstance(getter(obj, 'intValue'), int) 127 128 self.assertEqual(getter(obj, 'floatValue'), -10.055) 129 self.assertIsInstance(getter(obj, 'floatValue'), float) 130 131 self.assertEqual(getter(obj, 'charValue'), ord('a')) 132 self.assertIsInstance(getter(obj, 'charValue'), int) 133 134 self.assertEqual(getter(obj, 'strValue'), b"hello world") 135 self.assertIsInstance(getter(obj, 'strValue'), bytes) 136 137 self.assertIsInstance(getter(obj, 'objValue'), NSObject) 138 139 self.assertIsNone(getter(obj, 'nilValue')) 140 141 self.assertEqual(getter(obj, 'pyValue'), slice(1, 10, 4)) 142 self.assertIsInstance(getter(obj, 'pyValue'), slice) 143 144 self.assertEqual(getter(obj, 'rectValue'), ((1, 2), (3, 4))) 145 146 self.assertRaises(AttributeError, getter, obj, "noSuchMember") 147 148 def testWriting(self): 149 obj = ClassWithVariables.alloc().init() 150 151 getter = objc.getInstanceVariable 152 setter = objc.setInstanceVariable 153 154 self.assertEqual(getter(obj, 'intValue'), 42) 155 setter(obj, 'intValue', 99) 156 self.assertEqual(getter(obj, 'intValue'), 99) 157 158 self.assertEqual(getter(obj, 'floatValue'), -10.055) 159 setter(obj, 'floatValue', 0.5) 160 self.assertEqual(getter(obj, 'floatValue'), 0.5) 161 162 self.assertEqual(getter(obj, 'charValue'), ord('a')) 163 setter(obj, 'charValue', b'b') 164 self.assertEqual(getter(obj, 'charValue'), ord('b')) 165 setter(obj, 'charValue', 10) 166 self.assertEqual(getter(obj, 'charValue'), 10) 167 168 self.assertEqual(getter(obj, 'strValue'), b"hello world") 169 setter(obj, 'strValue', b"foo bar") 170 self.assertEqual(getter(obj, 'strValue'), b"foo bar") 171 setter(obj, 'strValue', None) 172 self.assertEqual(getter(obj, 'strValue'), None) 173 174 o = NSObject.new() 175 self.assertIsNot(getter(obj, 'objValue'), o) 176 self.assertRaises(TypeError, setter, 'objValue', o) 177 self.assertIsNot(getter(obj, 'objValue'), o) 178 setter(obj, 'objValue', o, True) 179 self.assertIs(getter(obj, 'objValue'), o) 180 181 o2 = NSObject.new() 182 o2.retain() 183 self.assertIsNot(getter(obj, 'objValue'), o2) 184 setter(obj, 'objValue', o2, False) 185 self.assertIs(getter(obj, 'objValue'), o2) 186 187 self.assertEqual(getter(obj, 'pyValue'), slice(1, 10, 4)) 188 setter(obj, 'pyValue', [1,2,3]) 189 self.assertEqual(getter(obj, 'pyValue'), [1,2,3]) 190 191 self.assertEqual(getter(obj, 'rectValue'), ((1, 2), (3, 4))) 192 setter(obj, 'rectValue', ((-4, -8), (2, 7))) 193 self.assertEqual(getter(obj, 'rectValue'), ((-4, -8), (2, 7))) 194 195 self.assertRaises(AttributeError, setter, obj, "noSuchMember", 'foo') 196 197 def testClassMod(self): 198 # It's scary as hell, but updating the class of an object does "work" 199 # (for some perverted interpretation of the word) 200 201 class DummyClass (NSObject): 202 __slots__ = () 203 204 o = NSObject.alloc().init() 205 self.assertIsInstance(o, NSObject) 206 self.assertIsNotInstance(o, DummyClass) 207 208 objc.setInstanceVariable(o, "isa", DummyClass) 209 self.assertIsInstance(o, DummyClass) 210 211 def testDir(self): 212 obj = ClassWithVariables.alloc().init() 213 214 # Note: cannot check the exact contents of dir(), who knows 215 # what NSObject defines... 216 v = objc.listInstanceVariables(obj) 217 self.assertIn(('charValue', objc._C_CHR), v) 218 self.assertIn(('intValue', objc._C_INT), v) 219 self.assertIn(('isa', objc._C_CLASS), v) 220 221 222 def testAnonymousIvar(self): 223 224 class AnonIvarClass (NSObject): 225 226 var = objc.ivar() 227 var2 = objc.ivar(type=objc._C_DBL) 228 229 outlet = objc.IBOutlet() 230 self.assertTrue(outlet.__isOutlet__) 231 self.assertFalse(outlet.__isSlot__) 232 233 o = AnonIvarClass.alloc().init() 234 o.var = NSObject.alloc().init() 235 236 self.assertIsInstance(o.var, NSObject) 237 238 o.var2 = 4 239 self.assertIsInstance(o.var2, float) 240 241 def testNamedOutlet(self): 242 class NamedOutlet (NSObject): 243 outlet1 = objc.IBOutlet() 244 outlet2 = objc.IBOutlet("my_outlet") 245 246 all_outlets = {} 247 248 for name, tp in objc.listInstanceVariables(NamedOutlet): 249 all_outlets[name] = tp 250 251 self.assertEqual(all_outlets['outlet1'], objc._C_ID) 252 self.assertEqual(all_outlets['my_outlet'], objc._C_ID) 253 254 o = NamedOutlet.alloc().init() 255 self.assertTrue(hasattr(o, 'outlet1')) 256 self.assertTrue(hasattr(o, 'outlet2')) 257 258class TestStructConvenience (TestCase): 259 def test_using_convenience(self): 260 for name, typestr in [ 261 ('bool', objc._C_BOOL), 262 ('char', objc._C_CHR), 263 ('int', objc._C_INT), 264 ('short', objc._C_SHT), 265 ('long', objc._C_LNG), 266 ('long_long', objc._C_LNG_LNG), 267 ('unsigned_char', objc._C_UCHR), 268 ('unsigned_int', objc._C_UINT), 269 ('unsigned_short', objc._C_USHT), 270 ('unsigned_long', objc._C_ULNG), 271 ('unsigned_long_long', objc._C_ULNG_LNG), 272 ('float', objc._C_FLT), 273 ('double', objc._C_DBL), 274 ('BOOL', objc._C_NSBOOL), 275 ('UniChar', objc._C_UNICHAR), 276 ('char_text', objc._C_CHAR_AS_TEXT), 277 ('char_int', objc._C_CHAR_AS_INT), 278 ]: 279 self.assertHasAttr(objc.ivar, name) 280 v = getattr(objc.ivar, name)() 281 self.assertIsInstance(v, objc.ivar) 282 self.assertEqual(v.__typestr__, typestr) 283 self.assertEqual(v.__name__, None) 284 self.assertFalse(v.__isOutlet__) 285 self.assertFalse(v.__isSlot__) 286 287 v = getattr(objc.ivar, name)('my_var') 288 self.assertIsInstance(v, objc.ivar) 289 self.assertEqual(v.__typestr__, typestr) 290 self.assertEqual(v.__name__, 'my_var') 291 self.assertFalse(v.__isOutlet__) 292 self.assertFalse(v.__isSlot__) 293 294if __name__ == '__main__': 295 main() 296