/* * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im> * * 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.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #include <string.h> #import "OFMutableStringTests.h" @interface CustomMutableString: OFMutableString { OFMutableString *_string; } @end static OFString *const whitespace[] = { @" \r \t\n\t \tasd \t \t\t\r\n", @" \t\t \t\t \t \t" }; @implementation OFMutableStringTests - (Class)stringClass { return [CustomMutableString class]; } - (void)setUp { [super setUp]; _mutableString = [[self.stringClass alloc] initWithString: @"täṠ€🤔"]; } - (void)dealloc { [_mutableString release]; [super dealloc]; } - (void)testAppendString { [_mutableString appendString: @"ö"]; OTAssertEqualObjects(_mutableString, @"täṠ€🤔ö"); } - (void)testAppendUTF8String { [_mutableString appendUTF8String: "ö"]; OTAssertEqualObjects(_mutableString, @"täṠ€🤔ö"); } - (void)testAppendUTF8StringLength { [_mutableString appendUTF8String: "\xEF\xBB\xBF" "öÖ" length: 7]; OTAssertEqualObjects(_mutableString, @"täṠ€🤔öÖ"); } - (void)testAppendFormat { [_mutableString appendFormat: @"%02X", 15]; OTAssertEqualObjects(_mutableString, @"täṠ€🤔0F"); } - (void)testAppendCharactersLength { [_mutableString appendCharacters: (OFUnichar []){ 0xF6, 0xD6 } length: 2]; OTAssertEqualObjects(_mutableString, @"täṠ€🤔öÖ"); } - (void)testUppercase { [_mutableString uppercase]; #ifdef OF_HAVE_UNICODE_TABLES OTAssertEqualObjects(_mutableString, @"TÄṠ€🤔"); #else OTAssertEqualObjects(_mutableString, @"TäṠ€🤔"); #endif } - (void)testLowercase { [_mutableString lowercase]; #ifdef OF_HAVE_UNICODE_TABLES OTAssertEqualObjects(_mutableString, @"täṡ€🤔"); #else OTAssertEqualObjects(_mutableString, @"täṠ€🤔"); #endif } - (void)testCapitalize { OFMutableString *string = [self.stringClass stringWithString: @"täṠ€🤔täṠ€🤔 täṠ€🤔"]; [string capitalize]; #ifdef OF_HAVE_UNICODE_TABLES OTAssertEqualObjects(string, @"Täṡ€🤔täṡ€🤔 Täṡ€🤔"); #else OTAssertEqualObjects(string, @"TäṠ€🤔täṠ€🤔 TäṠ€🤔"); #endif } - (void)testInsertStringAtIndex { [_mutableString insertString: @"fööbär" atIndex: 2]; OTAssertEqualObjects(_mutableString, @"täfööbärṠ€🤔"); } - (void)testSetCharacterAtIndex { [_mutableString setCharacter: 0x1F600 atIndex: 2]; OTAssertEqualObjects(_mutableString, @"tä😀€🤔"); } - (void)testDeleteCharactersInRange { [_mutableString deleteCharactersInRange: OFMakeRange(2, 2)]; OTAssertEqualObjects(_mutableString, @"tä🤔"); } - (void)testDeleteCharactersInRangeThrowsWithOutOfRangeRange { OTAssertThrowsSpecific( [_mutableString deleteCharactersInRange: OFMakeRange(4, 2)], OFOutOfRangeException); OTAssertThrowsSpecific( [_mutableString deleteCharactersInRange: OFMakeRange(5, 1)], OFOutOfRangeException); OTAssertThrowsSpecific( [_mutableString deleteCharactersInRange: OFMakeRange(6, 0)], OFOutOfRangeException); } - (void)testReplaceCharactersInRangeWithString { OFMutableString *string = [self.stringClass stringWithString: @"𝄞öööbä€"]; [string replaceCharactersInRange: OFMakeRange(1, 3) withString: @"äöüß"]; OTAssertEqualObjects(string, @"𝄞äöüßbä€"); [string replaceCharactersInRange: OFMakeRange(4, 2) withString: @"b"]; OTAssertEqualObjects(string, @"𝄞äöübä€"); [string replaceCharactersInRange: OFMakeRange(0, 7) withString: @""]; OTAssertEqualObjects(string, @""); } - (void)testReplaceCharactersInRangeWithStringFailsWithOutOfRangeRange { OTAssertThrowsSpecific( [_mutableString replaceCharactersInRange: OFMakeRange(4, 2) withString: @"abc"], OFOutOfRangeException); OTAssertThrowsSpecific( [_mutableString replaceCharactersInRange: OFMakeRange(5, 1) withString: @"abc"], OFOutOfRangeException); OTAssertThrowsSpecific( [_mutableString replaceCharactersInRange: OFMakeRange(6, 0) withString: @""], OFOutOfRangeException); } - (void)testReplaceOccurrencesOfStringWithString { OFMutableString *string; string = [self.stringClass stringWithString: @"asd fo asd fofo asd"]; [string replaceOccurrencesOfString: @"fo" withString: @"foo"]; OTAssertEqualObjects(string, @"asd foo asd foofoo asd"); string = [self.stringClass stringWithString: @"XX"]; [string replaceOccurrencesOfString: @"X" withString: @"XX"]; OTAssertEqualObjects(string, @"XXXX"); } - (void)testReplaceOccurrencesOfStringWithStringOptionsRange { OFMutableString *string = [self.stringClass stringWithString: @"foofoobarfoobarfoo"]; [string replaceOccurrencesOfString: @"oo" withString: @"óò" options: 0 range: OFMakeRange(2, 15)]; OTAssertEqualObjects(string, @"foofóòbarfóòbarfoo"); } - (void) testReplaceOccurrencesOfStringWithStringOptionsRangeThrowsWithOutOfRangeRange { OTAssertThrowsSpecific( [_mutableString replaceOccurrencesOfString: @"t" withString: @"abc" options: 0 range: OFMakeRange(4, 2)], OFOutOfRangeException); OTAssertThrowsSpecific( [_mutableString replaceOccurrencesOfString: @"t" withString: @"abc" options: 0 range: OFMakeRange(5, 1)], OFOutOfRangeException); OTAssertThrowsSpecific( [_mutableString replaceOccurrencesOfString: @"t" withString: @"" options: 0 range: OFMakeRange(6, 0)], OFOutOfRangeException); } - (void)deleteLeadingWhitespaces { OFMutableString *string; string = [self.stringClass stringWithString: whitespace[0]]; [string deleteLeadingWhitespaces]; OTAssertEqualObjects(string, @"asd \t \t\t\r\n"); string = [self.stringClass stringWithString: whitespace[1]]; [string deleteLeadingWhitespaces]; OTAssertEqualObjects(string, @""); } - (void)deleteTrailingWhitespaces { OFMutableString *string; string = [self.stringClass stringWithString: whitespace[0]]; [string deleteTrailingWhitespaces]; OTAssertEqualObjects(string, @" \r \t\n\t \tasd"); string = [self.stringClass stringWithString: whitespace[1]]; [string deleteTrailingWhitespaces]; OTAssertEqualObjects(string, @""); } - (void)deleteEnclosingWhitespaces { OFMutableString *string; string = [self.stringClass stringWithString: whitespace[0]]; [string deleteEnclosingWhitespaces]; OTAssertEqualObjects(string, @"asd"); string = [self.stringClass stringWithString: whitespace[1]]; [string deleteEnclosingWhitespaces]; OTAssertEqualObjects(string, @""); } @end @implementation CustomMutableString - (instancetype)init { self = [super init]; @try { _string = [[OFMutableString alloc] init]; } @catch (id e) { [self release]; @throw e; } return self; } - (instancetype)initWithString: (OFString *)string { self = [super init]; @try { _string = [string mutableCopy]; } @catch (id e) { [self release]; @throw e; } return self; } - (instancetype)initWithCString: (const char *)cString encoding: (OFStringEncoding)encoding length: (size_t)length { self = [super init]; @try { _string = [[OFMutableString alloc] initWithCString: cString encoding: encoding length: length]; } @catch (id e) { [self release]; @throw e; } return self; } - (instancetype)initWithUTF16String: (const OFChar16 *)UTF16String length: (size_t)length byteOrder: (OFByteOrder)byteOrder { self = [super init]; @try { _string = [[OFMutableString alloc] initWithUTF16String: UTF16String length: length byteOrder: byteOrder]; } @catch (id e) { [self release]; @throw e; } return self; } - (instancetype)initWithUTF32String: (const OFChar32 *)UTF32String length: (size_t)length byteOrder: (OFByteOrder)byteOrder { self = [super init]; @try { _string = [[OFMutableString alloc] initWithUTF32String: UTF32String length: length byteOrder: byteOrder]; } @catch (id e) { [self release]; @throw e; } return self; } - (instancetype)initWithFormat: (OFConstantString *)format arguments: (va_list)arguments { self = [super init]; @try { _string = [[OFMutableString alloc] initWithFormat: format arguments: arguments]; } @catch (id e) { [self release]; @throw e; } return self; } - (void)dealloc { [_string release]; [super dealloc]; } - (OFUnichar)characterAtIndex: (size_t)idx { return [_string characterAtIndex: idx]; } - (size_t)length { return _string.length; } - (void)replaceCharactersInRange: (OFRange)range withString: (OFString *)string { [_string replaceCharactersInRange: range withString: string]; } @end