/* copyright 2004 Alexander Malmberg portions: copyright (C) 2003 Free Software Foundation, Inc. Author: Alexander Malmberg Test whether a class is a working concrete subclass of NSString. This file should be included _once_ in a test that wants to test a particular class. */ #import "Testing.h" #import #import #import #import /* This is the main entry point to this file. Call it with a class that's supposed to be a concrete NSString subclass. */ void TestNSStringClass(Class stringClass); /* Solaris, in particular, can't handle a NULL string in a printf statement */ #define FORMAT_STRING(str) ((str) ? str : "NULL") #define IS_VALID_OBJECT(obj) (object_getClass((id)obj) != zombieClass) Class stringClass; /* Basic sanity test. */ BOOL test_initWithCString(void) { NSString *test1 = [[stringClass alloc] initWithCString: "ascii"]; NSString *sanity = @"ascii"; if (!test1) return NO; if (![sanity isEqualToString: test1]) return NO; if (![test1 isEqualToString: sanity]) return NO; if (![test1 isEqual: sanity]) return NO; return YES; } /* Test encoding and decoding in various character encodings. */ void test_encodings_helper(NSStringEncoding encoding, unsigned char *bytes, int bytes_length, unichar *characters, int characters_length) { NSData *encodedData = nil; NSString *decodedString = nil; NSData *referenceData = nil; NSString *referenceString = nil; NSStringEncoding *encodings; const char *enc; encodings = [NSString availableStringEncodings]; if (0 != encodings) { while (*encodings != 0 && *encodings != encoding) { encodings++; } } PASS(encodings != 0 && encoding == *encodings, "String encoding %d is supported", encoding); if (NO == testPassed) { return; } enc = [[NSString localizedNameOfStringEncoding: encoding] UTF8String]; referenceString = [[stringClass alloc] initWithCharacters: characters length: characters_length]; referenceData = [[NSData alloc] initWithBytes: bytes length: bytes_length]; PASS(nil != (decodedString = [[stringClass alloc] initWithData: referenceData encoding: encoding]), "can instantiate string from %s", enc); if (YES == testPassed) { PASS_EQUAL(decodedString, referenceString, "new %s string matches reference", enc); } PASS_EQUAL((encodedData = [referenceString dataUsingEncoding: encoding]), referenceData, "data using encoding %s matches reference data", enc); DESTROY(decodedString); DESTROY(referenceData); DESTROY(referenceString); } void test_encoding(void) { { NSData *d = [[NSData alloc] initWithBytes: "foo" length: 3]; NSString *s = [[stringClass alloc] initWithData: d encoding: 0]; PASS(s == nil, "-initWithData:encoding: gives nil for invalid encodings") DESTROY(d); } test_encodings_helper(NSASCIIStringEncoding, (unsigned char[]){65, 66, 67}, 3, (unichar[]){65, 66, 67}, 3); test_encodings_helper(NSUTF8StringEncoding, (unsigned char[]){65, 66, 67}, 3, (unichar[]){65, 66, 67}, 3); test_encodings_helper(NSUTF8StringEncoding, (unsigned char[]){0xc3, 0xa5, 0xc3, 0xa4, 0xc3, 0xb6, 0xd7, 0xa9, 0xd7, 0x9c, 0xd7, 0x95, 0xd7, 0x9d}, 14, (unichar[]){0xe5, 0xe4, 0xf6, 0x5e9, 0x5dc, 0x5d5, 0x5dd}, 7); /* Codepoint U+2F801 CJK Compatiblity Ideograph */ test_encodings_helper(NSUTF8StringEncoding, (unsigned char[]){0xf0, 0xaf, 0xa0, 0x81}, 4, (unichar[]){0xd87e, 0xdc01}, 2); #if defined(GNUSTEP_BASE_LIBRARY) test_encodings_helper(NSISOHebrewStringEncoding, (unsigned char[]){0xf9, 0xec, 0xe5, 0xed}, 4, (unichar[]){0x5e9, 0x5dc, 0x5d5, 0x5dd}, 4); #endif test_encodings_helper(NSISOLatin1StringEncoding, (unsigned char[]){116, 101, 115, 116, 45, 229, 228, 246}, 8, (unichar[]){116, 101, 115, 116, 45, 229, 228, 246}, 8); test_encodings_helper(NSUTF8StringEncoding, (unsigned char[]){0xe0, 0xb8, 0xa0, 0xe0, 0xb8, 0xb2, 0xe0, 0xb8, 0xa9, 0xe0, 0xb8, 0xb2, 0xe0, 0xb9, 0x84, 0xe0, 0xb8, 0x97, 0xe0, 0xb8, 0xa2}, 21, (unichar[]){0xe20, 0xe32, 0xe29, 0xe32, 0xe44, 0xe17, 0xe22}, 7); /* ; (test-data-string ; '(#xc0 #xd2 #xc9 #xd2 #xe4 #xb7 #xc2) 59 ; iso-8859-11, not yet implemented ; '(#xe20 #xe32 #xe29 ; #xe32 #xe44 #xe17 ; #xe22) #t #t) */ #if defined(GNUSTEP_BASE_LIBRARY) test_encodings_helper(NSBIG5StringEncoding, (unsigned char[]){0x41, 0x42, 0x43, 0x20, 0xa7, 0x41, 0xa6, 0x6e, 0x21}, 9, (unichar[]){0x41, 0x42, 0x43, 0x20, 0x4f60, 0x597d, 0x21}, 7); #endif } BOOL test_getCString_maxLength_range_remainingRange(void) { NS_DURING unsigned char *referenceBytes; int referenceBytesLength; NSString *referenceString; unsigned char buffer[16]; NSRange remainingRange; int i, j; BOOL ok = YES; switch ([NSString defaultCStringEncoding]) { case NSUTF8StringEncoding: referenceBytes =(unsigned char []){0x41, 0xc3, 0xa5, 0x42}; referenceBytesLength = 4; referenceString = [stringClass stringWithCharacters: (unichar []){0x41, 0xe5, 0x42} length: 3]; break; default: printf("Have no reference string for c-string encoding %i," " skipping test.\n", [NSString defaultCStringEncoding]); NS_VALUERETURN(YES, BOOL); } for (i = 0; i < referenceBytesLength; i++) { [referenceString getCString: buffer maxLength: i range: NSMakeRange(0, [referenceString length]) remainingRange: &remainingRange]; for (j = 0; j <= i ; j++) if (buffer[j] == 0 || buffer[j] != referenceBytes[j]) break; if (buffer[j]!= 0) { PASS(0, "-getCString: maxLength: %i range: remainingRange: failed", i); ok = NO; } } NS_VALUERETURN(ok, BOOL); NS_HANDLER printf("%s\n", POBJECT(localException)); return NO; NS_ENDHANDLER } void test_return_self_optimizations(void) { NSAutoreleasePool *arp; NSString *string, *returnValue; Class zombieClass = NSClassFromString(@"NSZombie"); arp = [NSAutoreleasePool new]; string = [[stringClass alloc] initWithCharacters: NULL length: 0]; returnValue = [string lowercaseString]; [string release]; PASS((IS_VALID_OBJECT(returnValue) && [@"" isEqual: returnValue]), "-lowercaseString returns a valid instance"); DESTROY(arp); arp = [NSAutoreleasePool new]; string = [[stringClass alloc] initWithCharacters: NULL length: 0]; returnValue = [string uppercaseString]; [string release]; PASS((IS_VALID_OBJECT(returnValue) && [@"" isEqual: returnValue]), "-uppercaseString returns a valid instance"); DESTROY(arp); arp = [NSAutoreleasePool new]; string = [[stringClass alloc] initWithCharacters: NULL length: 0]; returnValue = [string capitalizedString]; [string release]; PASS((IS_VALID_OBJECT(returnValue) && [@"" isEqual: returnValue]), "-capitalizedString returns a valid instance"); DESTROY(arp); arp = [NSAutoreleasePool new]; string = [[stringClass alloc] initWithCharacters: NULL length: 0]; returnValue = [string description]; PASS((IS_VALID_OBJECT(returnValue) && [@"" isEqual: returnValue]), "-description returns a valid instance"); [string release]; DESTROY(arp); arp = [NSAutoreleasePool new]; string = [[stringClass alloc] initWithCharacters: NULL length: 0]; returnValue = [string stringByExpandingTildeInPath]; [string release]; PASS([@"" isEqual: returnValue], "-stringByExpandingTildeInPath returns a valid instance (1)"); DESTROY(arp); arp = [NSAutoreleasePool new]; string = [[stringClass alloc] initWithCharacters: (unichar[]){0x41} length: 1]; returnValue = [string stringByExpandingTildeInPath]; [string release]; PASS((IS_VALID_OBJECT(returnValue) && [@"A" isEqual: returnValue]), "-stringByExpandingTildeInPath returns a valid instance (2)"); DESTROY(arp); arp = [NSAutoreleasePool new]; string = [[stringClass alloc] initWithCharacters: (unichar[]){0x41} length: 1]; returnValue = [string stringByAbbreviatingWithTildeInPath]; [string release]; PASS((IS_VALID_OBJECT(returnValue) && [@"A" isEqual: returnValue]), "-stringByAbbreviatingWithTildeInPath returns a valid instance"); DESTROY(arp); /* TODO: -stringByPaddingToLength:... -stringByResolvingSymlinksInPath -stringByTrimmingCharactersInSet: */ } void TestNSStringClass(Class aStringClass) { NSAutoreleasePool *arp = [NSAutoreleasePool new]; stringClass = aStringClass; PASS(test_initWithCString(), "-initWithCString: works"); test_encoding(); PASS(test_getCString_maxLength_range_remainingRange(), "-getCString:maxLength:range:remainingRange: works"); test_return_self_optimizations(); [arp release]; arp = nil; }