1"""
2Tests for the new-style metadata format interface.
3
4Note: Tests for calling from ObjC into python are in test_metadata_py.py
5
6TODO:
7- Add tests for calling functions instead of methods
8- The python->C interface (that is the contents of the metadata object) is
9  likely to change when the bridge is feature-complete.
10- Probably need special-casing for arrays (numarray and array.array)!
11"""
12from __future__ import unicode_literals
13import objc
14from PyObjCTools.TestSupport import *
15
16from PyObjCTest.metadata import *
17import PyObjCTest.test_metadata # to get the right metadata
18import warnings
19
20import sys
21if sys.version_info[0] == 3:
22    unicode = str
23
24
25class TestArrayDefault (TestCase):
26    # TODO: what is the default anyway?
27    pass
28
29class TestArraysOut (TestCase):
30    def testFixedSize(self):
31        o = OC_MetaDataTest.new()
32        m = o.methodForSelector_('fill4Tuple:')
33
34        v = m(o, None)
35        self.assertEqual(list(v), [0, -1, -8, -27])
36
37        self.assertRaises(ValueError, m, o, objc.NULL)
38
39        m = o.methodForSelector_('nullfill4Tuple:')
40        n, v = m(o, None)
41        self.assertEqual(n, 1)
42        self.assertEqual(list(v), [0, -1, -8, -27])
43
44        n, v = m(o, None)
45        self.assertEqual(n, 1)
46        self.assertEqual(list(v), [0, -1, -8, -27])
47
48        n, v = m(o, objc.NULL)
49        self.assertEqual(n, 0)
50        self.assertIs(v, objc.NULL)
51
52    def testNullTerminated(self):
53        o = OC_MetaDataTest.new()
54        m = o.methodForSelector_('fillStringArray:')
55
56
57        # Output only arrays of null-terminated arrays cannot be
58        # wrapped automaticly. How is the bridge supposed to know
59        # how much memory it should allocate for the C-array?
60        self.assertRaises(TypeError, m, o, None)
61        self.assertRaises(ValueError, m, o, objc.NULL)
62
63        m = o.methodForSelector_('fillStringArray:')
64        self.assertRaises(TypeError, m, o)
65        self.assertRaises(TypeError, m, o, None)
66        n, v = o.nullfillStringArray_(objc.NULL)
67        self.assertEqual(n, 0)
68        self.assertIs(v, objc.NULL)
69
70    def testWithCount(self):
71        o = OC_MetaDataTest.new()
72        m = o.methodForSelector_('fillArray:count:')
73
74        v = m(o, None, 3)
75        self.assertEqual(list(v),  [0,1,4])
76
77        v = m(o, None, 3)
78        self.assertEqual(list(v),  [0,1,4])
79
80        v = m(o, None, 5)
81        self.assertEqual(list(v),  [0,1,4,9,16])
82
83        v = m(o, None, 0)
84        self.assertEqual(list(v),  [])
85
86        self.assertRaises(ValueError, m, o, objc.NULL, 0)
87
88        m = o.methodForSelector_('nullfillArray:count:')
89        n, v = m(o, None, 3)
90        self.assertEqual(n, 1)
91        self.assertEqual(list(v),  [0,1,4])
92        n, v = m(o, None, 3)
93        self.assertEqual(n, 1)
94        self.assertEqual(list(v),  [0,1,4])
95
96
97        n, v = m(o, objc.NULL, 3)
98        self.assertEqual(n, 0)
99        self.assertIs(v, objc.NULL)
100
101    def testWithCountInResult(self):
102        o = OC_MetaDataTest.new()
103        m = o.methodForSelector_('fillArray:uptoCount:')
104
105        c, v = m(o, None, 20)
106        self.assertEqual(c, 10)
107        self.assertEqual(list(v),  [i+2 for i in range(10)])
108
109        m = o.methodForSelector_('maybeFillArray:')
110        c, v = m(o, None)
111        self.assertEqual(c, 2)
112        self.assertEqual(list(v),  [10, 11])
113
114
115
116class TestArraysInOut (TestCase):
117    def testFixedSize(self):
118        o = OC_MetaDataTest.new()
119        m = o.methodForSelector_('reverse4Tuple:')
120
121        a = (1,2,3,4)
122        v = m(o, a)
123        self.assertEqual(a, (1,2,3,4))
124        self.assertEqual(v, (4,3,2,1))
125
126        self.assertRaises(ValueError, m, o, (1,2,3))
127        self.assertRaises(ValueError, m, o, (1,2,3,4,5))
128        self.assertRaises(ValueError, m, o, objc.NULL)
129
130        m = o.methodForSelector_('nullreverse4Tuple:')
131        a = (1,2,3,4)
132        n, v = m(o, a)
133        self.assertEqual(n, 1)
134        self.assertEqual(a, (1,2,3,4))
135        self.assertEqual(v, (4,3,2,1))
136
137        n, v = m(o, objc.NULL)
138        self.assertEqual(n, 0)
139        self.assertIs(v, objc.NULL)
140
141    def testNullTerminated(self):
142        o = OC_MetaDataTest.new()
143        m = o.methodForSelector_('reverseStrings:')
144
145        a = (b'a', b'b', b'c')
146        v = m(o, a)
147        self.assertEqual(a, (b'a', b'b', b'c'))
148        self.assertEqual(v, (b'c', b'b', b'a'))
149
150        self.assertRaises(ValueError, m, o, (1,2))
151        self.assertRaises(ValueError, m, o, objc.NULL)
152
153        m = o.methodForSelector_('nullreverseStrings:')
154        a = (b'a', b'b', b'c')
155        n, v = m(o, a)
156        self.assertEqual(n, 1)
157        self.assertEqual(a, (b'a', b'b', b'c'))
158        self.assertEqual(v, (b'c', b'b', b'a'))
159
160        n, v = m(o, objc.NULL)
161        self.assertEqual(n, 0)
162        self.assertIs(v, objc.NULL)
163
164    def testWithCount(self):
165        o = OC_MetaDataTest.new()
166        m = o.methodForSelector_('reverseArray:count:')
167
168        a = (1.0, 2.0, 3.0, 4.0, 5.0)
169        v = m(o, a, 4)
170        self.assertEqual(a, (1.0, 2.0, 3.0, 4.0, 5.0))
171        self.assertEqual(v, (4.0, 3.0, 2.0, 1.0))
172
173        a = (1.0, 2.0, 3.0, 4.0, 5.0)
174        v = m(o, a, 5)
175        self.assertEqual(a, (1.0, 2.0, 3.0, 4.0, 5.0))
176        self.assertEqual(v, (5.0, 4.0, 3.0, 2.0, 1.0))
177
178        # Nice to have, but doesn't work without major
179        # surgery:
180        #a = (1.0, 2.0, 3.0, 4.0, 5.0)
181        #v = m(o, a, None)
182        #self.assertEqual(a, (1.0, 2.0, 3.0, 4.0, 5.0))
183        #self.assertEqual(v, (5.0, 4.0, 3.0, 2.0, 1.0))
184
185        self.assertRaises(ValueError, m, o, (1.0, 2.0), 5)
186        self.assertRaises(ValueError, m, o, objc.NULL, 0)
187
188        m = o.methodForSelector_('nullreverseArray:count:')
189        a = (1.0, 2.0, 3.0, 4.0, 5.0)
190        n, v = m(o, a, 5)
191        self.assertEqual(n, 1)
192        self.assertEqual(a, (1.0, 2.0, 3.0, 4.0, 5.0))
193        self.assertEqual(v, (5.0, 4.0, 3.0, 2.0, 1.0))
194
195        n, v = m(o, objc.NULL, 0)
196        self.assertEqual(n, 0)
197        self.assertIs(v, objc.NULL)
198
199    def testWithCountInResult(self):
200        o = OC_MetaDataTest.new()
201        m = o.methodForSelector_('reverseArray:uptoCount:')
202
203        c, v = m(o, range(10), 10)
204        self.assertEqual(c, 5)
205        self.assertEqual(len(v), 5)
206        self.assertEqual(list(v),  [9, 8, 7, 6, 5])
207
208        m = o.methodForSelector_('maybeReverseArray:')
209        c, v = m(o, [1,2,3,4])
210        self.assertEqual(c, 2)
211        self.assertEqual(len(v), 2)
212        self.assertEqual(list(v),  [4, 3])
213
214class TestArraysIn (TestCase):
215    def testFixedSize(self):
216        o = OC_MetaDataTest.new()
217        m = o.methodForSelector_('make4Tuple:')
218
219        v = m(o, (1.0, 4.0, 8.0, 12.5))
220        self.assertEqual(len(v), 4)
221        self.assertEqual(list(v), [1.0, 4.0, 8.0, 12.5])
222
223        v = m(o, (1, 2, 3, 4))
224        self.assertEqual(len(v), 4)
225        self.assertEqual(list(v), [1.0, 2.0, 3.0, 4.0])
226
227        self.assertRaises(ValueError, m, o, (1, 2, 3))
228        self.assertRaises(ValueError, m, o, (1, 2, 3, 4, 5))
229        self.assertRaises(ValueError, m, o, objc.NULL)
230
231        m = o.methodForSelector_('null4Tuple:')
232        v = m(o, objc.NULL)
233        self.assertIsNone(v)
234
235    def testNullTerminated(self):
236        o = OC_MetaDataTest.new()
237
238        m = o.methodForSelector_('makeStringArray:')
239
240        v = m(o, (b"hello", b"world", b"there"))
241        self.assertEqual(len(v), 3)
242        self.assertEqual(list(v), ["hello", "world", "there"])
243        self.assertIsInstance(v, objc.lookUpClass("NSArray"))
244        self.assertIsInstance(v[0], unicode)
245
246        m = o.methodForSelector_('makeObjectArray:')
247
248        NSObject = objc.lookUpClass('NSObject')
249        p, q, r = NSObject.new(), NSObject.new(), NSObject.new()
250        v = m(o, (p, q, r))
251        self.assertEqual(len(v), 3)
252        self.assertIs(v[0], p)
253        self.assertIs(v[1], q)
254        self.assertIs(v[2], r)
255
256        m = o.methodForSelector_('makeStringArray:')
257
258        v = m(o, ())
259        self.assertEqual(len(v), 0)
260
261        self.assertRaises(ValueError, m, o, [1,2])
262        self.assertRaises(ValueError, m, o, objc.NULL)
263
264        m = o.methodForSelector_('nullStringArray:')
265        v = m(o, objc.NULL)
266        self.assertEqual(v, None)
267
268    def testWithCount(self):
269        o = OC_MetaDataTest.new()
270        m = o.methodForSelector_('makeIntArray:count:')
271
272        v = m(o, (1,2,3,4), 3)
273        self.assertEqual(len(v), 3)
274        self.assertEqual(list(v), [1,2,3])
275
276        # XXX: This one would be nice to have, but not entirely trivial
277        #v = m(o, (1,2,3,4), None)
278        #self.assertEqual(len(v), 3)
279        #self.assertEqual(list(v), [1,2,3,4])
280
281        self.assertRaises(ValueError, m, o, [1,2,3], 4)
282        self.assertRaises(ValueError, m, o, objc.NULL, 0)
283        self.assertRaises(ValueError, m, o, objc.NULL, 1)
284
285        self.assertRaises(ValueError, m, o, objc.NULL, 1)
286
287        m = o.methodForSelector_('nullIntArray:count:')
288        v = m(o, objc.NULL, 0)
289        self.assertEqual(v, None)
290
291
292        # Make sure this also works when the length is in a pass-by-reference argument
293        m = o.methodForSelector_('makeIntArray:countPtr:')
294        v = m(o, (1,2,3,4), 4)
295        self.assertEqual(len(v), 4)
296        self.assertEqual(list(v), [1,2,3,4])
297
298class TestArrayReturns (TestCase):
299    # TODO:
300    # - Add null-terminated arrays of various supported types:
301    #   -> integers
302    #   -> CF-types
303    def testFixedSize(self):
304        o = OC_MetaDataTest.new()
305        m = o.methodForSelector_(b'makeIntArrayOf5')
306
307        v = m(o)
308        self.assertEqual( len(v), 5 )
309        self.assertEqual( v[0], 0 )
310        self.assertEqual( v[1], 1 )
311        self.assertEqual( v[2], 4 )
312        self.assertEqual( v[3], 9 )
313        self.assertEqual( v[4], 16 )
314
315        m = o.methodForSelector_(b'nullIntArrayOf5')
316        v = m(o)
317        self.assertEqual(v, objc.NULL)
318
319    def testSizeInArgument(self):
320        o = OC_MetaDataTest.new()
321        m = o.methodForSelector_(b'makeIntArrayOf:')
322
323        v = m(o, 3)
324        self.assertEqual(len(v), 3)
325        self.assertEqual(v[0], 0)
326        self.assertEqual(v[1], 1)
327        self.assertEqual(v[2], 8)
328
329        v = m(o, 10)
330        self.assertEqual(len(v), 10)
331        for i in range(10):
332            self.assertEqual(v[i], i**3)
333
334        m = o.methodForSelector_(b'nullIntArrayOf:')
335        v = m(o, 100)
336        self.assertEqual(v, objc.NULL)
337
338    def testNULLterminated(self):
339        o  = OC_MetaDataTest.new()
340        m = o.methodForSelector_(b'makeStringArray')
341
342        v = m(o)
343        self.assertEqual(len(v), 4)
344        self.assertEqual(list(v), [b"hello", b"world", b"out", b"there"])
345
346        m = o.methodForSelector_(b'nullStringArray')
347        v = m(o)
348        self.assertEqual(v, objc.NULL)
349
350class TestByReference (TestCase):
351    # Pass by reference arguments.
352    # Note that these tests aren't exhaustive, we have test_methods and
353    # test_methods2 for that :-)
354
355    def testInput(self):
356        o = OC_MetaDataTest.new()
357        m = o.methodForSelector_('sumX:andY:')
358
359        r = m(o, 1, 2)
360        self.assertEqual(r, 1+2)
361
362        r = m(o, 2535, 5325)
363        self.assertEqual(r, 2535 + 5325)
364
365        self.assertRaises(ValueError, m, o, 42, objc.NULL)
366
367    def testOutput(self):
368        o = OC_MetaDataTest.new()
369        m = o.methodForSelector_('divBy5:remainder:')
370
371        div, rem = m(o, 55, None)
372        self.assertEqual(div, 11)
373        self.assertEqual(rem, 0)
374
375        div, rem = m(o, 13, None)
376        self.assertEqual(div, 2)
377        self.assertEqual(rem, 3)
378
379        # To be fixed:
380        #self.assertRaises(ValueError, m, o, 42, objc.NULL)
381
382    def testInputOutput(self):
383        o = OC_MetaDataTest.new()
384        m = o.methodForSelector_('swapX:andY:')
385
386        x, y = m(o, 42, 284)
387        self.assertEqual(x, 284)
388        self.assertEqual(y, 42)
389
390        self.assertRaises(ValueError, m, o, 42, objc.NULL)
391
392    def testNullAccepted(self):
393        # Note: the commented-out test-cases require a change in the pyobjc-core
394        o = OC_MetaDataTest.new();
395        m = o.methodForSelector_('input:output:inputAndOutput:')
396
397        def makeNum(value):
398            return int(value, 0)
399
400        # All arguments present
401        r, y, z = m(o, 1, None, 2)
402        self.assertEqual(len(r), 3)
403        self.assertEqual(len(list(filter(None, map(makeNum, r)))), 3)
404        self.assertEqual(y, 3)
405        self.assertEqual(z, -1)
406
407        r, y, z = m(o, 1, None, 2)
408        self.assertEqual(len(r), 3)
409        self.assertEqual(len(list(filter(None, map(makeNum, r)))), 3)
410        self.assertEqual(y, 3)
411        self.assertEqual(z, -1)
412
413        # Argument 1 is NULL
414        r, y, z = m(o, objc.NULL, None, 2)
415        self.assertEqual(len(r), 3)
416        self.assertEqual(len(list(filter(None, map(makeNum, r)))), 2)
417        self.assertEqual(y, 40)
418        self.assertEqual(z, -2)
419
420        r, y, z = m(o, objc.NULL, None, 2)
421        self.assertEqual(len(r), 3)
422        self.assertEqual(len(list(filter(None, map(makeNum, r)))), 2)
423        self.assertEqual(y, 40)
424        self.assertEqual(z, -2)
425
426        # Argument 2 is NULL
427        r, y, z = m(o, 1, objc.NULL, 2)
428        self.assertEqual(len(r), 3)
429        self.assertEqual(len(list(filter(None, map(makeNum, r)))), 2)
430        self.assertEqual(y, objc.NULL)
431        self.assertEqual(z, -1)
432
433        # Argument 3 is NULL
434        r, y, z = m(o, 1, None, objc.NULL)
435        self.assertEqual(len(r), 3)
436        self.assertEqual(len(list(filter(None, map(makeNum, r)))), 2)
437        self.assertEqual(y, 43)
438        self.assertEqual(z, objc.NULL)
439
440        r, y, z = m(o, 1, None, objc.NULL)
441        self.assertEqual(len(r), 3)
442        self.assertEqual(len(list(filter(None, map(makeNum, r)))), 2)
443        self.assertEqual(y, 43)
444        self.assertEqual(z, objc.NULL)
445
446
447if __name__ == "__main__":
448    main()
449