1"""
2Tests for the new-style metadata format interface.
3
4These tests are for global function
5"""
6import objc
7from PyObjCTools.TestSupport import *
8import warnings
9
10from PyObjCTest.metadatafunction import *
11
12_FunctionTable = [
13    ("makeArrayWithFormat_", '@@', '',
14            dict(
15                variadic=True,
16                arguments={
17                    0: dict(printf_format=True),
18                }
19            )),
20
21    ("makeArrayWithCFormat_", '@*', '',
22            dict(
23                variadic=True,
24                arguments={
25                    0: dict(printf_format=True),
26                }
27            )),
28
29    ("make4Tuple_", '@^d', '',
30            dict(
31                arguments={
32                  0:  dict(type_modifier=objc._C_IN, c_array_of_fixed_length=4, null_accepted=False),
33                }
34            )),
35
36    ("null4Tuple_", '@^d', '',
37            dict(
38                arguments={
39                  0:  dict(type_modifier=objc._C_IN, c_array_of_fixed_length=4, null_accepted=True),
40                }
41            )),
42
43    ("makeObjectArray_", '@^@', '',
44            dict(
45                arguments={
46                  0:  dict(type_modifier=objc._C_IN, c_array_delimited_by_null=True, null_accepted=False),
47                }
48            )),
49
50    ("makeStringArray_", '@^*', '',
51            dict(
52                arguments={
53                  0:  dict(type_modifier=objc._C_IN, c_array_delimited_by_null=True, null_accepted=False),
54                }
55            )),
56
57    ("nullStringArray_", '@^*', '',
58            dict(
59                arguments={
60                  0:  dict(type_modifier=objc._C_IN, c_array_delimited_by_null=True, null_accepted=True),
61                }
62            )),
63
64    ("makeIntArray_count_", '@^iI', '',
65            dict(
66                arguments={
67                  0:  dict(type_modifier=objc._C_IN, c_array_length_in_arg=1, null_accepted=False),
68                }
69            )),
70
71    ("makeIntArray_countPtr_", '@^i^I', '',
72            dict(
73                arguments={
74                  0:  dict(type_modifier=objc._C_IN, c_array_length_in_arg=1, null_accepted=False),
75                  1:  dict(type_modifier=objc._C_IN),
76                }
77            )),
78
79    ("nullIntArray_count_", '@^iI', '',
80            dict(
81                arguments={
82                  0:  dict(type_modifier=objc._C_IN, c_array_length_in_arg=1, null_accepted=True),
83                }
84            )),
85
86    ("fillArray_uptoCount_", 'i^ii', '',
87            dict(
88                arguments={
89                    0: dict(type_modifier=objc._C_OUT, c_array_length_in_arg=1, c_array_length_in_result=True, null_accepted=False),
90                }
91            )),
92
93    ("fillArray_count_", 'v^ii', '',
94            dict(
95                arguments={
96                    0: dict(type_modifier=objc._C_OUT, c_array_length_in_arg=1, null_accepted=False),
97                }
98            )),
99
100    ("nullfillArray_count_", 'i^ii', '',
101            dict(
102                arguments={
103                    0: dict(type_modifier=objc._C_OUT, c_array_length_in_arg=1, null_accepted=True),
104                }
105            )),
106
107    ("maybeFillArray_", 'i^i', '',
108            dict(
109                arguments={
110                    0: dict(type_modifier=objc._C_OUT, c_array_of_fixed_length=4, c_array_length_in_result=True, null_accepted=False),
111                }
112            )),
113
114    ("fill4Tuple_", 'v^i', '',
115            dict(
116                arguments={
117                    0: dict(type_modifier=objc._C_OUT, c_array_of_fixed_length=4, null_accepted=False),
118                }
119            )),
120
121    ("nullfill4Tuple_", 'i^i', '',
122            dict(
123                arguments={
124                    0: dict(type_modifier=objc._C_OUT, c_array_of_fixed_length=4, null_accepted=True),
125                }
126            )),
127
128    ("fillStringArray_", 'i^*', '',
129            dict(
130                arguments={
131                    0: dict(type_modifier=objc._C_OUT, c_array_delimited_by_null=True, null_accepted=False),
132                }
133            )),
134
135    ("nullfillStringArray_", 'i^*', '',
136            dict(
137                arguments={
138                    0: dict(type_modifier=objc._C_OUT, c_array_delimited_by_null=True, null_accepted=True),
139                }
140            )),
141
142    ("reverseArray_uptoCount_", 'i^fi', '',
143            dict(
144                arguments={
145                    0: dict(type_modifier=objc._C_INOUT, c_array_length_in_arg=1, c_array_length_in_result=True, null_accepted=False),
146                }
147            )),
148
149    ("reverseArray_count_", 'v^fi', '',
150            dict(
151                arguments={
152                    0: dict(type_modifier=objc._C_INOUT, c_array_length_in_arg=1, null_accepted=False),
153                }
154            )),
155
156    ("nullreverseArray_count_", 'i^fi', '',
157            dict(
158                arguments={
159                    0: dict(type_modifier=objc._C_INOUT, c_array_length_in_arg=1, null_accepted=True),
160                }
161            )),
162
163    ("reverseStrings_", 'v^*', '',
164            dict(
165                arguments={
166                    0: dict(type_modifier=objc._C_INOUT, c_array_delimited_by_null=True, null_accepted=False),
167                }
168            )),
169
170    ("nullreverseStrings_", 'i^*', '',
171            dict(
172                arguments={
173                    0: dict(type_modifier=objc._C_INOUT, c_array_delimited_by_null=True, null_accepted=True),
174                }
175            )),
176
177    ("maybeReverseArray_", 'i^s', '',
178            dict(
179                arguments={
180                    0: dict(type_modifier=objc._C_INOUT, c_array_of_fixed_length=4, c_array_length_in_result=True, null_accepted=False),
181                }
182            )),
183
184    ("reverse4Tuple_", 'v^s', '',
185            dict(
186                arguments={
187                    0: dict(type_modifier=objc._C_INOUT, c_array_of_fixed_length=4, null_accepted=False),
188                }
189            )),
190
191    ("nullreverse4Tuple_", 'i^s', '',
192            dict(
193                arguments={
194                    0: dict(type_modifier=objc._C_INOUT, c_array_of_fixed_length=4, null_accepted=True),
195                }
196            )),
197
198    ("makeIntArrayOf5", '^i', '',
199            dict(
200                retval=dict(c_array_of_fixed_length=5)
201            )),
202
203    ("makeStringArray", '^*', '',
204            dict(
205                retval=dict(c_array_delimited_by_null=True),
206            )),
207
208    ("makeIntArrayOf_", '^ii', '',
209            dict(
210                retval=dict(c_array_length_in_arg=0)
211            )),
212
213    ("nullIntArrayOf5", '^i', '',
214            dict(
215                retval=dict(c_array_of_fixed_length=5)
216            )),
217
218    ("nullStringArray", '^*', '',
219            dict(
220                retval=dict(c_array_delimited_by_null=True),
221            )),
222
223    ("nullIntArrayOf_", '^ii',  '',
224            dict(
225                retval=dict(c_array_length_in_arg=0)
226            )),
227
228
229    ("sumX_andY_",  'i^i^i', '',
230            dict(arguments={
231                    0: dict(type_modifier=objc._C_IN, null_accepted=False),
232                    1: dict(type_modifier=objc._C_IN, null_accepted=False),
233                })),
234
235    ("divBy5_remainder_",  'ii^i', '',
236            dict(arguments={
237                    1: dict(type_modifier=objc._C_OUT, null_accepted=False),
238                })),
239
240    ("swapX_andY_", 'v^d^d', '',
241            dict(arguments={
242                    0: dict(type_modifier=objc._C_INOUT, null_accepted=False),
243                    1: dict(type_modifier=objc._C_INOUT, null_accepted=False),
244                })),
245
246    ("input_output_inputAndOutput_", '@^i^i^i', '',
247            dict(arguments={
248                    0: dict(type_modifier=objc._C_IN, null_accepted=True),
249                    1: dict(type_modifier=objc._C_OUT, null_accepted=True),
250                    2: dict(type_modifier=objc._C_INOUT, null_accepted=True),
251            })),
252]
253
254objc._loadFunctionList(function_list, globals(),  _FunctionTable, False)
255
256class TestExists (TestCase):
257    def testFunctionsExists(self):
258        for item in _FunctionTable:
259            self.assert_( item[0] in globals() )
260
261class TestArrayDefault (TestCase):
262    # TODO: what is the default anyway?
263    pass
264
265class TestArraysOut (TestCase):
266    def testFixedSize(self):
267        v = fill4Tuple_(None)
268        self.assertEquals(list(v), [0, -1, -8, -27])
269
270        self.assertRaises(ValueError, fill4Tuple_, objc.NULL)
271
272        n, v = nullfill4Tuple_(None)
273        self.assertEquals(n, 1)
274        self.assertEquals(list(v), [0, -1, -8, -27])
275
276        n, v = nullfill4Tuple_(objc.NULL)
277        self.assertEquals(n, 0)
278        self.assert_( v is objc.NULL )
279
280    def testNullTerminated(self):
281
282        # Output only arrays of null-terminated arrays cannot be
283        # wrapped automaticly. How is the bridge supposed to know
284        # how much memory it should allocate for the C-array?
285        self.assertRaises(TypeError, fillStringArray_, None)
286        self.assertRaises(ValueError, fillStringArray_, objc.NULL)
287
288        self.assertRaises(TypeError, nullfillStringArray_)
289        self.assertRaises(TypeError, nullfillStringArray_, None)
290        n, v = nullfillStringArray_(objc.NULL)
291        self.assertEquals(n, 0)
292        self.assert_( v is objc.NULL)
293
294    def testWithCount(self):
295
296        v = fillArray_count_(None, 3)
297        self.assertEquals(list(v),  [0,1,4])
298
299        v = fillArray_count_(None, 3)
300        self.assertEquals(list(v),  [0,1,4])
301
302        v = fillArray_count_(None, 5)
303        self.assertEquals(list(v),  [0,1,4,9,16])
304
305        v = fillArray_count_(None, 0)
306        self.assertEquals(list(v),  [])
307
308        self.assertRaises(ValueError, fillArray_count_, objc.NULL, 0)
309
310        n, v = nullfillArray_count_(None, 3)
311        self.assertEquals(n, 1)
312        self.assertEquals(list(v),  [0,1,4])
313        n, v = nullfillArray_count_(None, 3)
314        self.assertEquals(n, 1)
315        self.assertEquals(list(v),  [0,1,4])
316
317        n, v = nullfillArray_count_(objc.NULL, 3)
318        self.assertEquals(n, 0)
319        self.assert_( v is objc.NULL )
320
321    def testWithCountInResult(self):
322
323        c, v = fillArray_uptoCount_(None, 20)
324        self.assertEquals(c, 10)
325        self.assertEquals(list(v),  [i+2 for i in range(10)])
326
327        c, v = maybeFillArray_(None)
328        self.assertEquals(c, 2)
329        self.assertEquals(list(v),  [10, 11])
330
331
332class TestArraysInOut (TestCase):
333    def testFixedSize(self):
334
335        a = (1,2,3,4)
336        v = reverse4Tuple_(a)
337        self.assertEquals(a, (1,2,3,4))
338        self.assertEquals(v, (4,3,2,1))
339
340        self.assertRaises(ValueError, reverse4Tuple_, (1,2,3))
341        self.assertRaises(ValueError, reverse4Tuple_, (1,2,3,4,5))
342        self.assertRaises(ValueError, reverse4Tuple_, objc.NULL)
343
344        a = (1,2,3,4)
345        n, v = nullreverse4Tuple_(a)
346        self.assertEquals(n, 1)
347        self.assertEquals(a, (1,2,3,4))
348        self.assertEquals(v, (4,3,2,1))
349
350        n, v = nullreverse4Tuple_(objc.NULL)
351        self.assertEquals(n, 0)
352        self.assert_( v is objc.NULL )
353
354    def testNullTerminated(self):
355
356        a = ('a', 'b', 'c')
357        v = reverseStrings_(a)
358        self.assertEquals(a, ('a', 'b', 'c'))
359        self.assertEquals(v, ('c', 'b', 'a'))
360
361        self.assertRaises(ValueError, reverseStrings_, (1,2))
362        self.assertRaises(ValueError, reverseStrings_, objc.NULL)
363
364        a = ('a', 'b', 'c')
365        n, v = nullreverseStrings_(a)
366        self.assertEquals(n, 1)
367        self.assertEquals(a, ('a', 'b', 'c'))
368        self.assertEquals(v, ('c', 'b', 'a'))
369
370        n, v = nullreverseStrings_(objc.NULL)
371        self.assertEquals(n, 0)
372        self.assert_( v is objc.NULL )
373
374    def testWithCount(self):
375
376        a = (1.0, 2.0, 3.0, 4.0, 5.0)
377        v = reverseArray_count_(a, 4)
378        self.assertEquals(a, (1.0, 2.0, 3.0, 4.0, 5.0))
379        self.assertEquals(v, (4.0, 3.0, 2.0, 1.0))
380
381        a = (1.0, 2.0, 3.0, 4.0, 5.0)
382        v = reverseArray_count_(a, 5)
383        self.assertEquals(a, (1.0, 2.0, 3.0, 4.0, 5.0))
384        self.assertEquals(v, (5.0, 4.0, 3.0, 2.0, 1.0))
385
386        # Nice to have, but doesn't work without major
387        # surgery:
388        #a = (1.0, 2.0, 3.0, 4.0, 5.0)
389        #v = reverseArray_count_(a, None)
390        #self.assertEquals(a, (1.0, 2.0, 3.0, 4.0, 5.0))
391        #self.assertEquals(v, (5.0, 4.0, 3.0, 2.0, 1.0))
392
393        self.assertRaises(ValueError, reverseArray_count_, (1.0, 2.0), 5)
394        self.assertRaises(ValueError, reverseArray_count_, objc.NULL, 0)
395
396        a = (1.0, 2.0, 3.0, 4.0, 5.0)
397        n, v = nullreverseArray_count_(a, 5)
398        self.assertEquals(n, 1)
399        self.assertEquals(a, (1.0, 2.0, 3.0, 4.0, 5.0))
400        self.assertEquals(v, (5.0, 4.0, 3.0, 2.0, 1.0))
401
402        n, v = nullreverseArray_count_(objc.NULL, 0)
403        self.assertEquals(n, 0)
404        self.assert_( v is objc.NULL )
405
406    def testWithCountInResult(self):
407
408        c, v = reverseArray_uptoCount_(range(10), 10)
409        self.assertEquals(c, 5)
410        self.assertEquals(len(v), 5)
411        self.assertEquals(list(v),  [9, 8, 7, 6, 5])
412
413        c, v = maybeReverseArray_([1,2,3,4])
414        self.assertEquals(c, 2)
415        self.assertEquals(len(v), 2)
416        self.assertEquals(list(v),  [4, 3])
417
418class TestArraysIn (TestCase):
419    def testFixedSize(self):
420
421        v = make4Tuple_((1.0, 4.0, 8.0, 12.5))
422        self.assertEquals(len(v), 4)
423        self.assertEquals(list(v), [1.0, 4.0, 8.0, 12.5])
424
425        v = make4Tuple_((1, 2, 3, 4))
426        self.assertEquals(len(v), 4)
427        self.assertEquals(list(v), [1.0, 2.0, 3.0, 4.0])
428
429        self.assertRaises(ValueError, make4Tuple_, (1, 2, 3))
430        self.assertRaises(ValueError, make4Tuple_, (1, 2, 3, 4, 5))
431        self.assertRaises(ValueError, make4Tuple_, objc.NULL)
432
433        v = null4Tuple_(objc.NULL)
434        self.assert_( v is None )
435
436    def testNullTerminated(self):
437
438        v = makeStringArray_(("hello", "world", "there"))
439        self.assertEquals(len(v), 3)
440        self.assertEquals(list(v), [u"hello", u"world", u"there"])
441        self.assert_( isinstance(v, objc.lookUpClass("NSArray")) )
442        self.assert_( isinstance(v[0], unicode) )
443
444        NSObject = objc.lookUpClass('NSObject')
445        p, q, r = NSObject.new(), NSObject.new(), NSObject.new()
446        v = makeObjectArray_((p, q, r))
447        self.assertEquals(len(v), 3)
448        self.assert_( v[0] is p )
449        self.assert_( v[1] is q )
450        self.assert_( v[2] is r )
451
452
453        v = makeStringArray_(())
454        self.assertEquals(len(v), 0)
455
456        self.assertRaises(ValueError, makeStringArray_, [1,2])
457        self.assertRaises(ValueError, makeStringArray_, objc.NULL)
458
459        v = nullStringArray_(objc.NULL)
460        self.assertEquals(v, None)
461
462    def testWithCount(self):
463
464        v = makeIntArray_count_((1,2,3,4), 3)
465        self.assertEquals(len(v), 3)
466        self.assertEquals(list(v), [1,2,3])
467
468        # XXX: This one would be nice to have, but not entirely trivial
469        #v = makeIntArray_count_((1,2,3,4), None)
470        #self.assertEquals(len(v), 3)
471        #self.assertEquals(list(v), [1,2,3,4])
472
473        self.assertRaises(ValueError, makeIntArray_count_, [1,2,3], 4)
474        self.assertRaises(ValueError, makeIntArray_count_, objc.NULL, 0)
475        self.assertRaises(ValueError, makeIntArray_count_, objc.NULL, 1)
476
477        v = nullIntArray_count_(objc.NULL, 0)
478        self.assertEquals(v, None)
479
480        self.assertRaises(ValueError, makeIntArray_count_, objc.NULL, 1)
481
482        # Make sure this also works when the length is in a pass-by-reference argument
483        v = makeIntArray_countPtr_((1,2,3,4), 4)
484        self.assertEquals(len(v), 4)
485        self.assertEquals(list(v), [1,2,3,4])
486
487class TestArrayReturns (TestCase):
488    # TODO:
489    # - Add null-terminated arrays of various supported types:
490    #   -> integers
491    #   -> CF-types
492    def testFixedSize(self):
493
494        v = makeIntArrayOf5()
495        self.assertEquals( len(v), 5 )
496        self.assertEquals( v[0], 0 )
497        self.assertEquals( v[1], 1 )
498        self.assertEquals( v[2], 4 )
499        self.assertEquals( v[3], 9 )
500        self.assertEquals( v[4], 16 )
501
502        v = nullIntArrayOf5()
503        self.assertEquals(v, objc.NULL)
504
505    def testSizeInArgument(self):
506        v = makeIntArrayOf_(3)
507        self.assertEquals(len(v), 3)
508        self.assertEquals(v[0], 0)
509        self.assertEquals(v[1], 1)
510        self.assertEquals(v[2], 8)
511
512        v = makeIntArrayOf_(10)
513        self.assertEquals(len(v), 10)
514        for i in range(10):
515            self.assertEquals(v[i], i**3)
516
517        v = nullIntArrayOf_(100)
518        self.assertEquals(v, objc.NULL)
519
520    def testNULLterminated(self):
521
522        v = makeStringArray()
523        self.assertEquals(len(v), 4)
524        self.assertEquals(list(v), ["hello", "world", "out", "there"])
525
526        v = nullStringArray()
527        self.assertEquals(v, objc.NULL)
528
529class TestByReference (TestCase):
530    # Pass by reference arguments.
531    # Note that these tests aren't exhaustive, we have test_methods and
532    # test_methods2 for that :-)
533
534    def testInput(self):
535
536        r = sumX_andY_(1, 2)
537        self.assertEquals(r, 1+2)
538
539        r = sumX_andY_(2535, 5325)
540        self.assertEquals(r, 2535 + 5325)
541
542        self.assertRaises(ValueError, sumX_andY_, 42, objc.NULL)
543
544    def testOutput(self):
545
546        div, rem = divBy5_remainder_(55, None)
547        self.assertEquals(div, 11)
548        self.assertEquals(rem, 0)
549
550        div, rem = divBy5_remainder_(13, None)
551        self.assertEquals(div, 2)
552        self.assertEquals(rem, 3)
553
554        self.assertRaises(ValueError, divBy5_remainder_, 42, objc.NULL)
555
556    def testInputOutput(self):
557        x, y = swapX_andY_(42, 284)
558        self.assertEquals(x, 284)
559        self.assertEquals(y, 42)
560
561        self.assertRaises(ValueError, swapX_andY_, 42, objc.NULL)
562
563    def testNullAccepted(self):
564        # Note: the commented-out test-cases require a change in the pyobjc-core
565
566        def makeNum(value):
567            return int(value, 0)
568
569        r, y, z = input_output_inputAndOutput_(1, None, 2)
570        self.assertEquals(len(r), 3)
571        self.assertEquals(len(filter(None, map(makeNum, r))), 3)
572        self.assertEquals(y, 3)
573        self.assertEquals(z, -1)
574
575        # Argument 1 is NULL
576        r, y, z = input_output_inputAndOutput_(objc.NULL, None, 2)
577        self.assertEquals(len(r), 3)
578        self.assertEquals(len(filter(None, map(makeNum, r))), 2)
579        self.assertEquals(y, 40)
580        self.assertEquals(z, -2)
581
582        r, y, z = input_output_inputAndOutput_(objc.NULL, None, 2)
583        self.assertEquals(len(r), 3)
584        self.assertEquals(len(filter(None, map(makeNum, r))), 2)
585        self.assertEquals(y, 40)
586        self.assertEquals(z, -2)
587
588        # Argument 2 is NULL
589        r, y, z = input_output_inputAndOutput_(1, objc.NULL, 2)
590        self.assertEquals(len(r), 3)
591        self.assertEquals(len(filter(None, map(makeNum, r))), 2)
592        self.assertEquals(y, objc.NULL)
593        self.assertEquals(z, -1)
594
595        # Argument 3 is NULL
596        r, y, z = input_output_inputAndOutput_(1, None, objc.NULL)
597        self.assertEquals(len(r), 3)
598        self.assertEquals(len(filter(None, map(makeNum, r))), 2)
599        self.assertEquals(y, 43)
600        self.assertEquals(z, objc.NULL)
601
602        r, y, z = input_output_inputAndOutput_(1, None, objc.NULL)
603        self.assertEquals(len(r), 3)
604        self.assertEquals(len(filter(None, map(makeNum, r))), 2)
605        self.assertEquals(y, 43)
606        self.assertEquals(z, objc.NULL)
607
608class TestPrintfFormat (TestCase):
609    def test_nsformat(self):
610
611        v = makeArrayWithFormat_("%3d", 10)
612        self.assertEquals(list(v), [ "%3d", " 10"])
613
614        v = makeArrayWithFormat_("hello %s", "world")
615        self.assertEquals(list(v), [ "hello %s", "hello world"])
616
617    def test_cformat(self):
618
619        v = makeArrayWithCFormat_("%3d", 10)
620        self.assertEquals(list(v), [ "%3d", " 10"])
621
622        v = makeArrayWithCFormat_("hello %s", "world")
623        self.assertEquals(list(v), [ "hello %s", "hello world"])
624
625if __name__ == "__main__":
626    main()
627