1/*
2 * This file contains some unittests for specific functions in the extension
3 * module.
4 *
5 * The PyObjC unittest objc.test.test_ctests executes the tests in this file.
6 */
7#include "Python.h"
8#include "pyobjc-api.h"
9#include "pyobjc-compat.h"
10
11#if PY_VERSION_HEX >= 0x03000000
12#define PyInt_AsLong PyLong_AsLong
13#endif
14#include "pyobjc-unittest.h"
15
16
17#include <fcntl.h>
18
19#import <Foundation/Foundation.h>
20
21struct Struct1 {
22	int f1;
23	double f2;
24};
25
26struct Struct2 {
27	int f1;
28	double f2;
29	short s[5];
30};
31
32struct Struct3 {
33	char ch;
34	int  i;
35};
36
37struct Struct4 {
38	char ch;
39	long long i;
40};
41
42struct Struct5 {
43	long i;
44	char ch;
45};
46
47typedef struct Struct5 Struct5Array[2];
48
49
50
51/* Helper stuff for TestNSInvoke */
52
53static struct Struct2 invokeHelper = { 0, 0, { 0, 0, 0, 0, 0 } };
54
55@interface PyObjCTest_NSInvoke : NSObject
56{
57}
58-(void)methodWithMyStruct: (struct Struct2)val1 andShort:(short)val2;
59@end
60
61@implementation PyObjCTest_NSInvoke
62-(void)methodWithMyStruct: (struct Struct2)val1 andShort:(short)val2
63{
64	(void)val2;
65	invokeHelper = val1;
66}
67@end
68
69BEGIN_UNITTEST(CheckNSInvoke)
70	/* This is not a 'real' unittest, but is used to disable a number of
71	 * other tests (in objc.test.test_methods2) when NSInvocation isn't
72	 * working correctly (MacOS X at least upto 10.2.6).
73	 * [Panther previews also have this problem]
74	 *
75	 * Leopard is even worse, this test causes a crash of the interpreter when
76         * running on PPC64.
77	 */
78#ifdef __ppc64__
79	ASSERT_EQUALS(0, 1, "%d");
80#endif
81
82	PyObjCTest_NSInvoke* obj = [[PyObjCTest_NSInvoke alloc] init];
83	NSInvocation* inv;
84	struct Struct2 v1 = { 1, 2, { 3, 4, 5, 6, 7 } };
85	short    v2 = 8;
86
87	[obj methodWithMyStruct: v1 andShort: v2];
88	inv = [NSInvocation invocationWithMethodSignature:
89		[obj methodSignatureForSelector:@selector(methodWithMyStruct:andShort:)]];
90	[inv setTarget: obj];
91	[inv setSelector: @selector(methodWithMyStruct:andShort:)];
92	[inv setArgument: &v1 atIndex: 2];
93	[inv setArgument: &v2 atIndex: 3];
94
95	[inv invoke];
96	[obj release];
97	ASSERT_EQUALS(invokeHelper.f1, v1.f1, "%d");
98	ASSERT_EQUALS(invokeHelper.f2, v1.f2, "%g");
99	ASSERT_EQUALS(invokeHelper.s[0], v1.s[0], "%d");
100	ASSERT_EQUALS(invokeHelper.s[1], v1.s[1], "%d");
101	ASSERT_EQUALS(invokeHelper.s[2], v1.s[2], "%d");
102	ASSERT_EQUALS(invokeHelper.s[3], v1.s[3], "%d");
103	ASSERT_EQUALS(invokeHelper.s[4], v1.s[4], "%d");
104
105END_UNITTEST
106
107
108BEGIN_UNITTEST(StructSize)
109
110	ASSERT_EQUALS(
111	    sizeof(struct Struct1), PyObjCRT_SizeOfType(@encode(struct Struct1)),
112	    "%d");
113
114	ASSERT_EQUALS(
115	    sizeof(struct Struct2), PyObjCRT_SizeOfType(@encode(struct Struct2)),
116	    "%d");
117
118	ASSERT_EQUALS(
119	    sizeof(struct Struct3), PyObjCRT_SizeOfType(@encode(struct Struct3)),
120	    "%d");
121
122	ASSERT_EQUALS(
123	    sizeof(struct Struct4), PyObjCRT_SizeOfType(@encode(struct Struct4)),
124	    "%d");
125
126	ASSERT_EQUALS(
127	    sizeof(NSRect), PyObjCRT_SizeOfType(@encode(NSRect)), "%d");
128
129END_UNITTEST
130
131BEGIN_UNITTEST(StructAlign)
132
133	ASSERT_EQUALS(
134	    __alignof__(struct Struct1),
135	    PyObjCRT_AlignOfType(@encode(struct Struct1)),
136	    "%d");
137
138	ASSERT_EQUALS(
139	    __alignof__(struct Struct2),
140	    PyObjCRT_AlignOfType(@encode(struct Struct2)),
141	    "%d");
142
143	ASSERT_EQUALS(
144	    __alignof__(struct Struct3),
145	    PyObjCRT_AlignOfType(@encode(struct Struct3)),
146	    "%d");
147
148	ASSERT_EQUALS(
149	    __alignof__(struct Struct4),
150	    PyObjCRT_AlignOfType(@encode(struct Struct4)),
151	    "%d");
152
153END_UNITTEST
154
155
156BEGIN_UNITTEST(FillStruct1)
157
158	PyObject* input;
159	struct Struct1 output;
160	int r;
161
162	input = PyTuple_New(2);
163	FAIL_IF(input == NULL);
164
165	PyTuple_SetItem(input, 0, PyInt_FromLong(1));
166	PyTuple_SetItem(input, 1, PyFloat_FromDouble(2));
167
168	r = PyObjC_PythonToObjC(@encode(struct Struct1), input, &output);
169	FAIL_IF(r < 0);
170
171	Py_DECREF(input);
172
173	ASSERT_EQUALS(output.f1, 1, "%d");
174	ASSERT_EQUALS(output.f2, 2.0, "%g");
175
176END_UNITTEST
177
178BEGIN_UNITTEST(FillStruct2)
179
180	PyObject* input;
181	PyObject* v;
182	struct Struct2 output;
183	int r;
184
185	input = PyTuple_New(3);
186	FAIL_IF(input == NULL);
187
188	v = PyTuple_New(5);
189	PyTuple_SetItem(v, 0, PyInt_FromLong(10));
190	PyTuple_SetItem(v, 1, PyInt_FromLong(11));
191	PyTuple_SetItem(v, 2, PyInt_FromLong(12));
192	PyTuple_SetItem(v, 3, PyInt_FromLong(13));
193	PyTuple_SetItem(v, 4, PyInt_FromLong(14));
194
195	PyTuple_SetItem(input, 0, PyInt_FromLong(1));
196	PyTuple_SetItem(input, 1, PyFloat_FromDouble(2));
197	PyTuple_SetItem(input, 2, v);
198
199	r = PyObjC_PythonToObjC(@encode(struct Struct2), input, &output);
200	FAIL_IF(r < 0);
201
202	Py_DECREF(input);
203
204	ASSERT_EQUALS(output.f1, 1,    "%d");
205	ASSERT_EQUALS(output.f2, 2.0,  "%g");
206	ASSERT_EQUALS(output.s[0], 10, "%d");
207	ASSERT_EQUALS(output.s[1], 11, "%d");
208	ASSERT_EQUALS(output.s[2], 12, "%d");
209	ASSERT_EQUALS(output.s[3], 13, "%d");
210	ASSERT_EQUALS(output.s[4], 14, "%d");
211
212END_UNITTEST
213
214BEGIN_UNITTEST(FillStruct3)
215
216	PyObject* input;
217	struct Struct3 output;
218	int r;
219
220	input = PyTuple_New(2);
221	FAIL_IF(input == NULL);
222
223	PyTuple_SetItem(input, 0,  PyBytes_FromStringAndSize("\001", 1));
224	PyTuple_SetItem(input, 1, PyInt_FromLong(2));
225
226	r = PyObjC_PythonToObjC(@encode(struct Struct3), input, &output);
227	FAIL_IF(r < 0);
228
229	Py_DECREF(input);
230
231	ASSERT_EQUALS(output.ch, '\001',    "%d");
232	ASSERT_EQUALS(output.i, 2,  "%d");
233
234END_UNITTEST
235
236BEGIN_UNITTEST(FillStruct4)
237
238	PyObject* input;
239	struct Struct4 output;
240	int r;
241
242	input = PyTuple_New(2);
243	FAIL_IF(input == NULL);
244
245	PyTuple_SetItem(input, 0,  PyBytes_FromStringAndSize("\001", 1));
246	PyTuple_SetItem(input, 1, PyInt_FromLong(500000));
247
248	r = PyObjC_PythonToObjC(@encode(struct Struct4), input, &output);
249	FAIL_IF(r < 0);
250
251	Py_DECREF(input);
252
253	ASSERT_EQUALS(output.ch, '\001',    "%d");
254	ASSERT_EQUALS(output.i, 500000,  "%ll");
255
256END_UNITTEST
257
258BEGIN_UNITTEST(FillStruct5Array)
259
260	PyObject* input;
261	PyObject* v;
262	Struct5Array output;
263	int r;
264
265	input = PyTuple_New(2);
266	FAIL_IF(input == NULL);
267
268	v = PyTuple_New(2);
269	PyTuple_SetItem(v, 0, PyInt_FromLong(500000));
270	PyTuple_SetItem(v, 1,  PyBytes_FromStringAndSize("\001", 1));
271	PyTuple_SetItem(input, 0, v);
272
273	v = PyTuple_New(2);
274	PyTuple_SetItem(v, 0, PyInt_FromLong(1000000));
275	PyTuple_SetItem(v, 1,  PyBytes_FromStringAndSize("\002", 1));
276	PyTuple_SetItem(input, 1, v);
277
278	r = PyObjC_PythonToObjC(@encode(Struct5Array), input, &output);
279	FAIL_IF(r < 0);
280
281	Py_DECREF(input);
282
283	ASSERT_EQUALS(output[0].ch, '\001',    "%d");
284	ASSERT_EQUALS(output[0].i, 500000,  "%ll");
285	ASSERT_EQUALS(output[1].ch, '\002',    "%d");
286	ASSERT_EQUALS(output[1].i, 1000000,  "%ll");
287
288END_UNITTEST
289
290BEGIN_UNITTEST(ExtractStruct1)
291
292	struct Struct1 input;
293	PyObject* output;
294
295	input.f1 = 1;
296	input.f2 = 2;
297
298	output = PyObjC_ObjCToPython(@encode(struct Struct1), &input);
299	FAIL_IF(output == NULL);
300
301	ASSERT_ISINSTANCE(output, Tuple);
302	ASSERT_EQUALS(PyTuple_GET_SIZE(output), 2, "%d");
303#if PY_VERSION_HEX < 0x03000000
304	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 0), Int);
305#else
306	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 0), Long);
307#endif
308	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 1), Float);
309	ASSERT_EQUALS(PyInt_AsLong(PyTuple_GetItem(output, 0)), 1, "%d");
310	ASSERT_EQUALS(PyFloat_AsDouble(PyTuple_GetItem(output, 1)), 2.0, "%g");
311
312END_UNITTEST
313
314BEGIN_UNITTEST(ExtractStruct2)
315
316	struct Struct2 input;
317	PyObject* output;
318	PyObject* tup;
319	PyObject* v;
320
321	input.f1 = 1;
322	input.f2 = 2;
323	input.s[0] = 3;
324	input.s[1] = 4;
325	input.s[2] = 5;
326	input.s[3] = 6;
327	input.s[4] = 7;
328
329	output = PyObjC_ObjCToPython(@encode(struct Struct2), &input);
330	FAIL_IF(output == NULL);
331
332	ASSERT_ISINSTANCE(output, Tuple);
333	ASSERT_EQUALS(PyTuple_GET_SIZE(output), 3, "%d");
334#if PY_VERSION_HEX < 0x03000000
335	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 0), Int);
336#else
337	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 0), Long);
338#endif
339	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 1), Float);
340	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 2), Tuple);
341	ASSERT_EQUALS(PyInt_AsLong(PyTuple_GetItem(output, 0)), 1, "%d");
342	ASSERT_EQUALS(PyFloat_AsDouble(PyTuple_GetItem(output, 1)), 2.0, "%g");
343
344	tup = PyTuple_GetItem(output, 2);
345	ASSERT_EQUALS(PyTuple_GET_SIZE(tup), 5, "%d");
346
347	v = PyTuple_GetItem(tup, 0);
348#if PY_VERSION_HEX < 0x03000000
349	ASSERT_ISINSTANCE(v, Int);
350#else
351	ASSERT_ISINSTANCE(v, Long);
352#endif
353	ASSERT_EQUALS(PyInt_AsLong(v), 3, "%d");
354
355	v = PyTuple_GetItem(tup, 1);
356#if PY_VERSION_HEX < 0x03000000
357	ASSERT_ISINSTANCE(v, Int);
358#else
359	ASSERT_ISINSTANCE(v, Long);
360#endif
361	ASSERT_EQUALS(PyInt_AsLong(v), 4, "%d");
362
363	v = PyTuple_GetItem(tup, 2);
364#if PY_VERSION_HEX < 0x03000000
365	ASSERT_ISINSTANCE(v, Int);
366#else
367	ASSERT_ISINSTANCE(v, Long);
368#endif
369	ASSERT_EQUALS(PyInt_AsLong(v), 5, "%d");
370
371	v = PyTuple_GetItem(tup, 3);
372#if PY_VERSION_HEX < 0x03000000
373	ASSERT_ISINSTANCE(v, Int);
374#else
375	ASSERT_ISINSTANCE(v, Long);
376#endif
377	ASSERT_EQUALS(PyInt_AsLong(v), 6, "%d");
378
379	v = PyTuple_GetItem(tup, 4);
380#if PY_VERSION_HEX < 0x03000000
381	ASSERT_ISINSTANCE(v, Int);
382#else
383	ASSERT_ISINSTANCE(v, Long);
384#endif
385	ASSERT_EQUALS(PyInt_AsLong(v), 7, "%d");
386
387END_UNITTEST
388
389BEGIN_UNITTEST(ExtractStruct3)
390
391	struct Struct3 input;
392	PyObject* output;
393
394	input.ch = 1;
395	input.i = 2;
396
397	output = PyObjC_ObjCToPython(@encode(struct Struct3), &input);
398	FAIL_IF(output == NULL);
399
400	ASSERT_ISINSTANCE(output, Tuple);
401	ASSERT_EQUALS(PyTuple_GET_SIZE(output), 2, "%d");
402#if PY_VERSION_HEX < 0x03000000
403	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 0), Int);
404	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 1), Int);
405#else
406	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 0), Long);
407	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 1), Long);
408#endif
409	ASSERT_EQUALS(PyInt_AsLong(PyTuple_GetItem(output, 0)), 1, "%d");
410	ASSERT_EQUALS(PyInt_AsLong(PyTuple_GetItem(output, 1)), 2, "%d");
411
412END_UNITTEST
413
414BEGIN_UNITTEST(ExtractStruct4)
415
416	struct Struct4 input;
417	PyObject* output;
418
419	input.ch = 1;
420	input.i = 500000;
421
422	output = PyObjC_ObjCToPython(@encode(struct Struct4), &input);
423	FAIL_IF(output == NULL);
424
425	ASSERT_ISINSTANCE(output, Tuple);
426	ASSERT_EQUALS(PyTuple_GET_SIZE(output), 2, "%d");
427#if PY_VERSION_HEX < 0x03000000
428	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 0), Int);
429#ifdef __LP64__
430	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 1), Int);
431#else
432	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 1), Long);
433#endif
434#else
435	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 0), Long);
436	ASSERT_ISINSTANCE(PyTuple_GetItem(output, 1), Long);
437#endif
438
439	ASSERT_EQUALS(PyInt_AsLong(PyTuple_GetItem(output, 0)), 1, "%d");
440	ASSERT_EQUALS(PyInt_AsLong(PyTuple_GetItem(output, 1)), 500000, "%d");
441
442END_UNITTEST
443
444BEGIN_UNITTEST(ExtractStruct5Array)
445
446	Struct5Array input;
447	PyObject* output;
448	PyObject* v;
449
450	input[0].ch = 1;
451	input[0].i = 500000;
452	input[1].ch = 2;
453	input[1].i = 1000000;
454
455	output = PyObjC_ObjCToPython(@encode(Struct5Array), &input);
456	FAIL_IF(output == NULL);
457
458	ASSERT_ISINSTANCE(output, Tuple);
459	ASSERT_EQUALS(PyTuple_GET_SIZE(output), 2, "%d");
460
461	v = PyTuple_GetItem(output, 0);
462	ASSERT_ISINSTANCE(v, Tuple);
463#if PY_VERSION_HEX < 0x03000000
464	ASSERT_ISINSTANCE(PyTuple_GetItem(v, 0), Int);
465	ASSERT_ISINSTANCE(PyTuple_GetItem(v, 1), Int);
466#else
467	ASSERT_ISINSTANCE(PyTuple_GetItem(v, 0), Long);
468	ASSERT_ISINSTANCE(PyTuple_GetItem(v, 1), Long);
469#endif
470	ASSERT_EQUALS(PyInt_AsLong(PyTuple_GetItem(v, 0)), 500000, "%d");
471	ASSERT_EQUALS(PyInt_AsLong(PyTuple_GetItem(v, 1)), 1, "%d");
472
473	v = PyTuple_GetItem(output, 1);
474	ASSERT_ISINSTANCE(v, Tuple);
475#if PY_VERSION_HEX < 0x03000000
476	ASSERT_ISINSTANCE(PyTuple_GetItem(v, 0), Int);
477	ASSERT_ISINSTANCE(PyTuple_GetItem(v, 1), Int);
478#else
479	ASSERT_ISINSTANCE(PyTuple_GetItem(v, 0), Long);
480	ASSERT_ISINSTANCE(PyTuple_GetItem(v, 1), Long);
481#endif
482	ASSERT_EQUALS(PyInt_AsLong(PyTuple_GetItem(v, 0)), 1000000, "%d");
483	ASSERT_EQUALS(PyInt_AsLong(PyTuple_GetItem(v, 1)), 2, "%d");
484
485END_UNITTEST
486
487#ifdef _C_BOOL
488
489BEGIN_UNITTEST(TestSizeOfBool)
490
491	/* Code in libffi_support.m depends on this equality. */
492#if defined(__ppc__) || defined(__ppc64__)
493	ASSERT_EQUALS(sizeof(bool), sizeof(int), "%d");
494
495#else
496	ASSERT_EQUALS(sizeof(bool), sizeof(char), "%d");
497#endif
498
499END_UNITTEST
500
501#endif
502
503BEGIN_UNITTEST(TestTypeCode)
504
505	/* These are manually defined on some platforms */
506	ASSERT_EQUALS(@encode(long long)[0], 'q', "%c");
507	ASSERT_EQUALS(@encode(unsigned long long)[0], 'Q', "%c");
508
509#if defined(MACOSX) &&  MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_1
510	ASSERT_EQUALS(@encode(bool)[0], 'B', "%#x");
511#endif
512
513END_UNITTEST
514
515BEGIN_UNITTEST(TestSimplifySignature)
516	/* Make sure PyObjCRT_SimplifySignature works */
517	char b[1024];
518	int  r;
519
520	r = PyObjCRT_SimplifySignature("@1234@0:{_NSPoint=ff}02i22", b, sizeof(b));
521	ASSERT(r != -1);
522	ASSERT_STREQUALS("@@:{_NSPoint=ff}i", b);
523
524	r = PyObjCRT_SimplifySignature("@@:{_NSPoint=ff}i", b, sizeof(b));
525	ASSERT(r != -1);
526	ASSERT_STREQUALS("@@:{_NSPoint=ff}i", b);
527END_UNITTEST
528
529BEGIN_UNITTEST(TestArrayCoding)
530	/*
531  	 * According to the docs on Panther, valueForKey: on an array should
532	 * return [ o.valueForKey_(key) for o in anArray ].
533	 * On MacOS X 10.2 it doesn't.
534	 *
535         * This test was added to make sure PyObjC is not at fault :-), the
536	 * test is also used to avoid giving false positives in the unittests
537 	 * for key-value coding.
538         */
539
540	NSMutableDictionary* d;
541	NSMutableArray* a;
542	NSObject* v;
543	int haveException;
544
545	NSAutoreleasePool* p;
546
547	p = [[NSAutoreleasePool alloc] init];
548
549	d = [NSMutableDictionary dictionary];
550
551	[d setObject:@"foo" forKey:@"keyM"];
552
553	a = [NSMutableArray arrayWithObjects: d, nil];
554
555	NS_DURING
556		v = [a valueForKey:@"keyM"];
557		haveException = 0;
558	NS_HANDLER
559		v = nil;
560		haveException = 1;
561	NS_ENDHANDLER
562
563	[p release];
564
565	ASSERT(!haveException);
566END_UNITTEST
567
568
569BEGIN_UNITTEST(PythonListAsNSArray)
570	PyObject* aList;
571	NSMutableArray* array;
572	NSArray* array2;
573
574	aList = Py_BuildValue("[iiiii]", 0, 1, 2, 3, 4);
575	FAIL_IF(aList == NULL);
576
577	array = PyObjC_PythonToId(aList);
578	FAIL_IF(array == nil);
579
580	/* Check lenght */
581	ASSERT_EQUALS(5, [array count], "%d");
582
583	/* Check basic element access */
584	ASSERT([[NSNumber numberWithInt:0] isEqual:[array objectAtIndex:0]]);
585	ASSERT([[NSNumber numberWithInt:1] isEqual:[array objectAtIndex:1]]);
586	ASSERT([[NSNumber numberWithInt:2] isEqual:[array objectAtIndex:2]]);
587	ASSERT([[NSNumber numberWithInt:3] isEqual:[array objectAtIndex:3]]);
588	ASSERT([[NSNumber numberWithInt:4] isEqual:[array objectAtIndex:4]]);
589
590	/* Check some other methods */
591	array2 = [array arrayByAddingObject: [NSNumber numberWithInt:5]];
592	FAIL_IF(array2 == nil);
593
594	ASSERT_EQUALS(6, [array2 count], "%d");
595	ASSERT_EQUALS(5, [array count], "%d");
596
597	ASSERT([[NSNumber numberWithInt:0] isEqual:[array2 objectAtIndex:0]]);
598	ASSERT([[NSNumber numberWithInt:1] isEqual:[array2 objectAtIndex:1]]);
599	ASSERT([[NSNumber numberWithInt:2] isEqual:[array2 objectAtIndex:2]]);
600	ASSERT([[NSNumber numberWithInt:3] isEqual:[array2 objectAtIndex:3]]);
601	ASSERT([[NSNumber numberWithInt:4] isEqual:[array2 objectAtIndex:4]]);
602	ASSERT([[NSNumber numberWithInt:5] isEqual:[array2 objectAtIndex:5]]);
603
604	ASSERT([array containsObject:[NSNumber numberWithInt:4]]);
605	ASSERT(![array containsObject:[NSNumber numberWithInt:10]]);
606
607	/* Mutating methods */
608	[array addObject: [NSNumber numberWithInt:5]];
609	ASSERT_EQUALS(6, [array count], "%d");
610	ASSERT([[NSNumber numberWithInt:5] isEqual:[array objectAtIndex:5]]);
611
612	[array removeLastObject];
613	ASSERT_EQUALS(5, [array count], "%d");
614	ASSERT([[NSNumber numberWithInt:0] isEqual:[array objectAtIndex:0]]);
615	ASSERT([[NSNumber numberWithInt:4] isEqual:[array objectAtIndex:4]]);
616
617	[array insertObject: [NSNumber numberWithInt:6] atIndex: 1];
618	ASSERT_EQUALS(6, [array count], "%d");
619	ASSERT([[NSNumber numberWithInt:6] isEqual:[array objectAtIndex:1]]);
620
621	[array removeObjectAtIndex: 1];
622	ASSERT_EQUALS(5, [array count], "%d");
623	ASSERT([[NSNumber numberWithInt:1] isEqual:[array objectAtIndex:1]]);
624
625	[array replaceObjectAtIndex: 1 withObject: [NSNumber numberWithInt:7]];
626	ASSERT_EQUALS(5, [array count], "%d");
627	ASSERT([[NSNumber numberWithInt:7] isEqual:[array objectAtIndex:1]]);
628
629END_UNITTEST
630
631BEGIN_UNITTEST(PythonTupleAsNSArray)
632	PyObject* aTuple;
633	NSArray* array;
634	NSArray* array2;
635
636	aTuple = Py_BuildValue("(iiiii)", 0, 1, 2, 3, 4);
637	FAIL_IF(aTuple == NULL);
638
639	array = PyObjC_PythonToId(aTuple);
640	FAIL_IF(array == nil);
641
642	/* Check lenght */
643	ASSERT_EQUALS(5, [array count], "%d");
644
645	/* Check basic element access */
646	ASSERT([[NSNumber numberWithInt:0] isEqual:[array objectAtIndex:0]]);
647	ASSERT([[NSNumber numberWithInt:1] isEqual:[array objectAtIndex:1]]);
648	ASSERT([[NSNumber numberWithInt:2] isEqual:[array objectAtIndex:2]]);
649	ASSERT([[NSNumber numberWithInt:3] isEqual:[array objectAtIndex:3]]);
650	ASSERT([[NSNumber numberWithInt:4] isEqual:[array objectAtIndex:4]]);
651
652	/* Check some other methods */
653	array2 = [array arrayByAddingObject: [NSNumber numberWithInt:5]];
654	ASSERT(array2 != nil);
655
656	ASSERT_EQUALS(6, [array2 count], "%d");
657	ASSERT_EQUALS(5, [array count], "%d");
658
659	ASSERT([[NSNumber numberWithInt:0] isEqual:[array2 objectAtIndex:0]]);
660	ASSERT([[NSNumber numberWithInt:1] isEqual:[array2 objectAtIndex:1]]);
661	ASSERT([[NSNumber numberWithInt:2] isEqual:[array2 objectAtIndex:2]]);
662	ASSERT([[NSNumber numberWithInt:3] isEqual:[array2 objectAtIndex:3]]);
663	ASSERT([[NSNumber numberWithInt:4] isEqual:[array2 objectAtIndex:4]]);
664	ASSERT([[NSNumber numberWithInt:5] isEqual:[array2 objectAtIndex:5]]);
665
666	ASSERT([array containsObject:[NSNumber numberWithInt:4]]);
667	ASSERT(![array containsObject:[NSNumber numberWithInt:10]]);
668
669END_UNITTEST
670
671BEGIN_UNITTEST(PythonDictAsNSDictionary)
672	// count, objectForKey:, keyEnumerator
673	// setObject:forKey: removeObjectForKey:
674	PyObject* aDictionary;
675	NSMutableDictionary* dict;
676	NSEnumerator* iter;
677	NSArray* keys;
678
679	aDictionary = Py_BuildValue(
680		"{iiiiiiii}",
681		1, 2,
682		2, 4,
683		3, 6,
684		4, 8
685	);
686	FAIL_IF(aDictionary == NULL);
687
688	dict = PyObjC_PythonToId(aDictionary);
689	FAIL_IF(dict == nil);
690
691	ASSERT_EQUALS(4, [dict count], "%d");
692	ASSERT([
693		[dict objectForKey:[NSNumber numberWithInt:1]]
694			isEqual: [NSNumber numberWithInt: 2]]);
695
696	[dict setObject: [NSNumber numberWithInt:10]
697	      forKey: [NSNumber numberWithInt:5]];
698	ASSERT_EQUALS(5, [dict count], "%d");
699	ASSERT([
700		[dict objectForKey:[NSNumber numberWithInt:5]]
701			isEqual: [NSNumber numberWithInt: 10]]);
702
703	[dict removeObjectForKey: [NSNumber numberWithInt:5]];
704	ASSERT_EQUALS(4, [dict count], "%d");
705
706	iter = [dict keyEnumerator];
707	ASSERT(iter != nil);
708
709	keys = [iter allObjects];
710	ASSERT_EQUALS(4, [keys count], "%d");
711	ASSERT([[keys objectAtIndex:0] isEqual:[NSNumber numberWithInt:1]]);
712	ASSERT([[keys objectAtIndex:1] isEqual:[NSNumber numberWithInt:2]]);
713	ASSERT([[keys objectAtIndex:2] isEqual:[NSNumber numberWithInt:3]]);
714	ASSERT([[keys objectAtIndex:3] isEqual:[NSNumber numberWithInt:4]]);
715
716END_UNITTEST
717
718BEGIN_UNITTEST(NSLogging)
719	/* This is a pretty lame test ...
720	 *
721	 * What this does is tests that the proxies of plain Python objects
722	 * can be logged. This used to be impossible upto (and including)
723	 * release 1.1!
724	 */
725	PyObject* o = (PyObject*)(Py_BuildValue("i", 10)->ob_type);
726	NSObject* value;
727	int fd;
728	int stderr_orig;
729	int r;
730
731	value = PyObjC_PythonToId(o);
732	FAIL_IF(value == nil);
733
734	fd = open("/dev/null", O_WRONLY);
735	ASSERT((fd != -1));
736	stderr_orig = dup(2);
737	ASSERT(stderr_orig != -1);
738	r = dup2(fd, 2);
739	ASSERT(r != -1);
740	NSLog(@"%@", value);
741	r = dup2(stderr_orig, 2);
742	ASSERT(r != -1);
743	r = close(fd);
744	ASSERT(r != -1);
745END_UNITTEST
746
747BEGIN_UNITTEST(FillNSRect)
748
749	struct output {
750		unsigned int before;
751		NSRect rect;
752		unsigned int after;
753	};
754
755
756	PyObject* input;
757	PyObject* v;
758	PyObject* t;
759	struct output output;
760	int r;
761
762	output.before = 0xDEADBEEF;
763	output.after = 0xBEEFDEAD;
764
765	input = PyTuple_New(2);
766	FAIL_IF(input == NULL);
767
768	v= PyTuple_New(2);
769	PyTuple_SetItem(v, 0, PyInt_FromLong(10));
770	PyTuple_SetItem(v, 1, PyInt_FromLong(11));
771
772	t= PyTuple_New(2);
773	PyTuple_SetItem(t, 0, PyInt_FromLong(20));
774	PyTuple_SetItem(t, 1, PyInt_FromLong(21));
775
776	PyTuple_SetItem(input, 0, v);
777	PyTuple_SetItem(input, 1, t);
778
779	r = PyObjC_PythonToObjC(@encode(NSRect), input, &output.rect);
780	FAIL_IF(r < 0);
781
782	Py_DECREF(input);
783
784	ASSERT_EQUALS(output.rect.origin.x, 10, "%d");
785	ASSERT_EQUALS(output.rect.origin.y, 11, "%d");
786	ASSERT_EQUALS(output.rect.size.width, 20, "%d");
787	ASSERT_EQUALS(output.rect.size.height, 21, "%d");
788	ASSERT_EQUALS(output.before, 0xDEADBEEF, "%x");
789	ASSERT_EQUALS(output.after, 0xBEEFDEAD, "%x");
790
791END_UNITTEST
792
793BEGIN_UNITTEST(RemoveFieldNames)
794	char buffer[2048];
795	const char* end;
796	size_t i;
797
798	/* Simple type */
799	memset(buffer, '\xab', sizeof(buffer));
800	end = PyObjCRT_RemoveFieldNames(buffer, "i");
801	ASSERT(end != NULL);
802	ASSERT_STREQUALS(buffer, "i");
803	ASSERT_EQUALS(*end, '\0', "%c");
804	for (i = strlen(buffer)+1; i < sizeof(buffer);i++) {
805		ASSERT_EQUALS(buffer[i], '\xab', "%c");
806	}
807
808	/* Simple struct */
809	memset(buffer, '\xab', sizeof(buffer));
810	end = PyObjCRT_RemoveFieldNames(buffer, "{_NSPoint=\"x1\"f\"y2\"i}");
811	ASSERT(end != NULL);
812	ASSERT_STREQUALS(buffer, "{_NSPoint=fi}");
813	ASSERT_EQUALS(*end, '\0', "%c");
814	for (i = strlen(buffer)+1; i < sizeof(buffer);i++) {
815		ASSERT_EQUALS(buffer[i], '\xab', "%c");
816	}
817
818	memset(buffer, '\xab', sizeof(buffer));
819	end = PyObjCRT_RemoveFieldNames(buffer, "{_NSPoint=fi}");
820	ASSERT(end != NULL);
821	ASSERT_STREQUALS(buffer, "{_NSPoint=fi}");
822	ASSERT_EQUALS(*end, '\0', "%c");
823	for (i = strlen(buffer)+1; i < sizeof(buffer);i++) {
824		ASSERT_EQUALS(buffer[i], '\xab', "%c");
825	}
826
827	/* Simple array */
828	memset(buffer, '\xab', sizeof(buffer));
829	end = PyObjCRT_RemoveFieldNames(buffer, "[22f]");
830	ASSERT(end != NULL);
831	ASSERT_STREQUALS(buffer, "[22f]");
832	ASSERT_EQUALS(*end, '\0', "%c");
833	for (i = strlen(buffer)+1; i < sizeof(buffer);i++) {
834		ASSERT_EQUALS(buffer[i], '\xab', "%c");
835	}
836
837	memset(buffer, '\xab', sizeof(buffer));
838	end = PyObjCRT_RemoveFieldNames(buffer, "[22{_F=ii}]");
839	ASSERT(end != NULL);
840	ASSERT_STREQUALS(buffer, "[22{_F=ii}]");
841	ASSERT_EQUALS(*end, '\0', "%c");
842	for (i = strlen(buffer)+1; i < sizeof(buffer);i++) {
843		ASSERT_EQUALS(buffer[i], '\xab', "%c");
844	}
845
846	memset(buffer, '\xab', sizeof(buffer));
847	end = PyObjCRT_RemoveFieldNames(buffer, "[22{_F=\"ab\"d\"cd\"d}]");
848	ASSERT(end != NULL);
849	ASSERT_STREQUALS(buffer, "[22{_F=dd}]");
850	ASSERT_EQUALS(*end, '\0', "%c");
851	for (i = strlen(buffer)+1; i < sizeof(buffer);i++) {
852		ASSERT_EQUALS(buffer[i], '\xab', "%c");
853	}
854
855	/* Nested struct */
856	memset(buffer, '\xab', sizeof(buffer));
857	end = PyObjCRT_RemoveFieldNames(buffer, "[22{_F=\"ab\"{_G=\"x\"f\"y\"f}\"cd\"{_G=\"x\"f\"y\"f}}]");
858	ASSERT(end != NULL);
859	ASSERT_STREQUALS(buffer, "[22{_F={_G=ff}{_G=ff}}]");
860	ASSERT_EQUALS(*end, '\0', "%c");
861	for (i = strlen(buffer)+1; i < sizeof(buffer);i++) {
862		ASSERT_EQUALS(buffer[i], '\xab', "%c");
863	}
864
865END_UNITTEST
866
867BEGIN_UNITTEST(UnicodeFunctions)
868	PyObject* unicode = PyUnicode_FromString("hello world");
869	int ok;
870
871	ok = PyObjC_is_ascii_string(unicode, "hello world");
872	ASSERT(ok);
873
874	ok = PyObjC_is_ascii_string(unicode, "hello");
875	ASSERT(!ok);
876
877	ok = PyObjC_is_ascii_string(unicode, "hello world!");
878	ASSERT(!ok);
879
880
881	ok = PyObjC_is_ascii_prefix(unicode, "hello world", 11);
882	ASSERT(ok);
883
884	ok = PyObjC_is_ascii_prefix(unicode, "hello worlk", 11);
885	ASSERT(!ok);
886
887	ok = PyObjC_is_ascii_prefix(unicode, "hello worlk", 10);
888	ASSERT(ok);
889
890	ok = PyObjC_is_ascii_prefix(unicode, "hello", 5);
891	ASSERT(ok);
892
893	ok = PyObjC_is_ascii_prefix(unicode, "hello world!", 12);
894	ASSERT(ok);
895
896END_UNITTEST
897
898static PyMethodDef mod_methods[] = {
899	TESTDEF(CheckNSInvoke),
900
901	TESTDEF(StructSize),
902	TESTDEF(StructAlign),
903	TESTDEF(FillStruct1),
904	TESTDEF(FillStruct2),
905	TESTDEF(FillStruct3),
906	TESTDEF(FillStruct4),
907	TESTDEF(FillStruct5Array),
908	TESTDEF(ExtractStruct1),
909	TESTDEF(ExtractStruct2),
910	TESTDEF(ExtractStruct3),
911	TESTDEF(ExtractStruct4),
912	TESTDEF(ExtractStruct5Array),
913#ifdef _C_BOOL
914	TESTDEF(TestSizeOfBool),
915#endif
916	TESTDEF(TestTypeCode),
917	TESTDEF(TestSimplifySignature),
918	TESTDEF(TestArrayCoding),
919	TESTDEF(PythonListAsNSArray),
920	TESTDEF(PythonTupleAsNSArray),
921	TESTDEF(PythonDictAsNSDictionary),
922	TESTDEF(NSLogging),
923	TESTDEF(FillNSRect),
924	TESTDEF(RemoveFieldNames),
925	TESTDEF(UnicodeFunctions),
926	{ 0, 0, 0, 0 }
927};
928
929#if PY_VERSION_HEX >= 0x03000000
930
931static struct PyModuleDef mod_module = {
932	PyModuleDef_HEAD_INIT,
933	"ctests",
934	NULL,
935	0,
936	mod_methods,
937	NULL,
938	NULL,
939	NULL,
940	NULL
941};
942
943#define INITERROR() return NULL
944#define INITDONE() return m
945
946PyObject* PyInit_ctests(void);
947
948PyObject*
949PyInit_ctests(void)
950
951#else
952
953#define INITERROR() return
954#define INITDONE() return
955
956void initctests(void);
957
958void
959initctests(void)
960#endif
961{
962	PyObject* m;
963
964#if PY_VERSION_HEX >= 0x03000000
965	m = PyModule_Create(&mod_module);
966#else
967	m = Py_InitModule4("ctests", mod_methods,
968		NULL, NULL, PYTHON_API_VERSION);
969#endif
970	if (!m) {
971		INITERROR();
972	}
973
974	if (PyObjC_ImportAPI(m) < 0) {
975		INITERROR();
976	}
977
978	INITDONE();
979}
980