// // Created by Larry Campbell on 12/12/08. // #import #import "ObjectTesting.h" @interface GnustepBaseTests : NSObject { unsigned _successes; unsigned _failures; } @end @implementation GnustepBaseTests - (BOOL) performTest: (NSString *)name { NSAutoreleasePool *pool = [NSAutoreleasePool new]; BOOL result; NSLog(@"Performing test %@", name); NS_DURING { [self performSelector: NSSelectorFromString(name)]; _successes++; result = YES; } NS_HANDLER { NSLog(@"Test %@ failed: %@", name, [localException reason]); _failures++; result = NO; } NS_ENDHANDLER [pool release]; return result; } - (unsigned) successes { return _successes; } - (unsigned) failures { return _failures; } @end @interface GnustepBaseTests(TheTests) @end @implementation GnustepBaseTests(TheTests) - (void) cr39118 { int x = 1999999999; NSString *s = @"1999999999"; NSAssert([s intValue] == x, @"intValue botch"); } // verify that distinct strings get distinct hashes even if strings are very long - (void) cr48439 { NSMutableSet *hashes = [NSMutableSet set]; NSArray *strings = [NSArray arrayWithObjects: @"", @"a", @"aa", @"123456789012345678901234567890123456789012345678901234567890123", @"123456789012345678901234567890123456789012345678901234567890123a", @"123456789012345678901234567890123456789012345678901234567890123b", @"123456789012345678901234567890123456789012345678901234567890123c", @"123456789012345678901234567890123456789012345678901234567890123d", @"1234567890123456789012345678901234567890123456789012345678901234", @"1234567890123456789012345678901234567890123456789012345678901234a", @"1234567890123456789012345678901234567890123456789012345678901234b", @"1234567890123456789012345678901234567890123456789012345678901234c", @"1234567890123456789012345678901234567890123456789012345678901234d", @"12345678901234567890123456789012345678901234567890123456789012345", @"12345678901234567890123456789012345678901234567890123456789012345a", @"12345678901234567890123456789012345678901234567890123456789012345b", @"12345678901234567890123456789012345678901234567890123456789012345c", @"12345678901234567890123456789012345678901234567890123456789012345d", @"123456789012345678901234567890123456789012345678901234567890123456789012345", @"123456789012345678901234567890123456789012345678901234567890123456789012345a", @"123456789012345678901234567890123456789012345678901234567890123456789012345b", @"123456789012345678901234567890123456789012345678901234567890123456789012345c", @"123456789012345678901234567890123456789012345678901234567890123456789012345d", nil]; NSString *s; NSEnumerator *e; e = [strings objectEnumerator]; while ((s = [e nextObject]) != nil) [hashes addObject:[NSNumber numberWithUnsignedInt:[s hash]]]; NSAssert([hashes count] == [strings count], @"hash botch"); } // this also covers CR 150661 - (void)cr153594 { NSDate *t1 = [NSDate date]; NSDate *t2; NSData *d; d = [NSKeyedArchiver archivedDataWithRootObject: t1]; t2 = [NSKeyedUnarchiver unarchiveObjectWithData: d]; NSAssert([t1 isEqual:t2], @"equality botch"); } - (void)cr1524466 { NSURL *u = [[[NSURL alloc] initWithScheme: @"http" host: @"1.2.3.4" path: @"/a?b;foo"] autorelease]; NSString *s = [[u absoluteURL] description]; NSAssert([s isEqual: @"http://1.2.3.4/a?b;foo"], @"NSURL encoding botch"); } - (void)cr2096767 { static struct { NSString *inputString; NSTimeInterval increment; NSString *expectedOutput; } tests[] = { { @"2006-04-22 22:22:22:901", 0.0, @"2006-04-22 22:22:22:901" }, // gnustep bug https://savannah.gnu.org/bugs/?func=detailitem&item_id=16426 { @"2006-04-22 22:22:22:999", 0.0, @"2006-04-22 22:22:22:999" }, { @"2006-04-22 22:22:22:999", 0.0005, @"2006-04-22 22:22:22:999" }, { @"2006-04-22 22:22:22:999", 0.0006, @"2006-04-22 22:22:22:999" }, { @"2006-04-22 22:22:22:999", 0.0007, @"2006-04-22 22:22:22:999" }, { @"2006-04-22 22:22:22:999", 0.0008, @"2006-04-22 22:22:22:999" }, { @"2006-04-22 22:22:22:999", 0.00089, @"2006-04-22 22:22:22:999" }, { @"2006-04-22 22:22:22:999", 0.000899, @"2006-04-22 22:22:22:999" }, { @"2006-04-22 22:22:22:999", 0.0008999, @"2006-04-22 22:22:22:999" }, { @"2006-04-22 22:22:22:999", 0.00089999, @"2006-04-22 22:22:23:000" }, { @"2006-04-22 22:22:22:999", 0.0009, @"2006-04-22 22:22:23:000" }, // CR https://bugzilla.akamai.com/show_bug.cgi?id=2096767 }; unsigned i; NSString *fmt = [NSString stringWithFormat: @"%%Y-%%m-%%d %%H:%%M:%%S:%%F"]; for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { NSString *inputString = tests[i].inputString; NSString *expectedOutput = tests[i].expectedOutput; NSCalendarDate *d1 = [NSCalendarDate dateWithString:inputString calendarFormat:fmt]; NSCalendarDate *d2 = [[[NSCalendarDate alloc] initWithTimeInterval:tests[i].increment sinceDate:d1] autorelease]; NSString *result = [d2 descriptionWithCalendarFormat:fmt]; NSLog(@"input string: %@, increment: %.4f", inputString, tests[i].increment); NSLog(@"input date: %@", d1); NSLog(@"output date: %@", result); NSLog(@"expect: %@", expectedOutput); NSAssert([result isEqualToString:expectedOutput], @"mismatch"); } } - (void)cr2549370 { NSString *path = @"./json.data"; NSString *string = @"Hello garçon! ¡Ola! A little more coöperation please!"; NSMutableDictionary *dict = [NSMutableDictionary dictionary]; NSMutableArray *array = [NSMutableArray array]; NSData *d; NSInputStream *stream; [array addObject:[NSDictionary dictionaryWithObjectsAndKeys:string, @"nickname", nil]]; [dict setObject:array forKey: @"datacenters"]; d = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:0]; [d writeToFile:path atomically:NO]; stream = [NSInputStream inputStreamWithFileAtPath:path]; [stream open]; dict = [NSJSONSerialization JSONObjectWithStream:stream options:0 error:0]; dict = [[dict objectForKey: @"datacenters"] objectAtIndex:0]; [[NSFileManager defaultManager] removeFileAtPath: path handler: nil]; NSAssert(dict != nil, @"JSON returned nil"); NSAssert([string isEqualToString:[dict objectForKey: @"nickname"]], @"data mismatch"); } void checkstr(NSString *expected, NSString *got) { if ([expected caseInsensitiveCompare:got] != NSOrderedSame) { NSLog(@"expected %@", expected); NSLog(@" got %@", got); [NSException raise: @"error" format: @"test failed"]; } } // This is copied from servermonitor. We want to use the same quoting rules it does. // We use this only for the username and password; we assume the path/query/fragment // is already escaped. static NSString *percentQuoted(NSString *s) { NSMutableString *retval = [NSMutableString stringWithCapacity:[s length]]; const unsigned char *p = (const unsigned char *)[s UTF8String]; unsigned char c; const char *allowedNonalnumChars = "-_,.'~!$&*();"; while ((c = *p++) != '\0') { if (isalnum(c) || strchr(allowedNonalnumChars, c) != 0) { [retval appendFormat: @"%c", c]; } else { [retval appendFormat: @"%%%02x", c]; } } return retval; } - (void)urlTest { static NSString *schemes[] = { @"ftp", @"http", @"https" }; static NSString *hosts[] = { @"www.akamai.com", @"10.0.1.1", @"localhost" }; static NSString *usernames[] = { nil, @"username", @"foo", @"a_username" }; static NSString *passwords[] = { nil, @"password", @"M@nx2y#" }; // The path/query/fragment part here must be percent-quoted // as it would have to be if pasted into a curl command. struct { NSString *pqf; // path, query, fragment NSString *path; // expected path returned from NSURL (nil if same as pqf) } pqfs[] = { { @"/", nil }, { @"/foo/bar/zot", nil }, { @"/a%20dillar%20a%20dollar", nil }, { @"/foo:bar:zot", nil }, { @"/a?b;foo", @"/a" }, { @"/a%25b", nil }, { @"/MHcwdTBOMEwwSjAJBgUrDgMCGgUABBScDhI23ZEqCpe2zGqbkoJVvUaDTgQUf/ZMNigUrs0eN6/eWvJbw6CsK/4CEQCbL3Mm0kXS8q7t0jI7E5gdoiMwITAfBgkrBgEFBQcwAQIEEgQQi7kTQMz7QK60KI2PnRR3mg==", nil }, { @"/interface/6/?mode=rc3&outputType=json&url=http%3A%2F%2Fwww.ehow.com%2Fhow_2324118_take-care-paper-cut.html&category=Health&subCategory=Family%20Health&subSubCategory=General%20Family%20Health&pageLocations=PLATFORM_TL|0&flushPage=1", @"/interface/6" }, { @"/d/search/p/enom/xml/domain/multiset/v4/?url=http%3A%2F%2Fnuseek.com&Partner=enom_internal_d2r_derp&config=1234567890&affilData=ip%3d127.0.0.1%26ua%3dIE|6.0|WinNT%26ur%3d&maxListings=10&maxRT=20&maxRTL=20&maxWeb=4&serveUrl=http://parkingweb30/default.pk", @"/d/search/p/enom/xml/domain/multiset/v4" }, }; unsigned i, j, k, l, m; for (i = 0; i < sizeof(schemes)/sizeof(schemes[0]); i++) { NSString *scheme = schemes[i]; for (j = 0; j < sizeof(hosts)/sizeof(hosts[0]); j++) { NSString *host = hosts[j]; for (k = 0; k < sizeof(usernames)/sizeof(usernames[0]); k++) { NSString *username = usernames[k]; for (l = 0; l < sizeof(passwords)/sizeof(passwords[0]); l++) { NSString *password = passwords[l]; for (m = 0; m < sizeof(pqfs)/sizeof(pqfs[0]); m++) { NSMutableString *hostpart = [NSMutableString string]; NSString *pqf = pqfs[m].pqf; NSString *expectedPath = [(pqfs[m].path == nil ? pqf : pqfs[m].path) stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSString *urlstring; NSURL *url; expectedPath = [(pqfs[m].path == nil ? pqf : pqfs[m].path) stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; if (username != nil) { if (password != nil) { [hostpart appendFormat: @"%@:%@@", percentQuoted(username), percentQuoted(password)]; } else { [hostpart appendFormat: @"%@@", percentQuoted(username)]; } } [hostpart appendString:host]; urlstring = [NSString stringWithFormat: @"%@://%@%@", scheme, hostpart, pqf]; url = [[[NSURL alloc] initWithString: urlstring] autorelease]; // work around Apple bug, which rejects // objects containing vertical bar (turns out // gnustep is bug-for-bug compatible here, // so no need to make this Apple-only) if (url == nil && [pqf rangeOfString: @"|"].length != 0) { NSMutableString *fixedObject = [[pqf mutableCopy] autorelease]; unsigned n; do { n = [fixedObject replaceOccurrencesOfString: @"|" withString: @"%7C" options:0 range:NSMakeRange(0, [fixedObject length])]; } while (n != 0); urlstring = [NSString stringWithFormat: @"%@://%@%@", scheme, hostpart, fixedObject]; url = [[[NSURL alloc] initWithString:urlstring] autorelease]; } NSAssert(url != nil, @"URL creation failed"); NSAssert([[url scheme] isEqual:schemes[i]], @"scheme botch"); NSAssert((username == nil) == ([url user] == nil), @"username existence botch"); if (username != nil) { NSAssert([[url user] isEqual:username], @"username botch"); NSAssert((password == nil) == ([url password] == nil), @"password existence botch"); if (password != nil) { NSString *urlpassword = [[url password] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSAssert([urlpassword isEqual:password], @"password botch"); } } checkstr(expectedPath, [url path]); checkstr(urlstring, [[url absoluteURL] description]); NSAssert([[url host] isEqual:host], @"host botch"); NSAssert([[url path] isEqual:expectedPath], @"path botch"); } } } } } } - (void)longLongOverflow { NSNumber *big = [NSNumber numberWithUnsignedLongLong: 0xffffffffffffffff]; NSNumber *small = [NSNumber numberWithLongLong: 0xffffffffffffffff]; NSData *data = [NSJSONSerialization dataWithJSONObject: big options: 0 error: NULL]; NSString *string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; NSAssert([string isEqualToString:@"18446744073709551615"], @"unsigned long long"); [string release]; data = [NSJSONSerialization dataWithJSONObject: small options: 0 error: NULL]; string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; NSAssert([string isEqualToString:@"-1"], @"signed long long"); [string release]; } @end int main(int argc, char *argv[]) { int status = 0; NSAutoreleasePool *pool = [NSAutoreleasePool new]; GnustepBaseTests *gtb = [GnustepBaseTests new]; PASS([gtb performTest: @"cr39118"], "cr39118"); PASS([gtb performTest: @"cr48439"], "cr48439"); PASS([gtb performTest: @"cr153594"], "cr153594"); PASS([gtb performTest: @"urlTest"], "urlTest"); PASS([gtb performTest: @"cr1524466"], "cr1524466"); PASS([gtb performTest: @"cr2096767"], "cr2096767"); PASS([gtb performTest: @"cr2549370"], "cr2549370"); PASS([gtb performTest: @"longLongOverflow"], "longLongOverflow"); [gtb release]; [pool release]; return status; }