github.com/F4RD1N/gomobile@v1.0.1/bind/objc/SeqTest.m (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build ignore 6 7 #import <Foundation/Foundation.h> 8 #import <XCTest/XCTest.h> 9 #import "testpkg/Testpkg.h" 10 11 // Objective-C implementation of testpkg.I2. 12 @interface Number : NSObject <TestpkgI2> { 13 } 14 @property int32_t value; 15 16 // TODO(hyangah): error:error is not good. 17 - (BOOL)error:(BOOL)e error:(NSError **)error; 18 - (int64_t)times:(int32_t)v; 19 @end 20 21 // numI is incremented when the first numI objective-C implementation is 22 // deallocated. 23 static int numI = 0; 24 25 @implementation Number { 26 } 27 @synthesize value; 28 29 - (NSString *)stringError:(NSString *)s 30 error:(NSError **)error { 31 if ([s isEqualToString:@"number"]) { 32 return @"OK"; 33 } 34 *error = [NSError errorWithDomain:@"SeqTest" code:1 userInfo:@{NSLocalizedDescriptionKey: @"NumberError"}]; 35 return NULL; 36 } 37 38 - (BOOL)error:(BOOL)triggerError error:(NSError **)error { 39 if (!triggerError) { 40 return YES; 41 } 42 if (error != NULL) { 43 *error = [NSError errorWithDomain:@"SeqTest" code:1 userInfo:NULL]; 44 } 45 return NO; 46 } 47 48 - (int64_t)times:(int32_t)v { 49 return v * value; 50 } 51 52 - (void)dealloc { 53 if (self.value == 0) { 54 numI++; 55 } 56 } 57 @end 58 59 // Objective-C implementation of testpkg.NullTest. 60 @interface NullTest : NSObject <TestpkgNullTest> { 61 } 62 63 - (TestpkgNullTest *)null; 64 @end 65 66 @implementation NullTest { 67 } 68 69 - (TestpkgNullTest *)null { 70 return nil; 71 } 72 @end 73 74 // Objective-C implementation of testpkg.InterfaceDupper. 75 @interface IDup : NSObject <TestpkgInterfaceDupper> { 76 } 77 78 @end 79 80 @implementation IDup { 81 } 82 83 - (id<TestpkgInterface>)iDup:(id<TestpkgInterface>)i { 84 return i; 85 } 86 @end 87 88 // Objective-C implementation of testpkg.ConcreteDupper. 89 @interface CDup : NSObject <TestpkgConcreteDupper> { 90 } 91 92 @end 93 94 @implementation CDup { 95 } 96 97 - (TestpkgConcrete *)cDup:(TestpkgConcrete *)c { 98 return c; 99 } 100 @end 101 102 // Objective-C implementation of testpkg.EmptyThrower. 103 @interface EmptyErrorer: NSObject <TestpkgEmptyErrorer> { 104 } 105 106 @end 107 108 @implementation EmptyErrorer { 109 } 110 111 - (BOOL)emptyError:(NSError **)error { 112 *error = [NSError errorWithDomain:@"SeqTest" code:1 userInfo:NULL]; 113 return NO; 114 } 115 @end 116 117 @interface tests : XCTestCase 118 119 @end 120 121 @implementation tests 122 123 - (void)setUp { 124 [super setUp]; 125 } 126 127 - (void)tearDown { 128 [super tearDown]; 129 } 130 131 - (void)testBasics { 132 TestpkgHi(); 133 134 TestpkgInt(42); 135 } 136 137 - (void)testAdd { 138 int64_t sum = TestpkgAdd(31, 21); 139 XCTAssertEqual(sum, 52, @"TestpkgSum(31, 21) = %lld, want 52\n", sum); 140 } 141 142 - (void)testHello:(NSString *)input { 143 NSString *got = TestpkgAppendHello(input); 144 NSString *want = [NSString stringWithFormat:@"Hello, %@!", input]; 145 XCTAssertEqualObjects(got, want, @"want %@\nTestpkgHello(%@)= %@", want, input, got); 146 } 147 148 - (void)testHellos { 149 [self testHello:@"세계"]; // korean, utf-8, world. 150 unichar t[] = { 151 0xD83D, 0xDCA9, 152 }; // utf-16, pile of poo. 153 [self testHello:[NSString stringWithCharacters:t length:2]]; 154 } 155 156 - (void)testString { 157 NSString *input = @""; 158 NSString *got = TestpkgStrDup(input); 159 XCTAssertEqualObjects(got, input, @"want %@\nTestpkgEcho(%@)= %@", input, input, got); 160 161 input = @"FOO"; 162 got = TestpkgStrDup(input); 163 XCTAssertEqualObjects(got, input, @"want %@\nTestpkgEcho(%@)= %@", input, input, got); 164 } 165 166 - (void)testStruct { 167 TestpkgS2 *s = TestpkgNewS2(10.0, 100.0); 168 XCTAssertNotNil(s, @"TestpkgNewS2 returned NULL"); 169 170 double x = [s x]; 171 double y = [s y]; 172 double sum = [s sum]; 173 XCTAssertTrue(x == 10.0 && y == 100.0 && sum == 110.0, 174 @"TestpkgS2(10.0, 100.0).X=%f Y=%f SUM=%f; want 10, 100, 110", x, y, sum); 175 176 double sum2 = TestpkgCallSSum(s); 177 XCTAssertEqual(sum, sum2, @"TestpkgCallSSum(s)=%f; want %f as returned by s.Sum", sum2, sum); 178 179 [s setX:7]; 180 [s setY:70]; 181 x = [s x]; 182 y = [s y]; 183 sum = [s sum]; 184 XCTAssertTrue(x == 7 && y == 70 && sum == 77, 185 @"TestpkgS2(7, 70).X=%f Y=%f SUM=%f; want 7, 70, 77", x, y, sum); 186 187 NSString *first = @"trytwotested"; 188 NSString *second = @"test"; 189 NSString *got = [s tryTwoStrings:first second:second]; 190 NSString *want = [first stringByAppendingString:second]; 191 XCTAssertEqualObjects(got, want, @"TestpkgS_TryTwoStrings(%@, %@)= %@; want %@", first, second, got, want); 192 } 193 194 - (void)testCollectS { 195 @autoreleasepool { 196 [self testStruct]; 197 } 198 199 TestpkgGC(); 200 long numS = TestpkgCollectS2( 201 1, 10); // within 10 seconds, collect the S used in testStruct. 202 XCTAssertEqual(numS, 1, @"%ld S objects were collected; S used in testStruct is supposed to " 203 @"be collected.", 204 numS); 205 } 206 - (void)testBytesAppend { 207 NSString *a = @"Foo"; 208 NSString *b = @"Bar"; 209 NSData *data_a = [a dataUsingEncoding:NSUTF8StringEncoding]; 210 NSData *data_b = [b dataUsingEncoding:NSUTF8StringEncoding]; 211 NSData *gotData = TestpkgBytesAppend(data_a, data_b); 212 NSString *got = [[NSString alloc] initWithData:gotData encoding:NSUTF8StringEncoding]; 213 NSString *want = [a stringByAppendingString:b]; 214 XCTAssertEqualObjects(got, want, @"want %@\nTestpkgBytesAppend(%@, %@) = %@", want, a, b, got); 215 } 216 217 - (void)testInterface { 218 // Test Go object implementing testpkg.I is handled correctly. 219 id<TestpkgI2> goObj = TestpkgNewI(); 220 int64_t got = [goObj times:10]; 221 XCTAssertEqual(got, 100, @"TestpkgNewI().times(10) = %lld; want %d", got, 100); 222 int32_t key = -1; 223 TestpkgRegisterI(key, goObj); 224 int64_t got2 = TestpkgMultiply(key, 10); 225 XCTAssertEqual(got, got2, @"TestpkgMultiply(10 * 10) = %lld; want %lld", got2, got); 226 TestpkgUnregisterI(key); 227 228 // Test Objective-C objects implementing testpkg.I is handled correctly. 229 @autoreleasepool { 230 for (int32_t i = 0; i < 10; i++) { 231 Number *num = [[Number alloc] init]; 232 num.value = i; 233 TestpkgRegisterI(i, num); 234 } 235 TestpkgGC(); 236 } 237 238 // Registered Objective-C objects are pinned on Go side which must 239 // prevent deallocation from Objective-C. 240 for (int32_t i = 0; i < 10; i++) { 241 int64_t got = TestpkgMultiply(i, 2); 242 XCTAssertEqual(got, i * 2,@"TestpkgMultiply(%d, 2) = %lld; want %d", i, got, i * 2); 243 TestpkgUnregisterI(i); 244 TestpkgGC(); 245 } 246 // Unregistered all Objective-C objects. 247 } 248 249 - (void)testCollectI { 250 @autoreleasepool { 251 [self testInterface]; 252 } 253 XCTAssertEqual(numI, 1, @"%d I objects were collected; I used in testInterface is supposed " 254 @"to be collected.", numI); 255 } 256 257 - (void)testConst { 258 XCTAssertEqualObjects(TestpkgAString, @"a string", @"TestpkgAString = %@, want 'a string'", TestpkgAString); 259 XCTAssertEqual(TestpkgAnInt, 7, @"TestpkgAnInt = %lld, want 7", TestpkgAnInt); 260 XCTAssertTrue(ABS(TestpkgAFloat - 0.12345) < 0.0001, @"TestpkgAFloat = %f, want 0.12345", TestpkgAFloat); 261 XCTAssertTrue(TestpkgABool == YES, @"TestpkgABool = %@, want YES", TestpkgAFloat ? @"YES" : @"NO"); 262 XCTAssertEqual(TestpkgMinInt32, INT32_MIN, @"TestpkgMinInt32 = %d, want %d", TestpkgMinInt32, INT32_MIN); 263 XCTAssertEqual(TestpkgMaxInt32, INT32_MAX, @"TestpkgMaxInt32 = %d, want %d", TestpkgMaxInt32, INT32_MAX); 264 XCTAssertEqual(TestpkgMinInt64, INT64_MIN, @"TestpkgMinInt64 = %lld, want %lld", TestpkgMinInt64, INT64_MIN); 265 XCTAssertEqual(TestpkgMaxInt64, INT64_MAX, @"TestpkgMaxInt64 = %lld, want %lld", TestpkgMaxInt64, INT64_MAX); 266 XCTAssertTrue(ABS(TestpkgSmallestNonzeroFloat64 - 267 4.940656458412465441765687928682213723651e-324) < 1e-323, @"TestpkgSmallestNonzeroFloat64 = %f, want %f", 268 TestpkgSmallestNonzeroFloat64, 269 4.940656458412465441765687928682213723651e-324); 270 XCTAssertTrue(ABS(TestpkgMaxFloat64 - 271 1.797693134862315708145274237317043567981e+308) < 0.0001, @"TestpkgMaxFloat64 = %f, want %f", TestpkgMaxFloat64, 272 1.797693134862315708145274237317043567981e+308); 273 XCTAssertTrue(ABS(TestpkgSmallestNonzeroFloat32 - 274 1.401298464324817070923729583289916131280e-45) < 1e-44, @"TestpkgSmallestNonzeroFloat32 = %f, want %f", 275 TestpkgSmallestNonzeroFloat32, 276 1.401298464324817070923729583289916131280e-45); 277 XCTAssertTrue(ABS(TestpkgMaxFloat32 - 3.40282346638528859811704183484516925440e+38) < 0.0001, 278 @"TestpkgMaxFloat32 = %f, want %f", TestpkgMaxFloat32, 3.40282346638528859811704183484516925440e+38); 279 XCTAssertTrue(ABS(TestpkgLog2E - 1 / 0.693147180559945309417232121458176568075500134360255254120680009) < 0.0001, 280 @"TestpkgLog2E = %f, want %f", TestpkgLog2E, 1 / 0.693147180559945309417232121458176568075500134360255254120680009); 281 } 282 283 - (void)testIssue12307 { 284 Number *num = [[Number alloc] init]; 285 num.value = 1024; 286 NSError *error; 287 XCTAssertFalse(TestpkgCallIError(num, YES, &error), @"TestpkgCallIError(Number, YES) succeeded; want error"); 288 NSError *error2; 289 XCTAssertTrue(TestpkgCallIError(num, NO, &error2), @"TestpkgCallIError(Number, NO) failed(%@); want success", error2); 290 } 291 292 - (void)testErrorField { 293 NSString *wantMsg = @"an error message"; 294 NSError *want = [NSError errorWithDomain:@"SeqTest" code:1 userInfo:@{NSLocalizedDescriptionKey: wantMsg}]; 295 TestpkgNode *n = TestpkgNewNode(@"ErrTest"); 296 n.err = want; 297 NSError *got = n.err; 298 XCTAssertEqual(got, want, @"got different objects after roundtrip"); 299 NSString *gotMsg = TestpkgErrorMessage(want); 300 XCTAssertEqualObjects(gotMsg, wantMsg, @"err = %@, want %@", gotMsg, wantMsg); 301 } 302 303 - (void)testErrorDup { 304 NSError *err = Testpkg.globalErr; 305 XCTAssertTrue(TestpkgIsGlobalErr(err), @"A Go error must preserve its identity across the boundary"); 306 XCTAssertEqualObjects([err localizedDescription], @"global err", "A Go error message must be preserved"); 307 } 308 309 - (void)testVar { 310 NSString *s = Testpkg.stringVar; 311 XCTAssertEqualObjects(s, @"a string var", @"Testpkg.StringVar = %@, want 'a string var'", s); 312 s = @"a new string var"; 313 Testpkg.stringVar = s; 314 NSString *s2 = Testpkg.stringVar; 315 XCTAssertEqualObjects(s2, s, @"Testpkg.stringVar = %@, want %@", s2, s); 316 317 int64_t i = Testpkg.intVar; 318 XCTAssertEqual(i, 77, @"Testpkg.intVar = %lld, want 77", i); 319 Testpkg.intVar = 777; 320 i = Testpkg.intVar; 321 XCTAssertEqual(i, 777, @"Testpkg.intVar = %lld, want 777", i); 322 [Testpkg setIntVar:7777]; 323 i = [Testpkg intVar]; 324 XCTAssertEqual(i, 7777, @"Testpkg.intVar = %lld, want 7777", i); 325 326 TestpkgNode *n0 = Testpkg.nodeVar; 327 XCTAssertEqualObjects(n0.v, @"a struct var", @"Testpkg.NodeVar = %@, want 'a struct var'", n0.v); 328 TestpkgNode *n1 = TestpkgNewNode(@"a new struct var"); 329 Testpkg.nodeVar = n1; 330 TestpkgNode *n2 = Testpkg.nodeVar; 331 XCTAssertEqualObjects(n2.v, @"a new struct var", @"Testpkg.NodeVar = %@, want 'a new struct var'", n2.v); 332 333 Number *num = [[Number alloc] init]; 334 num.value = 12345; 335 Testpkg.interfaceVar2 = num; 336 id<TestpkgI2> iface = Testpkg.interfaceVar2; 337 int64_t x = [iface times:10]; 338 int64_t y = [num times:10]; 339 XCTAssertEqual(x, y, @"Testpkg.InterfaceVar2 Times 10 = %lld, want %lld", x, y); 340 } 341 342 - (void)testIssue12403 { 343 Number *num = [[Number alloc] init]; 344 num.value = 1024; 345 346 NSError *error; 347 NSString *ret = TestpkgCallIStringError(num, @"alphabet", &error); 348 XCTAssertNil(ret, @"TestpkgCallIStringError(Number, 'alphabet') succeeded(%@); want error", ret); 349 NSString *desc = [error localizedDescription]; 350 XCTAssertEqualObjects(desc, @"NumberError", @"TestpkgCallIStringError(Number, 'alphabet') returned unexpected error message %@", desc); 351 NSError *error2; 352 NSString *ret2 = TestpkgCallIStringError(num, @"number", &error2); 353 XCTAssertNotNil(ret2, @"TestpkgCallIStringError(Number, 'number') failed(%@); want success", error2); 354 XCTAssertEqualObjects(ret2, @"OK", @"TestpkgCallIStringError(Number, 'number') returned unexpected results %@", ret2); 355 } 356 357 - (void)testStrDup:(NSString *)want { 358 NSString *got = TestpkgStrDup(want); 359 XCTAssertEqualObjects(want, got, @"StrDup returned %@; expected %@", got, want); 360 } 361 362 - (void)testUnicodeStrings { 363 [self testStrDup:@"abcxyz09{}"]; 364 [self testStrDup:@"Hello, 世界"]; 365 [self testStrDup:@"\uffff\U00010000\U00010001\U00012345\U0010ffff"]; 366 } 367 368 - (void)testByteArrayRead { 369 NSData *arr = [NSMutableData dataWithLength:8]; 370 long n; 371 XCTAssertTrue(TestpkgReadIntoByteArray(arr, &n, nil), @"ReadIntoByteArray failed"); 372 XCTAssertEqual(n, 8, @"ReadIntoByteArray wrote %ld bytes, expected %d", n, 8); 373 const uint8_t *b = [arr bytes]; 374 for (int i = 0; i < [arr length]; i++) { 375 XCTAssertEqual(b[i], i, @"ReadIntoByteArray wrote %d at %d; expected %d", b[i], i, i); 376 } 377 // Test that immutable data cannot be changed from Go 378 const uint8_t buf[] = {42}; 379 arr = [NSData dataWithBytes:buf length:1]; 380 XCTAssertTrue(TestpkgReadIntoByteArray(arr, &n, nil), @"ReadIntoByteArray failed"); 381 XCTAssertEqual(n, 1, @"ReadIntoByteArray wrote %ld bytes, expected %d", n, 8); 382 b = [arr bytes]; 383 XCTAssertEqual(b[0], 42, @"ReadIntoByteArray wrote to an immutable NSData; expected no change"); 384 } 385 386 - (void)testNilField { 387 TestpkgNullFieldStruct *s = TestpkgNewNullFieldStruct(); 388 XCTAssertNil([s f], @"NullFieldStruct has non-nil field; expected nil"); 389 } 390 391 - (void)testNullReferences { 392 NullTest *t = [[NullTest alloc] init]; 393 XCTAssertTrue(TestpkgCallWithNull(nil, t), @"Testpkg.CallWithNull failed"); 394 id<TestpkgI> i = TestpkgNewNullInterface(); 395 XCTAssertNil(i, @"NewNullInterface() returned %p; expected nil", i); 396 TestpkgS *s = TestpkgNewNullStruct(); 397 XCTAssertNil(s, @"NewNullStruct() returned %p; expected nil", s); 398 TestpkgIssue20330 *nullArger = TestpkgNewIssue20330(); 399 XCTAssertTrue([nullArger callWithNull:nil], @"Issue20330.CallWithNull failed"); 400 } 401 402 - (void)testReturnsError { 403 NSError *error; 404 NSString *value = TestpkgReturnsError(TRUE, &error); 405 NSString *got = [error.userInfo valueForKey:NSLocalizedDescriptionKey]; 406 NSString *want = @"Error"; 407 XCTAssertEqualObjects(got, want, @"want %@\nTestpkgReturnsError(TRUE) = (%@, %@)", want, value, got); 408 } 409 410 - (void)testImportedPkg { 411 XCTAssertEqualObjects(SecondpkgHelloString, SecondpkgHello(), @"imported string should match"); 412 id<SecondpkgI> i = TestpkgNewImportedI(); 413 SecondpkgS *s = TestpkgNewImportedS(); 414 XCTAssertEqual(8, [i f:8], @"numbers should match"); 415 XCTAssertEqual(8, [s f:8], @"numbers should match"); 416 i = TestpkgWithImportedI(i); 417 s = TestpkgWithImportedS(s); 418 i = [Testpkg importedVarI]; 419 s = [Testpkg importedVarS]; 420 [Testpkg setImportedVarI:i]; 421 [Testpkg setImportedVarS:s]; 422 TestpkgImportedFields *fields = TestpkgNewImportedFields(); 423 i = [fields i]; 424 s = [fields s]; 425 [fields setI:i]; 426 [fields setS:s]; 427 } 428 429 - (void)testRoundTripEquality { 430 Number *want = [[Number alloc] init]; 431 Number *got = (Number *)TestpkgI2Dup(want); 432 XCTAssertEqual(got, want, @"ObjC object passed through Go should not be wrapped"); 433 434 IDup *idup = [[IDup alloc] init]; 435 XCTAssertTrue(TestpkgCallIDupper(idup), @"Go interface passed through ObjC should not be wrapped"); 436 CDup *cdup = [[CDup alloc] init]; 437 XCTAssertTrue(TestpkgCallCDupper(cdup), @"Go struct passed through ObjC should not be wrapped"); 438 } 439 440 - (void)testEmptyError { 441 NSError *error; 442 XCTAssertFalse(TestpkgEmptyError(&error), @"GoTestpkgEmptyError succeeded; want error"); 443 XCTAssertNotNil(error, @"TestpkgEmptyError returned nil error"); 444 id<TestpkgEmptyErrorer> empty = [[EmptyErrorer alloc] init]; 445 XCTAssertFalse(TestpkgCallEmptyError(empty, &error), @"TestpkgCallEmptyError succeeded; want error"); 446 XCTAssertNotNil(error, @"TestpkgCallEmptyError returned nil error"); 447 } 448 449 - (void)testSIGPIPE { 450 TestpkgTestSIGPIPE(); 451 } 452 453 - (void)testTags { 454 XCTAssertEqual(42, TestpkgTaggedConst, @"Tagged const must exist"); 455 } 456 457 - (void)testConstructors { 458 id<TestpkgInterface> i = [[TestpkgConcrete alloc] init]; 459 [i f]; 460 461 TestpkgS2 *s = [[TestpkgS2 alloc] init:1 y:2]; 462 XCTAssertEqual(3.0, [s sum]); 463 XCTAssertEqualObjects(@"gostring", [s tryTwoStrings:@"go" second:@"string"]); 464 465 TestpkgS3 *s3 __attribute__((unused)) = [[TestpkgS3 alloc] init]; 466 467 TestpkgS4 *s4 = [[TestpkgS4 alloc] initWithInt:123]; 468 XCTAssertEqual(123, s4.i); 469 470 s4 = [[TestpkgS4 alloc] initWithFloat: 123.456]; 471 XCTAssertEqual(123, s4.i); 472 473 s4 = [[TestpkgS4 alloc] initWithBoolAndError: false]; 474 XCTAssertEqual(0, s4.i); 475 476 s4 = [[TestpkgS4 alloc] initWithBoolAndError: true]; 477 XCTAssertEqual(s4, NULL); 478 } 479 480 @end