;;; tests (use objc testeez) (require-library typetest) (objc:import-classes-at-toplevel!) (define (epsilon=? a b) (and (not (eqv? a b)) (< (abs (- a b)) 1e-14))) (define (nsstring=? a b) (string=? (objc:nsstring->string a) b)) (testeez "Chicken Objective C bridge" ;; Unimplemented ;; (objc-invoker TypeTest "printInt:Double:Float:" 1.1 2.2 3.3) => prints, returns YES (#\x1) ; (@ TypeTest nextChar: #t) => error: not a character (test/eq "Boolean false return" (@ TypeTest isGreaterThanThree: 1) #f) (test/equal "Boolean true return" (@ TypeTest isGreaterThanThree: 4) #\x1) (test/eq "True scheme predicate" (if (@ TypeTest isGreaterThanThree: 4) 'true 'false) 'true) (test/eq "False scheme predicate" (if (@ TypeTest isGreaterThanThree: 1) 'true 'false) 'false) (test/equal "(uchar)2 returned as character" (@ TypeTest convertIntToUChar: 2) #\x2) (test/equal "(uchar)0 returned as character" (@ TypeTest convertIntToUChar: 0) #\nul) (test/eqv "Int to short" (@ TypeTest convertIntToShort: -1) -1) (test/eqv "Int to ushort" (@ TypeTest convertIntToUShort: -1) 65535) (test/eqv "Int to short" (@ TypeTest convertIntToShort: 32768) -32768) (test/eqv "Int to ushort" (@ TypeTest convertIntToUShort: 32768) 32768) (test/eqv "Double precision" (@ TypeTest returnDoublePlusOneHalf: 2.1) 2.6) (test/equiv "Float precision" (@ TypeTest returnFloatPlusOneHalf: 2.1) 2.59999990463257 (epsilon=?)) (test/equiv "NSString returns a Scheme string" (@ TypeTest returnNSStringHiMom) "hi, mom!" (nsstring=?)) (test/eq "Null object return is #f" (@ TypeTest returnNullObject) #f) (test/eqv "Non-null char" (@ TypeTest nextChar: #\a) #\b) (test/eqv "Boolean true argument" (@ TypeTest isTrue: #t) #\x1) (test/eqv "Boolean false argument" (@ TypeTest isTrue: #f) #f) (test/eqv "Boolean char argument is ok" (@ TypeTest isTrue: #\a) #\x1) ;; -- Note: (@ NSNumber numberWithInt: n) returns the same pointer if you call ;; with identical n. Object only appears to be allocated once for each different value. (test/eqv "NSNumber within an NSArray" (@ (@ (@ NSArray arrayWithObject: (@ NSNumber numberWithInt: 5)) objectAtIndex: 0) isEqual: (@ NSNumber numberWithInt: 5)) #\x1) (test/eqv "NSNumber <" (@ (@ NSNumber numberWithInt: 5) compare: (@ NSNumber numberWithInt: 6)) -1) (test/eqv "NSNumber ==" (@ (@ NSNumber numberWithInt: 5) compare: (@ NSNumber numberWithInt: 5)) 0) (test/eqv "NSNumber >" (@ (@ NSNumber numberWithInt: 5) compare: (@ NSNumber numberWithInt: 4)) 1) (test/equal "Class name" (objc:class-name (@ NSString class)) "NSString") (test/eqv "Class check via toplevel symbol" (@ (@ NSScanner alloc) isKindOfClass: NSScanner) #\x1) (test/eqv "Class check via class method" (@ (@ NSScanner alloc) isKindOfClass: (@ NSScanner class)) #\x1) (test/eqv "Superclass check via symbol" (@ (@ NSScanner alloc) isKindOfClass: NSObject) #\x1) (test/eqv "Sibling (non-isa) class check via symbol" (@ (@ NSScanner alloc) isKindOfClass: NSString) #f) (test/equiv "NSString in/out conversion" (@ (@ NSArray arrayWithObject: "tralfamadore") objectAtIndex: 0) "tralfamadore" (nsstring=?)) (test/equal "Rectangle in/out conversion" @[TypeTest printRect: (ns:make-rect 1 2 3 4)] (ns:make-rect 1.0 2.0 3.0 4.0)) ) ;;; unimplemented ; (@ TypeTest returnIntMinusOne: 0) => -1 ; (@ TypeTest convertIntToUInt: -1) => 4294967295.0 ; (@ TypeTest convertIntToLong: -1) => -1 ; (@ TypeTest convertIntToULong: -1) => 4294967295.0 [prob. 1.84467440737096e+19 on 64-bit] ;; These 3 return integer. ; (@ TypeTest addShort: -1 toUShort: -1) => 65534 ; (@ TypeTest addInt: -1 toUInt: 4294967295.0) => -2 ; (@ TypeTest addLong: -1 toULong: -1) => -2 [likely to be different on 64-bit platform] ;; Should test ns:make-number for correct ObjC type created, when integrated ;; into the bridge. ;; Selector tests ;; (define inv (@ NSInvocation invocationWithMethodSignature: (@ NSScanner methodSignatureForSelector: "alloc"))) ;; (@ inv selector) => #f ;; (@ inv setSelector: "alloc") => void ;; (@ inv selector) => "alloc" ;; Note: In order to get the return value via getReturnValue:, we need to pass in a buffer ;; and also convert the result to a scheme object. We could create a wrapper around ;; ObjcObjRefToScmObj, though we would have to pass in the expected return type. ;; (This is available in [[inv methodSignature] methodReturnType] and the buffer length ;; is available in [[inv methodSignature] methodReturnLength]: ;; (define sig (@ inv methodSignature)) ;; (@ sig methodReturnType) => "@" ;; (@ sig methodReturnLength) => 4 ;; (@ inv invoke) => (void) ;; (@ inv getReturnType: (make-string 4)) ;; fatal: call with pointer argument ;; ;; use locations? values? ;; ;; This is a valid pointer pass which is incorrectly handled by gauche-objc, ;; i.e. a value is not returned thru this pointer. ;; Argument type for first argument is "^v", or void pointer -- not a struct pointer, ;; which gauche expects for return-by-reference but does not check past the ^. ;; (@ (@ inv methodSignatureForSelector: "getReturnValue:") getArgumentTypeAtIndex: 2) ;; Note, we could also use: ;; (cdr (assoc "getReturnValue:" (objc-class-method-list (@ (@ NSInvocation alloc) class)))) ;; to obtain the full signature, "v12@0:4^v8". ; (@ NSString alloc) => Exception ; Did you forget to nest alloc and init? ; *** -length only defined for ; abstract class. Define -[NSPlaceholderString length]! ;; Testing ivar-ref -- create a new NSInvocationFromScheme and have it assign to sig ; (define o (@ (@ NSInvocationFromScheme alloc) initWithTarget: (@ NSScanner alloc) selector: "class")) ; (ivar-ref o inv) => crashes ; (ivar-ref o sig) => # ; (@ (ivar-ref o sig) methodReturnType) => "#" ; (ivar-ref o inv) => suddenly works the second time (after the methodReturnType call) ;; This is an object deallocation problem. When the autorelease pool is eliminated (leaking memory) ;; the problem goes away. The debug output is showing many similar addresses being used multiple ;; times and probably one is not retained correctly or something.