1""" 2XXX: Add tests that check that the type actually works as expected: 3 4* Use struct value as method argument 5* Return struct value from a method 6 7Add tests for nested structs as well (that is assert that NSRect.location is 8an NSPoint, but using our own types) 9""" 10from PyObjCTools.TestSupport import * 11import objc 12from PyObjCTest.structs import * 13from PyObjCTest.fnd import NSObject 14 15 16class TestStructs (TestCase): 17 def testCreateExplicit(self): 18 tp = objc.createStructType("FooStruct", b"{_FooStruct=ffff}", ["a","b","c","d"]) 19 self.assertIsInstance(tp, type) 20 self.assertEqual(tp.__typestr__, b"{_FooStruct=ffff}") 21 22 self.assertEqual(tp._fields, ("a", "b", "c", "d")) 23 24 o = tp() 25 self.assertHasAttr(o, 'a') 26 self.assertHasAttr(o, 'b') 27 self.assertHasAttr(o, 'c') 28 self.assertHasAttr(o, 'd') 29 30 self.assertHasAttr(objc.ivar, 'FooStruct') 31 v = objc.ivar.FooStruct() 32 self.assertIsInstance(v, objc.ivar) 33 self.assertEqual(v.__typestr__, tp.__typestr__) 34 35 36 def testNamedTupleAPI(self): 37 Point = objc.createStructType("OCPoint", b"{_OCPoint=dd}", ["x", "y"]) 38 Line = objc.createStructType("OCLine", b"{_OCLine={_OCPoint=dd}{_OCPoint=dd}}d", ["start", "stop", "width"]) 39 40 self.assertEqual(Point._fields, ("x", "y")) 41 self.assertEqual(Line._fields, ("start", "stop", "width")) 42 43 p = Point(3, 4) 44 self.assertEqual(p.x, 3.0) 45 self.assertEqual(p.y, 4.0) 46 47 self.assertEqual(p._asdict(), {"x": 3.0, "y": 4.0}) 48 49 p2 = p._replace(y=5) 50 self.assertEqual(p.x, 3.0) 51 self.assertEqual(p.y, 4.0) 52 self.assertEqual(p2.x, 3.0) 53 self.assertEqual(p2.y, 5) 54 55 l = Line(Point(1,2), Point(8,9), 7) 56 self.assertEqual(l.start.x, 1.0) 57 self.assertEqual(l.start.y, 2.0) 58 self.assertEqual(l.stop.x, 8.0) 59 self.assertEqual(l.stop.y, 9.0) 60 self.assertEqual(l.width, 7.0) 61 62 self.assertEqual(l._asdict(), 63 {"start": Point(1,2), "stop":Point(8,9), "width": 7.0}) 64 65 l2 = l._replace(stop=Point(3,4), width=0.5) 66 self.assertEqual(l.start.x, 1.0) 67 self.assertEqual(l.start.y, 2.0) 68 self.assertEqual(l.stop.x, 8.0) 69 self.assertEqual(l.stop.y, 9.0) 70 self.assertEqual(l.width, 7.0) 71 72 self.assertEqual(l2.start.x, 1.0) 73 self.assertEqual(l2.start.y, 2.0) 74 self.assertEqual(l2.stop.x, 3.0) 75 self.assertEqual(l2.stop.y, 4.0) 76 self.assertEqual(l2.width, 0.5) 77 78 79 def testCreateImplicit(self): 80 tp = objc.createStructType("BarStruct", b'{_BarStruct="e"f"f"f"g"f"h"f}', None) 81 self.assertIsInstance(tp, type) 82 self.assertEqual(tp.__typestr__, b"{_BarStruct=ffff}") 83 84 o = tp() 85 self.assertHasAttr(o, 'e') 86 self.assertHasAttr(o, 'f') 87 self.assertHasAttr(o, 'g') 88 self.assertHasAttr(o, 'h') 89 90 self.assertEqual(tp._fields, ("e", "f", "g", "h")) 91 92 self.assertRaises(ValueError, objc.createStructType, "Foo2", b'{_Foo=f"a"}', None) 93 self.assertRaises(ValueError, objc.createStructType, "Foo3", b'{_Foo="a"f', None) 94 self.assertRaises(ValueError, objc.createStructType, "Foo4", b'^{_Foo="a"f}', None) 95 96 def testPointerFields(self): 97 # Note: the created type won't be all that useful unless the pointer 98 # happens to be something that PyObjC knows how to deal with, this is 99 # more a check to see if createStructType knows how to cope with 100 # non-trivial types. 101 tp = objc.createStructType("XBarStruct", b'{_XBarStruct="e"^f"f"^f"g"^@"h"f}', None) 102 self.assertIsInstance(tp, type) 103 self.assertEqual(tp.__typestr__, b"{_XBarStruct=^f^f^@f}") 104 105 o = tp() 106 self.assertHasAttr(o, 'e') 107 self.assertHasAttr(o, 'f') 108 self.assertHasAttr(o, 'g') 109 self.assertHasAttr(o, 'h') 110 111 def testEmbeddedFields(self): 112 tp = objc.createStructType("BarStruct", b'{FooStruct="first"i"second"i}', None) 113 114 v = OC_StructTest.createWithFirst_andSecond_(1, 2) 115 self.assertIsInstance(v, tp) 116 117 x = OC_StructTest.sumFields_(v) 118 self.assertEqual(x, v.first + v.second) 119 self.assertEqual(v.first, 1) 120 self.assertEqual(v.second, 2) 121 122 self.assertHasAttr(objc.ivar, 'BarStruct') 123 v = objc.ivar.BarStruct() 124 self.assertEqual(v.__typestr__, b'{FooStruct=ii}') 125 126 def testStructCallback(self): 127 """ 128 Regression test for an issue reported on the PyObjC mailinglist. 129 """ 130 tp = objc.createStructType("FooStruct", b'{FooStruct="first"i"second"i}', None) 131 132 StructArrayDelegate = objc.informal_protocol( 133 "StructArrayDelegate", 134 [ 135 objc.selector(None, b"arrayOf4Structs:", 136 signature=b"@@:[4{FooStruct=ii}]"), 137 ]) 138 139 class OC_PyStruct (NSObject): 140 141 def arrayOf4Structs_(self, value): 142 return value 143 144 self.assertEqual(OC_PyStruct.arrayOf4Structs_.signature, b"@@:[4{FooStruct=" + objc._C_INT + objc._C_INT + b"}]") 145 146 o = OC_PyStruct.alloc().init() 147 v = OC_StructTest.callArrayOf4Structs_(o) 148 self.assertEqual(len(v), 4) 149 for i in range(3): 150 self.assertIsInstance(v[i], tp) 151 152 self.assertEqual(v[0], tp(1, 2)) 153 self.assertEqual(v[1], tp(3, 4)) 154 self.assertEqual(v[2], tp(5, 6)) 155 self.assertEqual(v[3], tp(7, 8)) 156 157 158if __name__ == "__main__": 159 main() 160