1from __future__ import unicode_literals
2from PyObjCTools.TestSupport import *
3from PyObjCTest import structargs
4from PyObjCTest import testbndl
5from PyObjCTest import copying
6
7import objc, sys
8from PyObjCTest.fnd import NSObject, NSAutoreleasePool
9
10rct = structargs.StructArgClass.someRect.__metadata__()['retval']['type']
11
12class OCTestRegrWithGetItem (NSObject):
13    def objectForKey_(self, k):
14        return "ofk: %s"%(k,)
15
16    def __getitem__(self, k):
17        return "gi: %s"%(k,)
18
19class OCTestRegrWithGetItem2 (OCTestRegrWithGetItem):
20    def objectForKey_(self, k):
21        return "ofk2: %s"%(k,)
22
23class ReturnAStruct (NSObject):
24    def someRectWithRect_(self, aRect):
25        ((x, y), (h, w)) = aRect
26        return ((x,y),(h,w))
27    someRectWithRect_ = objc.selector(someRectWithRect_, signature=rct + b'@:' + rct)
28
29
30class TestRegressions(TestCase):
31    def testNSObjectRespondsToCommonMethods(self):
32        self.assertTrue(NSObject.pyobjc_classMethods.respondsToSelector_('alloc'))
33        self.assertTrue(NSObject.instancesRespondToSelector_('init'))
34        self.assertFalse(NSObject.instancesRespondToSelector_('frodel'))
35
36
37    def testDeallocUninit(self):
38        import objc
39
40        import warnings
41        warnings.filterwarnings('ignore',
42            category=objc.UninitializedDeallocWarning)
43
44        try:
45            for clsName in [ 'NSURL', 'NSObject', 'NSArray' ]:
46                d = objc.lookUpClass(clsName).alloc()
47                del d
48
49        finally:
50            del warnings.filters[0]
51
52        # Check that we generate a warning for unitialized objects that
53        # get deallocated
54        import sys
55        if sys.version_info[0] == 2:
56            from StringIO import StringIO
57        else:
58            from io import StringIO
59        warnings.filterwarnings('always',
60            category=objc.UninitializedDeallocWarning)
61        sys.stderr = buf = StringIO()
62        try:
63            d = NSObject.alloc()
64            del d
65
66        finally:
67            del warnings.filters[0]
68            sys.stderr = sys.__stderr__
69
70        # A warning is three lines: location info, source code, empty line
71        self.assertEqual(len(buf.getvalue().split('\n')), 3)
72
73    def testOneWayMethods(self):
74        # This one should be in test_methods*.py
75        from PyObjCTest.initialize import OC_TestInitialize
76
77        o = OC_TestInitialize.alloc().init()
78        self.assertEqual(objc.splitSignature(o.onewayVoidMethod.signature), (objc._C_ONEWAY + objc._C_VOID, objc._C_ID, objc._C_SEL))
79
80        # Make sure we can call the method
81        o.onewayVoidMethod()
82        self.assertEqual(o.isInitialized(), -1)
83
84
85    def testNoneAsSelf (self):
86        class SelfIsNone (NSObject):
87            def f(x):
88                pass
89
90        self.assertRaises(TypeError, NSObject.pyobjc_instanceMethods.description, None)
91        self.assertRaises(TypeError, SelfIsNone.pyobjc_instanceMethods.f, None)
92
93    def testOneArgumentTooMany (self):
94        class ClsIsNone (NSObject):
95            @classmethod
96            def f(cls):
97                pass
98
99        object = NSObject.alloc().init()
100
101        self.assertRaises(TypeError, object.description, None)
102        self.assertRaises(TypeError, object.description, "twelf")
103        self.assertRaises(TypeError, NSObject.description, None)
104        self.assertRaises(TypeError, ClsIsNone.f, None)
105
106
107    def testStructArgs (self):
108        # Like AppKit.test.test_nsimage.TestNSImage.test_compositePoint
109        # unlike that this one doesn't crash on darwin/x86, makeing it less
110        # likely that libffi is at fault
111
112        o = structargs.StructArgClass.alloc().init()
113        v = o.compP_aRect_anOp_((1,2), ((3,4),(5,6)), 7)
114        self.assertEqual(v, "aP:{1, 2} aR:{{3, 4}, {5, 6}} anO:7")
115
116    def testInitialize(self):
117        calls=[]
118        self.assertEqual(len(calls), 0)
119
120        class InitializeTestClass (NSObject):
121            @classmethod
122            def initialize(cls):
123                calls.append(repr(cls))
124
125        o = InitializeTestClass.new()
126        self.assertEqual(len(calls), 1)
127        o = InitializeTestClass.new()
128        self.assertEqual(len(calls), 1)
129
130    def testPrivateIntrospection(self):
131        o = testbndl.PyObjC_TestClass4.alloc().init()
132        self.assertEqual(o._privateMethodWithArg_(1.5), 1)
133        self.assertEqual(o._privateMethodWithArg_(-2.5), -2)
134
135        imp = testbndl.PyObjC_TestClass4.instanceMethodForSelector_('_privateMethodWithArg:')
136        self.assertEqual(imp.signature, b'i@:f')
137
138        sel = testbndl.PyObjC_TestClass4._privateMethodWithArg_
139        self.assertEqual(sel.signature, b'i@:f')
140
141    def testStructReturnPy(self):
142        o = ReturnAStruct.alloc().init()
143        p = structargs.StructArgClass.alloc().init()
144
145        v = p.someRectWithObject_X_Y_H_W_(o, 1, 2, 3, 4)
146        self.assertEqual(v, ((1,2),(3,4)))
147
148    def testStructReturn(self):
149        o = structargs.StructArgClass.alloc().init()
150        v = o.someRect()
151        self.assertEqual(v, ((1,2),(3,4)))
152
153
154
155if sys.byteorder == 'little':
156    # i386 has specific stack alignment requirements.
157
158    class AlignmentTestClass(NSObject):
159        def testWithObject_(self, obj):
160            return obj.stackPtr()
161
162
163    def testStackPtr(self):
164        o = structargs.StructArgClass.alloc().init()
165
166        p = self.AlignmentTestClass.alloc().init()
167        self.assertEqual(p.testWithObject_(o) % 16, o.stackPtr() % 16)
168
169
170
171#
172# Regression in retainCount management when a Python object
173# is created from Objective-C. This only happened when the
174# Python class has an implementation of the designated initializer.
175#
176# Mentioned by Dirk Stoop on the Pyobjc-dev mailing-list.
177#
178
179gDeallocCounter = 0
180class OC_LeakTest_20090704_init (NSObject):
181    def init(self):
182        #self = super(OC_LeakTest_20090704_init, self).init()
183        return self
184
185    def dealloc(self):
186        global gDeallocCounter
187        gDeallocCounter += 1
188
189class OC_LeakTest_20090704_noinit (NSObject):
190    def dealloc(self):
191        global gDeallocCounter
192        gDeallocCounter += 1
193
194
195class TestInitMemoryLeak (TestCase):
196    def testNoPythonInit(self):
197        # This test is basicly a self-test of the test-case, the
198        # test even passed before the regression was fixed.
199
200        global gDeallocCounter
201
202        pool = NSAutoreleasePool.alloc().init()
203        try:
204            v = copying.OC_CopyHelper.newObjectOfClass_(OC_LeakTest_20090704_noinit)
205            self.assertIsInstance(v, OC_LeakTest_20090704_noinit)
206
207            gDeallocCounter = 0
208            del v
209
210        finally:
211            del pool
212
213        self.assertNotEqual(gDeallocCounter, 0)
214
215    def testWithPythonInit(self):
216        global gDeallocCounter
217
218        pool = NSAutoreleasePool.alloc().init()
219        try:
220            v = copying.OC_CopyHelper.newObjectOfClass_(OC_LeakTest_20090704_init)
221            self.assertIsInstance(v, OC_LeakTest_20090704_init)
222
223            gDeallocCounter = 0
224            del v
225
226        finally:
227            del pool
228
229        self.assertNotEqual(gDeallocCounter, 0)
230
231    def testInitFailureLeaks(self):
232        NSData = objc.lookUpClass('NSData')
233        import warnings
234        warnings.filterwarnings('error',
235            category=objc.UninitializedDeallocWarning)
236
237        try:
238            try:
239                v = NSData.alloc().initWithContentsOfFile_("/etc/no-such-file.txt")
240            finally:
241                del warnings.filters[0]
242
243        except objc.UninitializedDeallocWarning:
244            self.fail("Unexpected raising of UninitializedDeallocWarning")
245
246        self.assertFalse(v is not None)
247
248    def testExplicitGetItem(self):
249        v = OCTestRegrWithGetItem.alloc().init()
250
251        self.assertEqual(v.objectForKey_("foo"), "ofk: foo")
252        self.assertEqual(v["foo"], "gi: foo")
253
254        v = OCTestRegrWithGetItem2.alloc().init()
255        self.assertEqual(v.objectForKey_("foo"), "ofk2: foo")
256        self.assertEqual(v["foo"], "gi: foo")
257
258
259if __name__ == '__main__':
260    main()
261