1"""
2Tests for the new-style metadata format interface.
3
4Note: Tests for calling from python into ObjC are in test_metadata.py
5
6TODO:
7-> OutputOptional version for TestByReference
8-> Testcode might need changes, C code definitely needs changes
9
10- Add more testcases: python methods that return the wrong value
11- The python->C interface (that is the contents of the metadata object) is
12  likely to change when the bridge is feature-complete.
13- Probably need special-casing for arrays (numarray and array.array)!
14"""
15import objc
16from PyObjCTools.TestSupport import *
17
18from PyObjCTest.metadata import *
19
20# To ensure we have the right metadata
21import PyObjCTest.test_metadata
22from PyObjCTest.test_metadata_py import Py_MetaDataTest_AllArgs
23
24if 0:
25    from PyObjCTest.test_metadata_py2 import Py_MetaDataTest_OutputOptional
26
27class TestArraysOut_AllArgs (TestCase):
28    def testFixedSize(self):
29        o = Py_MetaDataTest_AllArgs.new()
30
31        v = o.fill4Tuple_()
32        self.assertEqual(list(v), list(range(9, 13)))
33
34        v = o.fill4Tuple_(None)
35        self.assertEqual(list(v), list(range(9, 13)))
36
37        self.assertRaises(ValueError, OC_MetaDataTest.fill4Tuple_on_, objc.NULL, o)
38
39        n, v = o.nullfill4Tuple_()
40        self.assertEqual(n, 1)
41        self.assertEqual(list(v), list(range(1, 5)))
42
43        n, v = o.nullfill4Tuple_(None)
44        self.assertEqual(n, 1)
45        self.assertEqual(list(v), list(range(1, 5)))
46
47        n, v = o.nullfill4Tuple_(objc.NULL)
48        self.assertEqual(n, 2)
49        #self.assertIs(v, objc.NULL )
50
51    def testNullTerminated(self):
52        o = Py_MetaDataTest_AllArgs.new()
53
54        # Output only arrays of null-terminated arrays cannot be
55        # wrapped automaticly. How is the bridge supposed to know
56        # how much memory it should allocate for the C-array?
57
58        #self.assertRaises(TypeError, o.fillStringArray_)
59        #self.assertRaises(TypeError, o.fillStringArray_, None)
60        #self.assertRaises(ValueError, o.fillStringArray_, objc.NULL)
61
62        #self.assertRaises(TypeError, o.nullfillStringArray_)
63        #self.assertRaises(TypeError, o.nullfillStringArray_, None)
64        n, v = o.nullfillStringArray_(objc.NULL)
65        self.assertEqual(n, 9)
66        self.assertIs(v, objc.NULL)
67
68    def testWithCount(self):
69        o = Py_MetaDataTest_AllArgs.new()
70
71        v = o.fillArray_count_(3)
72        self.assertEqual(list(v),  [10, 11, 12])
73
74        v = o.fillArray_count_(None, 3)
75        self.assertEqual(list(v),  [10, 11, 12])
76
77        v = o.fillArray_count_(5)
78        self.assertEqual(list(v),  [10, 11, 12, 13, 14])
79
80        v = o.fillArray_count_(0)
81        self.assertEqual(list(v),  [])
82
83        #self.assertRaises(ValueError, o.fillArray_count_, objc.NULL, 0)
84
85        n, v = o.nullfillArray_count_(3)
86        self.assertEqual(n, 2)
87        self.assertEqual(list(v),  [30,31,32])
88        n, v = o.nullfillArray_count_(None, 3)
89        self.assertEqual(n, 2)
90        self.assertEqual(list(v),  [30,31,32])
91
92        n, v = o.nullfillArray_count_(objc.NULL, 3)
93        self.assertEqual(n, 1)
94        #self.assertIs(v, objc.NULL )
95
96    def testWithCountInResult(self):
97        o = Py_MetaDataTest_AllArgs.new()
98
99        c, v = o.fillArray_uptoCount_(20)
100        self.assertEqual(c, 10)
101        self.assertEqual(list(v),  [i+10 for i in range(10)])
102
103        c, v = o.maybeFillArray_()
104        self.assertEqual(c, 2)
105        self.assertEqual(list(v),  [0, 1])
106
107if 0:
108    class TestArraysOut_OutputOptional (TestCase):
109        def testFixedSize(self):
110            o = Py_MetaDataTest_OutputOptional.new()
111
112            v = o.fill4Tuple_()
113            self.assertEqual(list(v), list(range(9, 13)))
114
115            v = o.fill4Tuple_(None)
116            self.assertEqual(list(v), list(range(9, 13)))
117
118            self.assertRaises(ValueError, OC_MetaDataTest.fill4Tuple_on_, objc.NULL, o)
119
120            n, v = o.nullfill4Tuple_()
121            self.assertEqual(n, 1)
122            self.assertEqual(list(v), list(range(1, 5)))
123
124            n, v = o.nullfill4Tuple_(None)
125            self.assertEqual(n, 1)
126            self.assertEqual(list(v), list(range(1, 5)))
127
128            n, v = o.nullfill4Tuple_(objc.NULL)
129            #self.assertEqual(n, 2)
130            #self.assertIs(v, objc.NULL)
131
132        def testNullTerminated(self):
133            o = Py_MetaDataTest_OutputOptional.new()
134
135            # Output only arrays of null-terminated arrays cannot be
136            # wrapped automaticly. How is the bridge supposed to know
137            # how much memory it should allocate for the C-array?
138
139            #self.assertRaises(TypeError, o.fillStringArray_)
140            #self.assertRaises(TypeError, o.fillStringArray_, None)
141            #self.assertRaises(ValueError, o.fillStringArray_, objc.NULL)
142
143            #self.assertRaises(TypeError, o.nullfillStringArray_)
144            #self.assertRaises(TypeError, o.nullfillStringArray_, None)
145            #n, v = o.nullfillStringArray_(objc.NULL)
146            #self.assertEqual(n, 9)
147            #self.assertIs(v, objc.NULL)
148
149        def testWithCount(self):
150            o = Py_MetaDataTest_OutputOptional.new()
151
152            v = o.fillArray_count_(3)
153            self.assertEqual(list(v),  [10, 11, 12])
154
155            v = o.fillArray_count_(None, 3)
156            self.assertEqual(list(v),  [10, 11, 12])
157
158            v = o.fillArray_count_(5)
159            self.assertEqual(list(v),  [10, 11, 12, 13, 14])
160
161            v = o.fillArray_count_(0)
162            self.assertEqual(list(v),  [])
163
164            #self.assertRaises(ValueError, o.fillArray_count_, objc.NULL, 0)
165
166            n, v = o.nullfillArray_count_(3)
167            self.assertEqual(n, 2)
168            self.assertEqual(list(v),  [30,31,32])
169            n, v = o.nullfillArray_count_(None, 3)
170            self.assertEqual(n, 2)
171            self.assertEqual(list(v),  [30,31,32])
172
173            n, v = o.nullfillArray_count_(objc.NULL, 3)
174            #self.assertEqual(n, 1)
175            #self.assertIs(v, objc.NULL)
176
177        def testWithCountInResult(self):
178            o = Py_MetaDataTest_OutputOptional.new()
179
180            c, v = o.fillArray_uptoCount_(20)
181            self.assertEqual(c, 10)
182            self.assertEqual(list(v),  [i+10 for i in range(10)])
183
184            c, v = o.maybeFillArray_()
185            self.assertEqual(c, 2)
186            self.assertEqual(list(v),  [0, 1])
187
188class TestArraysInOut_AllArgs (TestCase):
189    def testFixedSize(self):
190        o = Py_MetaDataTest_AllArgs.new()
191
192        a = (1,2,3,4)
193        v = o.reverse4Tuple_(a)
194        self.assertEqual(a, (1,2,3,4))
195        self.assertEqual(list(v), [43, 44, 45, 46])
196
197        #self.assertRaises(ValueError, o.reverse4Tuple_, (1,2,3))
198        #self.assertRaises(ValueError, o.reverse4Tuple_, (1,2,3,4,5))
199        #self.assertRaises(ValueError, o.reverse4Tuple_, objc.NULL)
200
201        a = (1,2,3,4)
202        n, v = o.nullreverse4Tuple_(a)
203        self.assertEqual(n, 1)
204        self.assertEqual(a, (1,2,3,4))
205        self.assertEqual(list(v), [43, 44, 45, 46])
206
207        n, v = o.nullreverse4Tuple_(objc.NULL)
208        self.assertEqual(n, -1)
209        self.assertIs(v, objc.NULL)
210
211    def testNullTerminated(self):
212        o = Py_MetaDataTest_AllArgs.new()
213
214        a = ('aap', 'boot', 'cello')
215        v = o.reverseStrings_(a)
216        self.assertEqual(a, ('aap', 'boot', 'cello'))
217        self.assertEqual(list(v), ['paa', 'toob', 'ollec'])
218
219        #self.assertRaises(ValueError, o.reverseStrings_, (1,2))
220        #self.assertRaises(ValueError, o.reverseStrings_, objc.NULL)
221
222        a = ('aap', 'boot', 'cello')
223        n, v = o.nullreverseStrings_(a)
224        self.assertEqual(n, 10)
225        self.assertEqual(a, ('aap', 'boot', 'cello'))
226        self.assertEqual(list(v), ['paa', 'toob', 'ollec'])
227
228        n, v = o.nullreverseStrings_(objc.NULL)
229        self.assertEqual(n, 9)
230        self.assertIs(v, objc.NULL)
231
232    def testWithCount(self):
233        o = Py_MetaDataTest_AllArgs.new()
234
235        a = (1.0, 2.0, 3.0, 4.0, 5.0)
236        v = o.reverseArray_count_(a, 4)
237        self.assertEqual(a, (1.0, 2.0, 3.0, 4.0, 5.0))
238
239        # Python->python: same semantics as normal python calls, therefore
240        # the result is 5 long, and there is 2 added to the result (that is
241        # the method sees the actual argument array instead of a truncated one)
242        self.assertEqual(list(v[:4]), [3.0, 4.0, 5.0, 6.0])
243
244        a = (1.0, 2.0, 3.0, 4.0, 5.0)
245        v = o.reverseArray_count_(a, 5)
246        self.assertEqual(a, (1.0, 2.0, 3.0, 4.0, 5.0))
247        self.assertEqual(list(v), [2.0, 3.0, 4.0, 5.0, 6.0])
248
249        # Nice to have, but doesn't work without major
250        # surgery:
251        #a = (1.0, 2.0, 3.0, 4.0, 5.0)
252        #v = o.reverseArray_count_(a, None)
253        #self.assertEqual(a, (1.0, 2.0, 3.0, 4.0, 5.0))
254        #self.assertEqual(v, (2.0, 3.0, 4.0, 5.0, 6.0))
255
256        #self.assertRaises(ValueError, o.reverseArray_count_, (1.0, 2.0), 5)
257        #self.assertRaises(ValueError, o.reverseArray_count_, objc.NULL, 0)
258
259        a = (1.0, 2.0, 3.0, 4.0, 5.0)
260        n, v = o.nullreverseArray_count_(a, 5)
261        self.assertEqual(n, 9)
262        self.assertEqual(a, (1.0, 2.0, 3.0, 4.0, 5.0))
263        self.assertEqual(list(v), [43.0, 44.0, 45.0, 46.0, 47.0])
264
265        n, v = o.nullreverseArray_count_(objc.NULL, 0)
266        self.assertEqual(n, 2)
267        self.assertIs(v, objc.NULL)
268
269    def testWithCountInResult(self):
270        o = Py_MetaDataTest_AllArgs.new()
271
272        # XXX: caling python->python has the usual python semantics, hence
273        # the argument won't be truncated!
274        c, v = o.reverseArray_uptoCount_(range(10), 10)
275        self.assertEqual(c, 5)
276        self.assertEqual(len(v), 10)
277        self.assertEqual(list(v)[:int(c)],  [0, 10, 20, 30, 40])
278
279        c, v = o.maybeReverseArray_([1,2,3,4])
280        self.assertEqual(c, 2)
281        self.assertEqual(len(v), 2)
282        self.assertEqual(list(v),  [45, 51])
283
284class TestArraysIn_AllArgs (TestCase):
285    def testFixedSize(self):
286        o = Py_MetaDataTest_AllArgs.new()
287
288        v,  = o.make4Tuple_((1.0, 4.0, 8.0, 12.5))
289        self.assertEqual(len(v), 4)
290        self.assertEqual(list(v), [1.0, 4.0, 8.0, 12.5])
291
292        v, = o.make4Tuple_((1, 2, 3, 4))
293        self.assertEqual(len(v), 4)
294        self.assertEqual(list(v), [1.0, 2.0, 3.0, 4.0])
295
296        # XXX: Calling python->python has a the same semantics as a normal
297        # python call.
298        #self.assertRaises(ValueError, o.make4Tuple_, (1, 2, 3))
299        #self.assertRaises(ValueError, o.make4Tuple_, (1, 2, 3, 4, 5))
300        #self.assertRaises(ValueError, o.make4Tuple_, objc.NULL)
301
302        v, = o.null4Tuple_(objc.NULL)
303        self.assertIs(v, objc.NULL)
304
305    def testNullTerminated(self):
306        o = Py_MetaDataTest_AllArgs.new()
307
308        v, = OC_MetaDataTest.makeStringArray_on_((b"hello", b"world", b"there"), o)
309        self.assertEqual(len(v), 3)
310        self.assertEqual(list(v), ["hello", "world", "there"])
311
312        NSObject = objc.lookUpClass('NSObject')
313        p, q = NSObject.new(), NSObject.new()
314        v, = o.makeObjectArray_((p, q))
315        self.assertEqual(len(v), 2)
316        self.assertIs(v[0], p)
317        self.assertIs(v[1], q)
318
319        v, = OC_MetaDataTest.makeStringArray_on_((), o)
320        self.assertEqual(len(v), 0)
321
322        self.assertRaises(ValueError, OC_MetaDataTest.makeStringArray_on_, [1,2], o)
323        self.assertRaises(ValueError, OC_MetaDataTest.makeStringArray_on_, objc.NULL, o)
324
325        v, = OC_MetaDataTest.nullStringArray_on_(objc.NULL, o)
326        self.assertEqual(v, objc.NULL)
327
328    def testWithCount(self):
329        o = Py_MetaDataTest_AllArgs.new()
330
331        v, c = o.makeIntArray_count_((1,2,3,4), 3)
332        self.assertEqual(c, 3)
333
334        # Calling python -> python doesn't pass through C, hence the usual
335        # python semantics are used which are slightly different from calling
336        # into C or from C.
337        self.assertEqual(len(v), 4)
338        self.assertEqual(list(v)[:c], [1,2,3])
339
340        # XXX: This one would be nice to have, but not entirely trivial
341        #v, c = o.makeIntArray_count_((1,2,3,4), None)
342        #self.assertEqual(c, 3)
343        #self.assertEqual(len(v), 3)
344        #self.assertEqual(list(v), [1,2,3,4])
345
346        # See above
347        #self.assertRaises(ValueError, o.makeIntArray_count_, [1,2,3], 4)
348        #self.assertRaises(ValueError, o.makeIntArray_count_, objc.NULL, 0)
349        #self.assertRaises(ValueError, o.makeIntArray_count_, objc.NULL, 1)
350
351        v, c = o.nullIntArray_count_(objc.NULL, 0)
352        self.assertEqual(c, 0)
353        self.assertEqual(v, objc.NULL)
354
355        # See above
356        #self.assertRaises(ValueError, o.makeIntArray_count_, objc.NULL, 1)
357
358        # Make sure this also works when the length is in a pass-by-reference argument
359        v, c = o.makeIntArray_countPtr_((1,2,3,4), 4)
360        self.assertEqual(c, 4)
361        self.assertEqual(len(v), 4)
362        self.assertEqual(list(v), [1,2,3,4])
363
364class TestArrayReturns_AllArgs (TestCase):
365    # TODO:
366    # - Add null-terminated arrays of various supported types:
367    #   -> integers
368    #   -> CF-types
369    def testFixedSize(self):
370        o = Py_MetaDataTest_AllArgs.new()
371
372        v = o.makeIntArrayOf5()
373        self.assertEqual( len(v), 5 )
374        self.assertEqual( list(v), [100, 200, 300, 400, 500] )
375
376        v = o.nullIntArrayOf5()
377        self.assertEqual(v, objc.NULL)
378
379    def testSizeInArgument(self):
380        o = Py_MetaDataTest_AllArgs.new()
381        v = o.makeIntArrayOf_(3)
382        self.assertEqual(len(v), 3)
383        self.assertEqual(list(v), [20, 21, 22])
384
385        v = o.makeIntArrayOf_(10)
386        self.assertEqual(len(v), 10)
387        self.assertEqual(list(v), list(range(20, 30)))
388
389        v = o.nullIntArrayOf_(100)
390        self.assertEqual(v, objc.NULL)
391
392    def testNULLterminated(self):
393        o  = Py_MetaDataTest_AllArgs.new()
394
395        v = o.makeStringArray()
396        self.assertEqual(len(v), 3)
397        self.assertEqual(list(v), [ b"jaap", b"pieter", b"hans" ])
398
399        v = o.nullStringArray()
400        self.assertEqual(v, objc.NULL)
401
402class TestByReference_AllArgs (TestCase):
403    # Pass by reference arguments.
404    # Note that these tests aren't exhaustive, we have test_methods and
405    # test_methods2 for that :-)
406
407    def testInput(self):
408        o = Py_MetaDataTest_AllArgs.new()
409
410        r = o.sumX_andY_(1, 2)
411        self.assertEqual(r, 1**2+2**2)
412
413        r = o.sumX_andY_(2535, 5325)
414        self.assertEqual(r, 2535**2 + 5325**2)
415
416        #self.assertRaises(ValueError, o.sumX_andY_, 42, objc.NULL)
417
418    def testOutput(self):
419        o = Py_MetaDataTest_AllArgs.new()
420
421        div, rem = o.divBy5_remainder_(55)
422        self.assertEqual(div, 55 / 7)
423        self.assertEqual(rem, 55 % 7)
424
425        div, rem = o.divBy5_remainder_(13)
426        self.assertEqual(div, 13 / 7)
427        self.assertEqual(rem, 13 % 7)
428
429        # XXX: To be fixed:
430        #self.assertRaises(ValueError, o.divBy5_remainder_, 42, objc.NULL)
431
432    def testInputOutput(self):
433        o = Py_MetaDataTest_AllArgs.new()
434        x, y = o.swapX_andY_(42, 284)
435        self.assertEqual(x, 284*2)
436        self.assertEqual(y, 42*2)
437
438        #self.assertRaises(ValueError, o.swapX_andY_, 42, objc.NULL)
439
440    def testNullAccepted(self):
441        # Note: the commented-out test-cases require a change in the pyobjc-core
442        o = Py_MetaDataTest_AllArgs.new();
443
444        def makeNum(value):
445            return int(value, 0)
446
447        # All arguments present
448        r, y, z = o.input_output_inputAndOutput_(1, 2)
449        self.assertEqual(len(r), 3)
450        self.assertEqual(len(list(filter(lambda x: x is not objc.NULL, r))), 3)
451        self.assertEqual(y, 9)
452        self.assertEqual(z, 10)
453
454        r, y, z = o.input_output_inputAndOutput_(1, None, 2)
455        self.assertEqual(len(r), 3)
456        self.assertEqual(len(list(filter(lambda x: x is not objc.NULL, r))), 3)
457        self.assertEqual(y, 9)
458        self.assertEqual(z, 10)
459
460        # Argument 1 is NULL
461        r, y, z = o.input_output_inputAndOutput_(objc.NULL, 2)
462        self.assertEqual(len(r), 3)
463        self.assertEqual(len(list(filter(lambda x: x is not objc.NULL, r))), 2)
464        self.assertEqual(y, 11)
465        self.assertEqual(z, 12)
466
467        r, y, z = o.input_output_inputAndOutput_(objc.NULL, None, 2)
468        self.assertEqual(len(r), 3)
469        self.assertEqual(len(list(filter(lambda x: x is not objc.NULL, r))), 2)
470        self.assertEqual(y, 11)
471        self.assertEqual(z, 12)
472
473        # Argument 2 is NULL
474        r, y, z = o.input_output_inputAndOutput_(1, objc.NULL, 2)
475        self.assertEqual(len(r), 3)
476        self.assertEqual(len(list(filter(lambda x: x is not objc.NULL, r))), 2)
477        self.assertEqual(y, 13) # objc.NULL ...
478        self.assertEqual(z, 14)
479
480        # Argument 3 is NULL
481        r, y, z = o.input_output_inputAndOutput_(1, objc.NULL)
482        self.assertEqual(len(r), 3)
483        self.assertEqual(len(list(filter(lambda x: x is not objc.NULL, r))), 2)
484        self.assertEqual(y, 15)
485        self.assertEqual(z, 16) # objc.NULL ...
486
487        r, y, z = o.input_output_inputAndOutput_(1, None, objc.NULL)
488        self.assertEqual(len(r), 3)
489        self.assertEqual(len(list(filter(lambda x: x is not objc.NULL, r))), 2)
490        self.assertEqual(y, 15)
491        self.assertEqual(z, 16) # , objc.NULL)
492
493if __name__ == "__main__":
494    main()
495