/* * Copyright (c) 2008 - 2010 * Jonathan Schleifer <js@webkeks.org> * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE included in * the packaging of this file. */ #include "config.h" #import "OFString.h" #import "OFArray.h" #import "OFAutoreleasePool.h" #import "OFExceptions.h" #import "TestsAppDelegate.h" static OFString *module = @"OFString"; static OFString* whitespace[] = { @" \r \t\n\t \tasd \t \t\t\r\n", @" \t\t \t\t \t \t" }; @interface EntityHandler: OFObject <OFXMLUnescapingDelegate> @end @implementation EntityHandler - (OFString*)foundUnknownEntityNamed: (OFString*)entity { if ([entity isEqual: @"foo"]) return @"bar"; return nil; } @end @implementation TestsAppDelegate (OFStringTests) - (void)stringTests { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; OFMutableString *s[3]; OFArray *a; int i; EntityHandler *h; s[0] = [OFMutableString stringWithString: @"täs€"]; s[1] = [OFMutableString string]; s[2] = [[s[0] copy] autorelease]; TEST(@"-[isEqual:]", [s[0] isEqual: s[2]] && ![s[0] isEqual: [[[OFObject alloc] init] autorelease]]) TEST(@"-[compare:]", [s[0] compare: s[2]] == OF_ORDERED_SAME && [s[0] compare: @""] != OF_ORDERED_SAME && [@"" compare: @"a"] == OF_ORDERED_ASCENDING && [@"a" compare: @"b"] == OF_ORDERED_ASCENDING && [@"cd" compare: @"bc"] == OF_ORDERED_DESCENDING && [@"ä" compare: @"ö"] == OF_ORDERED_ASCENDING && [@"€" compare: @"ß"] == OF_ORDERED_DESCENDING && [@"aa" compare: @"z"] == OF_ORDERED_ASCENDING) TEST(@"-[caseInsensitiveCompare:]", [@"a" caseInsensitiveCompare: @"A"] == OF_ORDERED_SAME && [@"Ä" caseInsensitiveCompare: @"ä"] == OF_ORDERED_SAME && [@"я" caseInsensitiveCompare: @"Я"] == OF_ORDERED_SAME && [@"€" caseInsensitiveCompare: @"ß"] == OF_ORDERED_DESCENDING && [@"ß" caseInsensitiveCompare: @"→"] == OF_ORDERED_ASCENDING && [@"AA" caseInsensitiveCompare: @"z"] == OF_ORDERED_ASCENDING) TEST(@"-[hash] is the same if -[isEqual:] is YES", [s[0] hash] == [s[2] hash]) TEST(@"-[appendString:] and -[appendCString:]", [s[1] appendCString: "1𝄞"] && [s[1] appendString: @"3"] && [[s[0] appendString: s[1]] isEqual: @"täs€1𝄞3"]) TEST(@"-[length]", [s[0] length] == 7) TEST(@"-[cStringLength]", [s[0] cStringLength] == 13) TEST(@"-[hash]", [s[0] hash] == 0x8AC1EEF6) TEST(@"-[characterAtIndex:]", [s[0] characterAtIndex: 0] == 't' && [s[0] characterAtIndex: 1] == 0xE4 && [s[0] characterAtIndex: 3] == 0x20AC && [s[0] characterAtIndex: 5] == 0x1D11E) EXPECT_EXCEPTION(@"Detect out of range in -[characterAtIndex:]", OFOutOfRangeException, [s[0] characterAtIndex: 7]) TEST(@"-[reverse]", [[s[0] reverse] isEqual: @"3𝄞1€sät"]) s[1] = [OFMutableString stringWithString: @"abc"]; TEST(@"-[upper]", [[s[0] upper] isEqual: @"3𝄞1€SÄT"] && [[s[1] upper] isEqual: @"ABC"]) TEST(@"-[lower]", [[s[0] lower] isEqual: @"3𝄞1€sät"] && [[s[1] lower] isEqual: @"abc"]) TEST(@"+[stringWithCString:length:]", (s[0] = [OFMutableString stringWithCString: "foobar" length: 3]) && [s[0] isEqual: @"foo"]) TEST(@"+[stringWithContentsOfFile:encoding]", (s[1] = [OFString stringWithContentsOfFile: @"testfile.txt" encoding: OF_STRING_ENCODING_ISO_8859_1]) && [s[1] isEqual: @"testäöü"]) TEST(@"-[appendCStringWithLength:]", [[s[0] appendCString: "foobarqux" + 3 withLength: 3] isEqual: @"foobar"]) EXPECT_EXCEPTION(@"Detection of invalid UTF-8 encoding #1", OFInvalidEncodingException, [OFString stringWithCString: "\xE0\x80"]) EXPECT_EXCEPTION(@"Detection of invalid UTF-8 encoding #2", OFInvalidEncodingException, [OFString stringWithCString: "\xF0\x80\x80\xC0"]) TEST(@"-[reverse] on UTF-8 strings", (s[0] = [[OFMutableString stringWithCString: "äöü€𝄞"] reverse]) && [s[0] isEqual: @"𝄞€üöä"]) TEST(@"Conversion of ISO 8859-1 to UTF-8", [[OFString stringWithCString: "\xE4\xF6\xFC" encoding: OF_STRING_ENCODING_ISO_8859_1] isEqual: @"äöü"]) TEST(@"Conversion of ISO 8859-15 to UTF-8", [[OFString stringWithCString: "\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE" encoding: OF_STRING_ENCODING_ISO_8859_15] isEqual: @"€ŠšŽžŒœŸ"]) TEST(@"Conversion of Windows 1252 to UTF-8", [[OFString stringWithCString: "\x80\x82\x83\x84\x85\x86\x87\x88" "\x89\x8A\x8B\x8C\x8E\x91\x92\x93" "\x94\x95\x96\x97\x98\x99\x9A\x9B" "\x9C\x9E\x9F" encoding: OF_STRING_ENCODING_WINDOWS_1252] isEqual: @"€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ"]) TEST(@"+[stringWithFormat:]", [(s[0] = [OFMutableString stringWithFormat: @"%s: %d", "test", 123]) isEqual: @"test: 123"]) TEST(@"+[stringWithPath:]", (s[1] = [OFString stringWithPath: @"foo", @"bar", @"baz", nil]) && #ifndef _WIN32 [s[1] isEqual: @"foo/bar/baz"] && #else [s[1] isEqual: @"foo/bar/baz"] && #endif (s[1] = [OFString stringWithPath: @"foo", nil]) && [s[1] isEqual: @"foo"]) TEST(@"-[appendFormat:]", [([s[0] appendFormat: @"%02X", 15]) isEqual: @"test: 1230F"]) TEST(@"-[indexOfFirstOccurrenceOfString:]", [@"𝄞öö" indexOfFirstOccurrenceOfString: @"öö"] == 1 && [@"𝄞öö" indexOfFirstOccurrenceOfString: @"ö"] == 1 && [@"𝄞öö" indexOfFirstOccurrenceOfString: @"𝄞"] == 0 && [@"𝄞öö" indexOfFirstOccurrenceOfString: @"x"] == SIZE_MAX) TEST(@"-[indexOfLastOccurrenceOfString:]", [@"𝄞öö" indexOfLastOccurrenceOfString: @"öö"] == 1 && [@"𝄞öö" indexOfLastOccurrenceOfString: @"ö"] == 2 && [@"𝄞öö" indexOfLastOccurrenceOfString: @"𝄞"] == 0 && [@"𝄞öö" indexOfLastOccurrenceOfString: @"x"] == SIZE_MAX) TEST(@"-[substringFromIndexToIndex:]", [[@"𝄞öö" substringFromIndex: 1 toIndex: 2] isEqual: @"ö"] && [[@"𝄞öö" substringFromIndex: 3 toIndex: 3] isEqual: @""]) EXPECT_EXCEPTION(@"Detect out of range in " @"-[substringFromIndex:toIndex:] #1", OFOutOfRangeException, [@"𝄞öö" substringFromIndex: 2 toIndex: 4]) EXPECT_EXCEPTION(@"Detect out of range in " @"-[substringFromIndex:toIndex:] #2", OFOutOfRangeException, [@"𝄞öö" substringFromIndex: 4 toIndex: 4]) EXPECT_EXCEPTION(@"Detect start > end in " @"-[substringFromIndex:toIndex:]", OFInvalidArgumentException, [@"𝄞öö" substringFromIndex: 2 toIndex: 0]) TEST(@"-[stringByAppendingString:]", [[@"foo" stringByAppendingString: @"bar"] isEqual: @"foobar"]) TEST(@"-[hasPrefix:]", [@"foobar" hasPrefix: @"foo"] && ![@"foobar" hasPrefix: @"foobar0"]) TEST(@"-[hasSuffix:]", [@"foobar" hasSuffix: @"bar"] && ![@"foobar" hasSuffix: @"foobar0"]) i = 0; TEST(@"-[componentsSeparatedByString:]", (a = [@"fooXXbarXXXXbazXXXX" componentsSeparatedByString: @"XX"]) && [[a objectAtIndex: i++] isEqual: @"foo"] && [[a objectAtIndex: i++] isEqual: @"bar"] && [[a objectAtIndex: i++] isEqual: @""] && [[a objectAtIndex: i++] isEqual: @"baz"] && [[a objectAtIndex: i++] isEqual: @""] && [[a objectAtIndex: i++] isEqual: @""]) TEST(@"-[decimalValueAsInteger]", [@"1234" decimalValueAsInteger] == 1234 && [@"-500" decimalValueAsInteger] == -500 && [@"" decimalValueAsInteger] == 0) TEST(@"-[hexadecimalValueAsInteger]", [@"123f" hexadecimalValueAsInteger] == 0x123f && [@"0xABcd" hexadecimalValueAsInteger] == 0xABCD && [@"xbCDE" hexadecimalValueAsInteger] == 0xBCDE && [@"$CdEf" hexadecimalValueAsInteger] == 0xCDEF && [@"" hexadecimalValueAsInteger] == 0) EXPECT_EXCEPTION(@"Detect invalid characters in " @"-[decimalValueAsInteger] #1", OFInvalidEncodingException, [@"abc" decimalValueAsInteger]) EXPECT_EXCEPTION(@"Detect invalid characters in " @"-[decimalValueAsInteger] #2", OFInvalidEncodingException, [@"0a" decimalValueAsInteger]) EXPECT_EXCEPTION(@"Detect invalid chars in " @"-[hexadecimalValueAsInteger] #1", OFInvalidEncodingException, [@"0xABCDEFG" hexadecimalValueAsInteger]) EXPECT_EXCEPTION(@"Detect invalid chars in " @"-[hexadecimalValueAsInteger] #2", OFInvalidEncodingException, [@"0x" hexadecimalValueAsInteger]) EXPECT_EXCEPTION(@"Detect invalid chars in " @"-[hexadecimalValueAsInteger] #3", OFInvalidEncodingException, [@"$" hexadecimalValueAsInteger]) EXPECT_EXCEPTION(@"Detect out of range in -[decimalValueAsInteger", OFOutOfRangeException, [@"12345678901234567890123456789012345678901234567890" @"12345678901234567890123456789012345678901234567890" decimalValueAsInteger]) EXPECT_EXCEPTION(@"Detect out of range in -[hexadecilamValueAsInteger", OFOutOfRangeException, [@"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" @"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" hexadecimalValueAsInteger]) TEST(@"-[md5Hash]", [[@"asdfoobar" md5Hash] isEqual: @"184dce2ec49b5422c7cfd8728864db4c"]) TEST(@"-[sha1Hash]", [[@"asdfoobar" sha1Hash] isEqual: @"f5f81ac0a8b5cbfdc4585ec1ad32e7b3a12b9b49"]) TEST(@"-[stringByURLEncoding]", [[@"foo\"ba'_~$" stringByURLEncoding] isEqual: @"foo%22ba%27_~%24"]) TEST(@"-[stringByURLDecoding]", [[@"foo%20bar%22+%24" stringByURLDecoding] isEqual: @"foo bar\" $"]) EXPECT_EXCEPTION(@"Detect invalid encoding in -[stringByURLDecoding] " @"#1", OFInvalidEncodingException, [@"foo%bar" stringByURLDecoding]) EXPECT_EXCEPTION(@"Detect invalid encoding in -[stringByURLDecoding] " @"#2", OFInvalidEncodingException, [@"foo%FFbar" stringByURLDecoding]) TEST(@"-[removeCharactersFromIndex:toIndex:]", (s[0] = [OFMutableString stringWithString: @"𝄞öööbä€"]) && [s[0] removeCharactersFromIndex: 1 toIndex: 4] && [s[0] isEqual: @"𝄞bä€"] && [s[0] removeCharactersFromIndex: 0 toIndex: 4] && [s[0] isEqual: @""]) EXPECT_EXCEPTION(@"Detect OoR in " @"-[removeCharactersFromIndex:toIndex:] #1", OFOutOfRangeException, { s[0] = [OFMutableString stringWithString: @"𝄞öö"]; [s[0] substringFromIndex: 2 toIndex: 4]; }) EXPECT_EXCEPTION(@"Detect OoR in " @"-[removeCharactersFromIndex:toIndex:] #2", OFOutOfRangeException, [s[0] substringFromIndex: 4 toIndex: 4]) EXPECT_EXCEPTION(@"Detect s > e in " @"-[removeCharactersFromIndex:toIndex:]", OFInvalidArgumentException, [s[0] substringFromIndex: 2 toIndex: 0]) TEST(@"-[replaceOccurrencesOfString:withString:]", [[[OFMutableString stringWithString: @"asd fo asd fofo asd"] replaceOccurrencesOfString: @"fo" withString: @"foo"] isEqual: @"asd foo asd foofoo asd"] && [[[OFMutableString stringWithString: @"XX"] replaceOccurrencesOfString: @"X" withString: @"XX"] isEqual: @"XXXX"]) TEST(@"-[removeLeadingWhitespaces]", (s[0] = [OFMutableString stringWithString: whitespace[0]]) && [[s[0] removeLeadingWhitespaces] isEqual: @"asd \t \t\t\r\n"] && (s[0] = [OFMutableString stringWithString: whitespace[1]]) && [[s[0] removeLeadingWhitespaces] isEqual: @""]) TEST(@"-[removeTrailingWhitespaces]", (s[0] = [OFMutableString stringWithString: whitespace[0]]) && [[s[0] removeTrailingWhitespaces] isEqual: @" \r \t\n\t \tasd"] && (s[0] = [OFMutableString stringWithString: whitespace[1]]) && [[s[0] removeTrailingWhitespaces] isEqual: @""]) TEST(@"-[removeLeadingAndTrailingWhitespaces]", (s[0] = [OFMutableString stringWithString: whitespace[0]]) && [[s[0] removeLeadingAndTrailingWhitespaces] isEqual: @"asd"] && (s[0] = [OFMutableString stringWithString: whitespace[1]]) && [[s[0] removeLeadingAndTrailingWhitespaces] isEqual: @""]) TEST(@"-[stringByXMLEscaping]", (s[0] = [@"<hello> &world'\"!&" stringByXMLEscaping]) && [s[0] isEqual: @"<hello> &world'"!&"]) TEST(@"-[stringByXMLUnescaping]", [[s[0] stringByXMLUnescaping] isEqual: @"<hello> &world'\"!&"] && [[@"y" stringByXMLUnescaping] isEqual: @"y"] && [[@"ä" stringByXMLUnescaping] isEqual: @"ä"] && [[@"€" stringByXMLUnescaping] isEqual: @"€"] && [[@"𝄞" stringByXMLUnescaping] isEqual: @"𝄞"]) EXPECT_EXCEPTION(@"Detect invalid entities in -[stringByXMLUnescaping] " @"#1", OFInvalidEncodingException, [@"&foo;" stringByXMLUnescaping]) EXPECT_EXCEPTION(@"Detect invalid entities in -[stringByXMLUnescaping] " @"#2", OFInvalidEncodingException, [@"x&" stringByXMLUnescaping]) EXPECT_EXCEPTION(@"Detect invalid entities in -[stringByXMLUnescaping] " @"#3", OFInvalidEncodingException, [@"&#;" stringByXMLUnescaping]) EXPECT_EXCEPTION(@"Detect invalid entities in -[stringByXMLUnescaping] " @"#4", OFInvalidEncodingException, [@"&#x;" stringByXMLUnescaping]) EXPECT_EXCEPTION(@"Detect invalid entities in -[stringByXMLUnescaping] " @"#5", OFInvalidEncodingException, [@"&#g;" stringByXMLUnescaping]) EXPECT_EXCEPTION(@"Detect invalid entities in -[stringByXMLUnescaping] " @"#6", OFInvalidEncodingException, [@"&#xg;" stringByXMLUnescaping]) TEST(@"-[stringByXMLUnescapingWithHandler:]", (h = [[[EntityHandler alloc] init] autorelease]) && (s[0] = [@"x&foo;y" stringByXMLUnescapingWithHandler: h]) && [s[0] isEqual: @"xbary"]) [pool drain]; } @end