1/* Test/example program for the base library 2 3 Copyright (C) 2005 Free Software Foundation, Inc. 4 5 Copying and distribution of this file, with or without modification, 6 are permitted in any medium without royalty provided the copyright 7 notice and this notice are preserved. 8 9 This file is part of the GNUstep Base Library. 10*/ 11#include <stdio.h> 12#include <Foundation/NSObject.h> 13#include <Foundation/NSConnection.h> 14#include <Foundation/NSPort.h> 15#include <Foundation/NSPortNameServer.h> 16#include <Foundation/NSDistantObject.h> 17#include <Foundation/NSDictionary.h> 18#include <Foundation/NSString.h> 19#include <Foundation/NSRunLoop.h> 20#include <Foundation/NSData.h> 21#include <Foundation/NSDate.h> 22#include <Foundation/NSAutoreleasePool.h> 23#include <Foundation/NSDebug.h> 24#include <Foundation/NSProcessInfo.h> 25#include <Foundation/NSException.h> 26#include <Foundation/NSUserDefaults.h> 27#include <assert.h> 28#include "server.h" 29 30#include "wgetopt.h" 31 32/* 33 * Dummy declaration with different bycopy/byref info from the one 34 * in the server ... we expect the info from the server to be used. 35 */ 36@interface Dummy : NSObject 37- (id) quietBycopy: (byref id)a; 38@end 39 40@interface CallbackClient : NSObject <ClientProtocol> 41- (BOOL) callback; 42@end 43 44@implementation CallbackClient 45- (BOOL) callback 46{ 47 return YES; 48} 49@end 50 51 52@interface Auth : NSObject 53@end 54 55@implementation Auth 56- (BOOL) authenticateComponents: (NSMutableArray*)components 57 withData: (NSData*)authData 58{ 59 unsigned count = [components count]; 60 61 while (count-- > 0) 62 { 63 id obj = [components objectAtIndex: count]; 64 65 if ([obj isKindOfClass: [NSData class]] == YES) 66 { 67 NSMutableData *d = [obj mutableCopy]; 68 unsigned l = [d length]; 69 char *p = (char*)[d mutableBytes]; 70 71 while (l-- > 0) 72 p[l] ^= 42; 73 [components replaceObjectAtIndex: count withObject: d]; 74 RELEASE(d); 75 } 76 } 77 return YES; 78} 79@end 80 81int con_data (id prx) 82{ 83 id pool; 84 BOOL b, br; 85 unsigned char uc, ucr; 86 char c, cr; 87 short s, sr; 88 int i, ir; 89 long l, lr; 90 float flt, fltr; 91 double dbl, dblr; 92 char *str; 93 id obj; 94 small_struct ss = {12}; 95 foo ffoo = {'Z', 1234.5678, 99, "cow", 9876543}; 96 foo bck; 97 98 printf("Testing data sending\n"); 99 100 printf("Boolean:\n"); 101 b = YES; 102 printf(" sending %d", b); 103 br = [prx sendBoolean: b]; 104 printf(" got %d", br); 105 if (b == !br) 106 printf(" ...ok\n"); 107 else 108 printf(" *** ERROR ***\n"); 109 br = b = YES; 110 printf(" sending ptr to %d", br); 111 [prx getBoolean: &br]; 112 printf(" got %d", br); 113 if (b == !br) 114 printf(" ...ok\n"); 115 else 116 printf(" *** ERROR ***\n"); 117 printf(" error is ok (due to incorrect encoding by gcc)\n"); 118 119#define TEST_CALL(test, send, got, sendp, var, varr, val, msg1, msg2) \ 120 pool = [NSAutoreleasePool new]; \ 121 printf(test); \ 122 var = val; \ 123 printf(send, var); \ 124 varr = [prx msg1 var]; \ 125 printf(got, varr); \ 126 if (varr != (var+ADD_CONST)) \ 127 printf(" *** ERROR ***\n"); \ 128 else \ 129 printf(" ...ok\n"); \ 130 varr = var = val+1; \ 131 printf(sendp, varr); \ 132 [prx msg2 &varr]; \ 133 printf(got, varr); \ 134 if (varr != (var+ADD_CONST)) \ 135 printf(" *** ERROR ***\n"); \ 136 else \ 137 printf(" ...ok\n"); \ 138 [pool release]; 139 140#define TEST_FCALL(test, send, got, sendp, var, varr, val, msg1, msg2) \ 141 pool = [NSAutoreleasePool new]; \ 142 printf(test); \ 143 var = val; \ 144 printf(send, var); \ 145 varr = [prx msg1 var]; \ 146 printf(got, varr); \ 147 if (varr - (var+ADD_CONST) > 1e-3) \ 148 printf(" *** ERROR ***\n"); \ 149 else \ 150 printf(" ...ok\n"); \ 151 varr = var = val+1; \ 152 printf(sendp, varr); \ 153 [prx msg2 &varr]; \ 154 printf(got, varr); \ 155 if (varr - (var+ADD_CONST) > 1e-3) \ 156 printf(" *** ERROR ***\n"); \ 157 else \ 158 printf(" ...ok\n"); \ 159 [pool release]; 160 161 TEST_CALL("UChar:\n", " sending %d", " got %d", " sending ptr to %d", 162 uc, ucr, 23, sendUChar:, getUChar:) 163 printf(" error is ok (due to incorrect encoding by gcc)\n"); 164 165 TEST_CALL("Char:\n", " sending %d", " got %d", " sending ptr to %d", 166 c, cr, 23, sendChar:, getChar:) 167 printf(" error is ok (due to incorrect encoding by gcc)\n"); 168 169 TEST_CALL("Short:\n", " sending %hd", " got %hd", " sending ptr to %hd", 170 s, sr, 23, sendShort:, getShort:) 171 172 TEST_CALL("Int:\n", " sending %d", " got %d", " sending ptr to %d", 173 i, ir, 23, sendInt:, getInt:) 174 175 TEST_CALL("Long:\n", " sending %ld", " got %ld", " sending ptr to %ld", 176 l, lr, 23, sendLong:, getLong:) 177 178 TEST_FCALL("Float:\n", " sending %f", " got %f", " sending ptr to %f", 179 flt, fltr, 23.2, sendFloat:, getFloat:) 180 181 TEST_FCALL("Double:\n", " sending %g", " got %g", " sending ptr to %g", 182 dbl, dblr, 23.2, sendDouble:, getDouble:) 183 184 flt = 2.718; 185 dbl = 3.14159265358979323846264338327; 186 printf(" sending double %f, float %f\n", dbl, flt); 187 [prx sendDouble:dbl andFloat:flt]; 188 189 190 pool = [NSAutoreleasePool new]; 191 printf("String:\n"); 192 str = "My String 1"; 193 printf(" sending (%s)", str); 194 str = [prx sendString: str]; 195 printf(" got (%s)\n", str); 196 [pool release]; 197 198 pool = [NSAutoreleasePool new]; 199 str = "My String 3"; 200 printf(" sending ptr to (%s)", str); 201 [prx getString: &str]; 202 printf(" got (%s)\n", str); 203 [pool release]; 204 205 pool = [NSAutoreleasePool new]; 206 printf("Small Struct:\n"); 207 //printf(" sending %x", ss.z); 208 //ss = [prx sendSmallStruct: ss]; 209 //printf(" got %x\n", ss.z); 210 printf(" sending ptr to %x", ss.z); 211 [prx getSmallStruct: &ss]; 212 printf(" got %x\n", ss.z); 213 [pool release]; 214 215#if 1 || !defined(__MINGW__) 216 pool = [NSAutoreleasePool new]; 217 printf("Struct:\n"); 218 memcpy(&bck, &ffoo, sizeof(bck)); 219 printf(" sending c='%c',d=%g,i=%d,s=%s,l=%ld", 220 ffoo.c, ffoo.d, ffoo.i, ffoo.s, ffoo.l); 221 ffoo = [prx sendStruct: ffoo]; 222 printf(" got c='%c',d=%g,i=%d,s=%s,l=%ld\n", 223 ffoo.c, ffoo.d, ffoo.i, ffoo.s, ffoo.l); 224 memcpy(&ffoo, &bck, sizeof(bck)); 225 printf(" sending ptr to c='%c',d=%g,i=%d,s=%s,l=%ld", 226 ffoo.c, ffoo.d, ffoo.i, ffoo.s, ffoo.l); 227 [prx getStruct: &ffoo]; 228 printf(" got c='%c',d=%g,i=%d,s=%s,l=%ld\n", 229 ffoo.c, ffoo.d, ffoo.i, ffoo.s, ffoo.l); 230 [pool release]; 231#endif 232 233 pool = [NSAutoreleasePool new]; 234 printf("Object:\n"); 235 obj = [NSObject new]; 236 [prx addObject: obj]; // FIXME: Why is this needed? 237 printf(" sending %s", [[obj description] cString]); 238 obj = [prx sendObject: obj]; 239 printf(" got %s\n", [[obj description] cString]); 240 printf(" sending ptr to %s", [[obj description] cString]); 241 [prx getObject: &obj]; 242 printf(" got %s\n", [[obj description] cString]); 243 [pool release]; 244 245 printf("Many Arguments:\n"); 246 [prx manyArgs:1 :2 :3 :4 :5 :6 :7 :8 :9 :10 :11 :12]; 247 248 printf("Done\n"); 249 return 0; 250} 251 252int 253con_messages (id prx) 254{ 255 id obj; 256 Protocol *pc = @protocol(ClientProtocol); 257 Protocol *ps = @protocol(ServerProtocol); 258 259 obj = [NSObject new]; 260 261 printf("Conforms to protocol (remote) should be 1: %d\n", 262 [prx conformsToProtocol: ps]); 263 printf("Conforms to protocol (remote) should be 0: %d\n", 264 [prx conformsToProtocol: pc]); 265 266 [prx setProtocolForProxy: ps]; 267 268 printf("Conforms to protocol (local) should be 1: %d\n", 269 [prx conformsToProtocol: ps]); 270 printf("Conforms to protocol (local) should be 0: %d\n", 271 [prx conformsToProtocol: pc]); 272 273 printf("Oneway Void message:\n"); 274 [prx shout]; 275 printf(" ok\n"); 276 277 printf("Testing exception in method with return value:\n"); 278 NS_DURING 279 { 280 [prx exceptionTest1]; 281 printf(" ERROR\n"); 282 } 283 NS_HANDLER 284 { 285 printf(" ok ... %s\n", [[localException description] cString]); 286 } 287 NS_ENDHANDLER 288 289 printf("Testing exception in method with void return:\n"); 290 NS_DURING 291 { 292 [prx exceptionTest2]; 293 printf(" ERROR\n"); 294 } 295 NS_HANDLER 296 { 297 printf(" ok ... %s\n", [[localException description] cString]); 298 } 299 NS_ENDHANDLER 300 301 printf("Testing exception in oneway void method:\n"); 302 NS_DURING 303 { 304 [prx exceptionTest3]; 305 printf(" ok\n"); 306 } 307 NS_HANDLER 308 { 309 printf(" ERROR ... %s\n", [[localException description] cString]); 310 } 311 NS_ENDHANDLER 312 313 /* this next line doesn't actually test callbacks, it tests 314 sending the same object twice in the same message. */ 315 printf("Send same object twice in message\n"); 316 [prx sendObject: prx]; 317 printf(" ok\n"); 318 319 printf("performSelector:\n"); 320 if (prx != [prx performSelector: GSSelectorFromName("self")]) 321 printf(" ERROR\n"); 322 else 323 printf(" ok\n"); 324 325 printf("Testing bycopy/byref:\n"); 326 [prx sendBycopy: obj]; 327 [prx quietBycopy: obj]; 328 329#ifdef _F_BYREF 330 [prx sendByref: obj]; 331 [prx sendByref: @"hello"]; 332 [prx sendByref: [NSDate date]]; 333 { 334 NSMutableString *str = [NSMutableString string]; 335 336 [prx modifyByref: str]; 337 printf(" Modified '%s'\n", [str lossyCString]); 338 } 339#endif 340 printf(" ok\n"); 341 342 printf("Done\n"); 343 return 0; 344} 345 346int 347con_benchmark (id prx) 348{ 349 int i; 350 NSDate *d = [NSDate date]; 351 NSMutableData *sen = [NSMutableData data]; 352 id localObj; 353 id rep; 354 355 printf("Benchmarking\n"); 356 [sen setLength: 100000]; 357 rep = [prx sendObject: sen]; 358 printf(" Sent: 0x%p, Reply: 0x%p, Length: %d\n", sen, rep, [rep length]); 359 360 localObj = [[NSObject alloc] init]; 361 [prx addObject: localObj]; // FIXME: Why is this needed? 362 for (i = 0; i < 10000; i++) 363 { 364#if 0 365 k = [prx count]; 366 for (j = 0; j < k; j++) 367 { 368 id remote_peer_obj = [prx objectAt: j]; 369 } 370#endif 371 [prx echoObject: localObj]; 372 } 373 374 printf(" Delay is %f\n", [d timeIntervalSinceNow]); 375 printf("Done\n"); 376 return 0; 377} 378 379int 380con_statistics (id prx) 381{ 382 int j; 383 id localObj, cobj, a, o; 384 385 printf("------------------------------------------------------------\n"); 386 printf("Printing Statistics\n"); 387 localObj = [[NSObject alloc] init]; 388 [prx outputStats: localObj]; 389 printf(" >>list proxy's hash is 0x%d\n", [prx hash]); 390 printf(" >>list proxy's self is 0x%p = 0x%p\n", [prx self], prx); 391 printf(" >>proxy's description is (%s)\n", [[prx description] lossyCString]); 392 393 cobj = [prx connectionForProxy]; 394 o = [cobj statistics]; 395 a = [o allKeys]; 396 397 for (j = 0; j < [a count]; j++) 398 { 399 id k = [a objectAtIndex:j]; 400 id v = [o objectForKey:k]; 401 402 printf(" %s - %s\n", [k cString], [[v description] cString]); 403 } 404 printf("------------------------------------------------------------\n"); 405 406 return 0; 407} 408 409int 410con_loop (id prx) 411{ 412 NSAutoreleasePool *arp; 413 id cobj; 414 415 arp = [NSAutoreleasePool new]; 416 [prx addObject: [NSObject new]]; // So loss of this connection is logged. 417 cobj = [prx connectionForProxy]; 418 printf("%d\n", [cobj retainCount]); 419 printf("%s\n", [[[cobj statistics] description] cString]); 420 //printf("%s\n", GSDebugAllocationList(YES)); 421 422 printf("loop left running idle for 30 seconds\n"); 423 [[NSRunLoop currentRunLoop] runUntilDate: 424 [NSDate dateWithTimeIntervalSinceNow: 30]]; 425 [cobj invalidate]; 426 [arp release]; 427 return 0; 428} 429 430int 431con_objects (id prx) 432{ 433 int j, k; 434 id localObj; 435 436 localObj = [NSObject new]; 437 [prx addObject:localObj]; 438 k = [prx count]; 439 for (j = 0; j < k; j++) 440 { 441 id remote_peer_obj = [prx objectAt:j]; 442 printf("triangle %d object proxy's hash is 0x%x\n", 443 j, (unsigned)[remote_peer_obj hash]); 444 445#if 0 446 /* xxx look at this again after we use release/retain everywhere */ 447 if ([remote_peer_obj isProxy]) 448 [remote_peer_obj release]; 449#endif 450 remote_peer_obj = [prx objectAt:j]; 451 printf("repeated triangle %d object proxy's hash is 0x%x\n", 452 j, (unsigned)[remote_peer_obj hash]); 453 } 454 return 0; 455} 456 457int 458con_callback (id prx) 459{ 460 int j, k; 461 id localObj; 462 463 localObj = [CallbackClient new]; 464 [prx registerClient: localObj]; 465 k = 1000; 466 for (j = 0; j < k; j++) 467 { 468 ENTER_POOL 469 [prx unregisterClient: localObj]; 470 [prx registerClient: localObj]; 471 [prx tryClientCallback]; 472 if (j < 10 || j %10 == 0) 473 printf("repeated client registration and callback %d\n", j); 474 LEAVE_POOL 475 } 476 printf("repeated client registration and callback %d\n", j); 477 RELEASE(localObj); 478 return 0; 479} 480 481void 482usage(const char *program) 483{ 484 printf("Usage: %s [-ds] [t|b|m|l|o] [host] [server]\n", program); 485 printf(" -d - Debug connection\n"); 486 printf(" -s - Print Statistics\n"); 487 printf(" -t - Data type test [default]\n"); 488 printf(" -b - Benchmark test\n"); 489 printf(" -m - Messaging test\n"); 490 printf(" -l - Loop test\n"); 491 printf(" -o - Objects test\n"); 492 printf(" -c - Connect test\n"); 493 printf(" -r - Registration and callback test\n"); 494} 495 496typedef enum { 497 NO_TEST, TYPE_TEST, BENCHMARK_TEST, MESSAGE_TEST, 498 LOOP_TEST, OBJECT_TEST, CONNECT_TEST, CALLBACK_TEST 499} test_t; 500 501int main (int argc, char *argv[], char **env) 502{ 503 int c, debug, stats; 504 test_t type_test; 505 id cobj, prx; 506 unsigned connect_attempts; 507 NSAutoreleasePool *arp; 508 NSPortNameServer *ns; 509 Auth *auth; 510#if !defined(__MINGW__) 511 extern int optind; 512 extern char *optarg; 513#endif 514 515 [NSProcessInfo initializeWithArguments: argv count: argc environment: env]; 516 arp = [NSAutoreleasePool new]; 517 auth = [Auth new]; 518 GSDebugAllocationActive(YES); 519 520 setvbuf(stdout, 0, _IONBF, 0); 521 debug = 0; 522 type_test = 0; 523 stats = 0; 524 while ((c = wgetopt(argc, argv, "hdtbmslocr")) != EOF) 525 switch (c) 526 { 527 case 'd': 528 debug++; 529 break; 530 case 't': 531 type_test = TYPE_TEST; 532 break; 533 case 'b': 534 type_test = BENCHMARK_TEST; 535 break; 536 case 'm': 537 type_test = MESSAGE_TEST; 538 break; 539 case 's': 540 stats = 1; 541 break; 542 case 'l': 543 type_test = LOOP_TEST; 544 break; 545 case 'o': 546 type_test = OBJECT_TEST; 547 break; 548 case 'c': 549 type_test = CONNECT_TEST; 550 break; 551 case 'r': 552 type_test = CALLBACK_TEST; 553 break; 554 case 'h': 555 usage(argv[0]); 556 exit(0); 557 break; 558 default: 559#if 0 560 usage(argv[0]); 561 exit(1); 562#endif 563 break; 564 } 565 if (type_test == NO_TEST) 566 type_test = TYPE_TEST; 567 568 if (type_test == CONNECT_TEST) 569 connect_attempts = 100000; 570 else 571 connect_attempts = 1; 572 573 if (debug > 0) 574 { 575 [NSConnection setDebug: debug]; 576 [NSDistantObject setDebug: debug]; 577 [NSObject enableDoubleReleaseCheck: YES]; 578 } 579 580 ns = [NSSocketPortNameServer sharedInstance]; 581 while (connect_attempts-- > 0) 582 { 583 if (optind < argc) 584 { 585 if (optind+1 < argc) 586 prx = [NSConnection rootProxyForConnectionWithRegisteredName: 587 [NSString stringWithCString: argv[optind+1]] 588 host: [NSString stringWithCString:argv[optind]] 589 usingNameServer: ns]; 590 else 591 prx = [NSConnection rootProxyForConnectionWithRegisteredName: 592 @"test2server" 593 host:[NSString stringWithCString:argv[optind]] 594 usingNameServer: ns]; 595 } 596 else 597 prx = [NSConnection rootProxyForConnectionWithRegisteredName: 598 @"test2server" host: @"" 599 usingNameServer: ns]; 600 if (prx == nil) 601 { 602 printf("ERROR: Failed to connect to server\n"); 603 return -1; 604 } 605 if (type_test == CONNECT_TEST) 606 { 607 NSLog(@"Made connection\n"); 608 if (connect_attempts > 0) 609 { 610 RELEASE(arp); 611 arp = [NSAutoreleasePool new]; 612 } 613 } 614 } 615 616#if 1 617 /* Check that we can retain the connection, release the proxy, 618 * and then regain the proxy from the connection. 619 */ 620 cobj = RETAIN([prx connectionForProxy]); 621 RELEASE(arp); 622 arp = [NSAutoreleasePool new]; 623 prx = [cobj rootProxy]; 624 AUTORELEASE(cobj); 625#else 626 cobj = [prx connectionForProxy]; 627#endif 628 629 [cobj setDelegate:auth]; 630 [cobj setRequestTimeout:180.0]; 631 [cobj setReplyTimeout:180.0]; 632 633 [prx print: "This is a message from the client. Starting Tests!"]; 634 635 switch (type_test) 636 { 637 case TYPE_TEST: 638 con_data (prx); 639 break; 640 case BENCHMARK_TEST: 641 con_benchmark (prx); 642 break; 643 case MESSAGE_TEST: 644 con_messages (prx); 645 break; 646 case LOOP_TEST: 647 con_loop (prx); 648 break; 649 case OBJECT_TEST: 650 con_objects (prx); 651 break; 652 case CALLBACK_TEST: 653 con_callback (prx); 654 break; 655 default: 656 break; 657 } 658 659 if (stats) 660 con_statistics (prx); 661 662 [cobj invalidate]; 663 664 [arp release]; 665 return 0; 666} 667