/*
* 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