Index: new_tests/Makefile ================================================================== --- new_tests/Makefile +++ new_tests/Makefile @@ -1,23 +1,27 @@ include ../extra.mk SUBDIRS = ${TESTPLUGIN} PROG_NOINST = tests${PROG_SUFFIX} -SRCS = OFCharacterSetTests.m \ - OFColorTests.m \ - OFDateTests.m \ - OFIRITests.m \ - OFInvocationTests.m \ - OFJSONTests.m \ - OFMatrix4x4Tests.m \ - OFMethodSignatureTests.m \ - OFNumberTests.m \ - OFPBKDF2Tests.m \ - OFPropertyListTests.m \ - OFScryptTests.m \ - ${USE_SRCS_PLUGINS} \ +SRCS = OFArrayTests.m \ + OFCharacterSetTests.m \ + OFColorTests.m \ + OFConcreteArrayTests.m \ + OFConcreteMutableArrayTests.m \ + OFDateTests.m \ + OFIRITests.m \ + OFInvocationTests.m \ + OFJSONTests.m \ + OFMatrix4x4Tests.m \ + OFMethodSignatureTests.m \ + OFMutableArrayTests.m \ + OFNumberTests.m \ + OFPBKDF2Tests.m \ + OFPropertyListTests.m \ + OFScryptTests.m \ + ${USE_SRCS_PLUGINS} \ ${USE_SRCS_SOCKETS} SRCS_PLUGINS = OFPluginTests.m SRCS_SOCKETS = OFSocketTests.m include ../buildsys.mk ADDED new_tests/OFArrayTests.h Index: new_tests/OFArrayTests.h ================================================================== --- new_tests/OFArrayTests.h +++ new_tests/OFArrayTests.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * 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. + */ + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFArrayTests: OTTestCase +{ + OFArray *_array; +} + +- (Class)arrayClass; +@end ADDED new_tests/OFArrayTests.m Index: new_tests/OFArrayTests.m ================================================================== --- new_tests/OFArrayTests.m +++ new_tests/OFArrayTests.m @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * 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" + +#import "OFArrayTests.h" + +@interface CustomArray: OFArray +{ + OFMutableArray *_array; +} +@end + +static OFString *const cArray[] = { + @"Foo", + @"Bar", + @"Baz" +}; + +@implementation OFArrayTests +- (Class)arrayClass +{ + return [CustomArray class]; +} + +- (void)setUp +{ + [super setUp]; + + _array = [[self.arrayClass alloc] + initWithObjects: cArray + count: sizeof(cArray) / sizeof(*cArray)]; +} + +- (void)dealloc +{ + [_array release]; + + [super dealloc]; +} + +- (void)testArray +{ + OFArray *array = [self.arrayClass array]; + + OTAssertNotNil(array); + OTAssertEqual(array.count, 0); +} + +- (void)testArrayWithObjects +{ + OFArray *array = [self.arrayClass arrayWithObjects: + @"Foo", @"Bar", @"Baz", nil]; + + OTAssertNotNil(array); + OTAssertEqual(array.count, 3); + OTAssertEqualObjects([array objectAtIndex: 0], @"Foo"); + OTAssertEqualObjects([array objectAtIndex: 1], @"Bar"); + OTAssertEqualObjects([array objectAtIndex: 2], @"Baz"); +} + +- (void)testArrayWithObjectsCount +{ + OFArray *array1 = [self.arrayClass arrayWithObjects: + @"Foo", @"Bar", @"Baz", nil]; + OFArray *array2 = [self.arrayClass arrayWithObjects: cArray count: 3]; + + OTAssertEqualObjects(array1, array2); +} + +- (void)testDescription +{ + OTAssertEqualObjects(_array.description, + @"(\n\tFoo,\n\tBar,\n\tBaz\n)"); +} + +- (void)testCount +{ + OTAssertEqual(_array.count, 3); +} + +- (void)testIsEqual +{ + OFArray *array = [self.arrayClass arrayWithObjects: cArray count: 3]; + + OTAssertEqualObjects(array, _array); + OTAssertNotEqual(array, _array); +} + +- (void)testObjectAtIndex +{ + OTAssertEqualObjects([_array objectAtIndex: 0], cArray[0]); + OTAssertEqualObjects([_array objectAtIndex: 1], cArray[1]); + OTAssertEqualObjects([_array objectAtIndex: 2], cArray[2]); +} + +- (void)testObjectAtIndexFailsWhenOutOfRange +{ + OTAssertThrowsSpecific([_array objectAtIndex: _array.count], + OFOutOfRangeException); +} + +- (void)testContainsObject +{ + OTAssertTrue([_array containsObject: cArray[1]]); + OTAssertFalse([_array containsObject: @"nonexistent"]); +} + +- (void)testContainsObjectIdenticalTo +{ + OTAssertTrue([_array containsObjectIdenticalTo: cArray[1]]); + OTAssertFalse([_array containsObjectIdenticalTo: + [OFString stringWithString: cArray[1]]]); +} + +- (void)testIndexOfObject +{ + OTAssertEqual([_array indexOfObject: cArray[1]], 1); + OTAssertEqual([_array indexOfObject: @"nonexistent"], OFNotFound); +} + +- (void)testIndexOfObjectIdenticalTo +{ + OTAssertEqual([_array indexOfObjectIdenticalTo: cArray[1]], 1); + OTAssertEqual([_array indexOfObjectIdenticalTo: + [OFString stringWithString: cArray[1]]], + OFNotFound); +} + +- (void)objectsInRange +{ + OTAssertEqualObjects([_array objectsInRange: OFMakeRange(1, 2)], + ([self.arrayClass arrayWithObjects: cArray[1], cArray[2], nil])); +} + +- (void)testEnumerator +{ + OFEnumerator *enumerator = [_array objectEnumerator]; + + OTAssertEqualObjects([enumerator nextObject], cArray[0]); + OTAssertEqualObjects([enumerator nextObject], cArray[1]); + OTAssertEqualObjects([enumerator nextObject], cArray[2]); + OTAssertNil([enumerator nextObject]); +} + +- (void)testFastEnumeration +{ + size_t i = 0; + + for (OFString *object in _array) { + OTAssert(i < 3); + OTAssertEqualObjects(object, cArray[i++]); + } +} + +- (void)testComponentsJoinedByString +{ + OFArray *array; + + array = [self.arrayClass arrayWithObjects: @"", @"a", @"b", @"c", nil]; + OTAssertEqualObjects([array componentsJoinedByString: @" "], + @" a b c"); + + array = [self.arrayClass arrayWithObject: @"foo"]; + OTAssertEqualObjects([array componentsJoinedByString: @" "], @"foo"); +} + +- (void)testComponentsJoinedByStringOptions +{ + OFArray *array; + + array = [self.arrayClass + arrayWithObjects: @"", @"foo", @"", @"", @"bar", @"", nil]; + OTAssertEqualObjects( + [array componentsJoinedByString: @" " + options: OFArraySkipEmptyComponents], + @"foo bar"); +} + +- (void)testSortedArray +{ + OFArray *array = [_array arrayByAddingObjectsFromArray: + [OFArray arrayWithObjects: @"0", @"z", nil]]; + + OTAssertEqualObjects([array sortedArray], + ([OFArray arrayWithObjects: @"0", @"Bar", @"Baz", @"Foo", @"z", + nil])); + + OTAssertEqualObjects( + [array sortedArrayUsingSelector: @selector(compare:) + options: OFArraySortDescending], + ([OFArray arrayWithObjects: @"z", @"Foo", @"Baz", @"Bar", @"0", + nil])); +} + +- (void)testReversedArray +{ + OTAssertEqualObjects(_array.reversedArray, + ([OFArray arrayWithObjects: cArray[2], cArray[1], cArray[0], nil])); +} + +#ifdef OF_HAVE_BLOCKS +- (void)testEnumerateObjectsUsingBlock +{ + __block size_t i = 0; + + [_array enumerateObjectsUsingBlock: + ^ (id object, size_t idx, bool *stop) { + OTAssertEqualObjects(object, [_array objectAtIndex: i++]); + }]; + + OTAssertEqual(i, _array.count); +} + +- (void)testMappedArrayUsingBlock +{ + OTAssertEqualObjects( + [_array mappedArrayUsingBlock: ^ id (id object, size_t idx) { + switch (idx) { + case 0: + return @"foobar"; + case 1: + return @"qux"; + } + + return @""; + }].description, + @"(\n\tfoobar,\n\tqux,\n\t\n)"); +} + +- (void)testFilteredArrayUsingBlock +{ + OTAssertEqualObjects( + [_array filteredArrayUsingBlock: ^ bool (id object, size_t idx) { + return [object isEqual: @"Foo"]; + }].description, + @"(\n\tFoo\n)"); + +} + +- (void)testFoldUsingBlock +{ + OTAssertEqualObjects( + [([self.arrayClass arrayWithObjects: [OFMutableString string], + @"foo", @"bar", @"baz", nil]) + foldUsingBlock: ^ id (id left, id right) { + [left appendString: right]; + return left; + }], + @"foobarbaz"); +} +#endif + +- (void)testValueForKey +{ + OTAssertEqualObjects( + [([self.arrayClass arrayWithObjects: @"foo", @"bar", @"quxqux", + nil]) valueForKey: @"length"], + ([self.arrayClass arrayWithObjects: [OFNumber numberWithInt: 3], + [OFNumber numberWithInt: 3], [OFNumber numberWithInt: 6], nil])); + + OTAssertEqualObjects( + [([self.arrayClass arrayWithObjects: @"1", @"2", nil]) + valueForKey: @"@count"], + [OFNumber numberWithInt: 2]); +} +@end + +@implementation CustomArray +- (instancetype)init +{ + self = [super init]; + + @try { + _array = [[OFMutableArray alloc] init]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)initWithObject: (id)object arguments: (va_list)arguments +{ + self = [super init]; + + @try { + _array = [[OFMutableArray alloc] initWithObject: object + arguments: arguments]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)initWithObjects: (id const *)objects count: (size_t)count +{ + self = [super init]; + + @try { + _array = [[OFMutableArray alloc] initWithObjects: objects + count: count]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_array release]; + + [super dealloc]; +} + +- (id)objectAtIndex: (size_t)idx +{ + return [_array objectAtIndex: idx]; +} + +- (size_t)count +{ + return [_array count]; +} +@end Index: new_tests/OFColorTests.m ================================================================== --- new_tests/OFColorTests.m +++ new_tests/OFColorTests.m @@ -25,10 +25,12 @@ @end @implementation OFColorTests - (void)setUp { + [super setUp]; + _color = [[OFColor alloc] initWithRed: 63.f / 255 green: 127.f / 255 blue: 1 alpha: 1]; } ADDED new_tests/OFConcreteArrayTests.m Index: new_tests/OFConcreteArrayTests.m ================================================================== --- new_tests/OFConcreteArrayTests.m +++ new_tests/OFConcreteArrayTests.m @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * 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" + +#import "OFArrayTests.h" + +#import "OFConcreteArray.h" + +@interface OFConcreteArrayTests: OFArrayTests +@end + +@implementation OFConcreteArrayTests +- (Class)arrayClass +{ + return [OFConcreteArray class]; +} +@end ADDED new_tests/OFConcreteMutableArrayTests.m Index: new_tests/OFConcreteMutableArrayTests.m ================================================================== --- new_tests/OFConcreteMutableArrayTests.m +++ new_tests/OFConcreteMutableArrayTests.m @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * 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" + +#import "OFMutableArrayTests.h" + +#import "OFConcreteMutableArray.h" + +@interface OFConcreteMutableArrayTests: OFMutableArrayTests +@end + +static OFString *const cArray[] = { + @"Foo", + @"Bar", + @"Baz" +}; + +@implementation OFConcreteMutableArrayTests +- (Class)arrayClass +{ + return [OFConcreteMutableArray class]; +} + +- (void)testDetectMutationDuringEnumeration +{ + OFEnumerator *enumerator = [_mutableArray objectEnumerator]; + OFString *object; + size_t i; + + i = 0; + while ((object = [enumerator nextObject]) != nil) { + OTAssertEqualObjects(object, cArray[i]); + + [_mutableArray replaceObjectAtIndex: i withObject: @""]; + i++; + } + OTAssertEqual(i, _mutableArray.count); + + [_mutableArray removeObjectAtIndex: 0]; + OTAssertThrowsSpecific([enumerator nextObject], + OFEnumerationMutationException); +} + +- (void)testDetectMutationDuringFastEnumeration +{ + bool detected = false; + size_t i; + + i = 0; + for (OFString *object in _mutableArray) { + OTAssertEqualObjects(object, cArray[i]); + + [_mutableArray replaceObjectAtIndex: i withObject: @""]; + i++; + } + OTAssertEqual(i, _mutableArray.count); + + @try { + for (OFString *object in _mutableArray) { + (void)object; + [_mutableArray removeObjectAtIndex: 0]; + } + } @catch (OFEnumerationMutationException *e) { + detected = true; + } + OTAssertTrue(detected); +} + +#ifdef OF_HAVE_BLOCKS +- (void)testDetectMutationDuringEnumerateObjectsUsingBlock +{ + __block size_t i; + + i = 0; + [_mutableArray enumerateObjectsUsingBlock: + ^ (id object, size_t idx, bool *stop) { + OTAssertEqualObjects(object, cArray[idx]); + + [_mutableArray replaceObjectAtIndex: idx withObject: @""]; + i++; + }]; + OTAssertEqual(i, _mutableArray.count); + + OTAssertThrowsSpecific( + [_mutableArray enumerateObjectsUsingBlock: + ^ (id object, size_t idx, bool *stop) { + [_mutableArray removeObjectAtIndex: 0]; + }], + OFEnumerationMutationException); +} +#endif +@end Index: new_tests/OFDateTests.m ================================================================== --- new_tests/OFDateTests.m +++ new_tests/OFDateTests.m @@ -29,10 +29,12 @@ @end @implementation OFDateTests - (void)setUp { + [super setUp]; + _date[0] = [[OFDate alloc] initWithTimeIntervalSince1970: 0]; _date[1] = [[OFDate alloc] initWithTimeIntervalSince1970: 3600 * 25 + 5.000002]; } Index: new_tests/OFIRITests.m ================================================================== --- new_tests/OFIRITests.m +++ new_tests/OFIRITests.m @@ -29,10 +29,12 @@ @"pa%3Fth?que%23ry=1&f%26oo=b%3dar#frag%23ment"; @implementation OFIRITests - (void)setUp { + [super setUp]; + _IRI[0] = [[OFIRI alloc] initWithString: IRI0String]; _IRI[1] = [[OFIRI alloc] initWithString: @"http://foo:80"]; _IRI[2] = [[OFIRI alloc] initWithString: @"http://bar/"]; _IRI[3] = [[OFIRI alloc] initWithString: @"file:///etc/passwd"]; _IRI[4] = [[OFIRI alloc] Index: new_tests/OFInvocationTests.m ================================================================== --- new_tests/OFInvocationTests.m +++ new_tests/OFInvocationTests.m @@ -44,10 +44,12 @@ return testStruct; } - (void)setUp { + [super setUp]; + SEL selector = @selector(invocationTestMethod1::::); OFMethodSignature *signature = [self methodSignatureForSelector: selector]; _invocation = [[OFInvocation alloc] initWithMethodSignature: signature]; Index: new_tests/OFJSONTests.m ================================================================== --- new_tests/OFJSONTests.m +++ new_tests/OFJSONTests.m @@ -31,10 +31,12 @@ @"null//bar\n,\"foo\",false]}"; @implementation OFJSONTests - (void)setUp { + [super setUp]; + _hashSeed = OFHashSeed; OFHashSeed = 0; _dictionary = [[OFDictionary alloc] initWithKeysAndObjects: @"foo", @"b\na\r", @@ -49,10 +51,12 @@ } - (void)tearDown { OFHashSeed = _hashSeed; + + [super tearDown]; } - (void)dealloc { [_dictionary release]; Index: new_tests/OFMatrix4x4Tests.m ================================================================== --- new_tests/OFMatrix4x4Tests.m +++ new_tests/OFMatrix4x4Tests.m @@ -25,10 +25,12 @@ @end @implementation OFMatrix4x4Tests - (void)setUp { + [super setUp]; + _matrix = [[OFMatrix4x4 alloc] initWithValues: (const float [4][4]){ { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }, { 13, 14, 15, 16 } ADDED new_tests/OFMutableArrayTests.h Index: new_tests/OFMutableArrayTests.h ================================================================== --- new_tests/OFMutableArrayTests.h +++ new_tests/OFMutableArrayTests.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * 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. + */ + +#import "OFArrayTests.h" + +@interface OFMutableArrayTests: OFArrayTests +{ + OFMutableArray *_mutableArray; +} +@end ADDED new_tests/OFMutableArrayTests.m Index: new_tests/OFMutableArrayTests.m ================================================================== --- new_tests/OFMutableArrayTests.m +++ new_tests/OFMutableArrayTests.m @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * 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" + +#import "OFMutableArrayTests.h" + +#import "OFArray+Private.h" + +@interface CustomMutableArray: OFMutableArray +{ + OFMutableArray *_array; +} +@end + +static OFString *const cArray[] = { + @"Foo", + @"Bar", + @"Baz" +}; + +@implementation OFMutableArrayTests +- (Class)arrayClass +{ + return [CustomMutableArray class]; +} + +- (void)setUp +{ + [super setUp]; + + _mutableArray = [[self.arrayClass alloc] + initWithObjects: cArray + count: sizeof(cArray) / sizeof(*cArray)]; +} + +- (void)dealloc +{ + [_mutableArray release]; + + [super dealloc]; +} + +- (void)testAddObject +{ + [_mutableArray addObject: cArray[0]]; + [_mutableArray addObject: cArray[2]]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Bar", @"Baz", @"Foo", @"Baz", + nil])); +} + +- (void)testInsertObjectAtIndex +{ + [_mutableArray insertObject: cArray[1] atIndex: 1]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Bar", @"Bar", @"Baz", nil])); +} + +- (void)testReplaceObjectWithObject +{ + [_mutableArray insertObject: cArray[1] atIndex: 1]; + [_mutableArray replaceObject: cArray[1] withObject: cArray[0]]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Foo", @"Foo", @"Baz", nil])); +} + +- (void)testReplaceObjectIdenticalToWithObject +{ + [_mutableArray insertObject: [[cArray[1] mutableCopy] autorelease] + atIndex: 1]; + [_mutableArray replaceObjectIdenticalTo: cArray[1] + withObject: cArray[0]]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Bar", @"Foo", @"Baz", nil])); +} + +- (void)testReplaceObjectAtIndexWithObject +{ + [_mutableArray replaceObjectAtIndex: 1 + withObject: cArray[0]]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Foo", @"Baz", nil])); +} + +- (void)testRemoveObject +{ + [_mutableArray removeObject: cArray[1]]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Baz", nil])); +} + +- (void)testRemoveObjectIdenticalTo +{ + [_mutableArray removeObjectIdenticalTo: cArray[1]]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Baz", nil])); +} + +- (void)testRemoveObjectAtIndex +{ + [_mutableArray removeObjectAtIndex: 1]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Baz", nil])); +} + +- (void)testRemoveObjectsInRange +{ + [_mutableArray removeObjectsInRange: OFMakeRange(1, 2)]; + + OTAssertEqualObjects(_mutableArray, [OFArray arrayWithObject: @"Foo"]); +} + +- (void)testRemoveObjectsInRangeFailsWhenOutOfRange +{ + OTAssertThrowsSpecific([_mutableArray removeObjectsInRange: + OFMakeRange(0, _mutableArray.count + 1)], OFOutOfRangeException); +} + +- (void)testReverse +{ + [_mutableArray reverse]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Baz", @"Bar", @"Foo", nil])); +} + +#ifdef OF_HAVE_BLOCKS +- (void)testReplaceObjectsUsingBlock +{ + [_mutableArray replaceObjectsUsingBlock: ^ id (id object, size_t idx) { + return [object lowercaseString]; + }]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil])); +} +#endif + +- (void)testSetValueForKey +{ + OFMutableArray *array = [self.arrayClass arrayWithObjects: + [OFMutableIRI IRIWithString: @"http://foo.bar/"], + [OFMutableIRI IRIWithString: @"http://bar.qux/"], + [OFMutableIRI IRIWithString: @"http://qux.quxqux/"], nil]; + + [array setValue: [OFNumber numberWithShort: 1234] + forKey: @"port"]; + OTAssertEqualObjects(array, ([OFArray arrayWithObjects: + [OFIRI IRIWithString: @"http://foo.bar:1234/"], + [OFIRI IRIWithString: @"http://bar.qux:1234/"], + [OFIRI IRIWithString: @"http://qux.quxqux:1234/"], nil])); +} +@end + +@implementation CustomMutableArray +- (instancetype)init +{ + self = [super init]; + + @try { + _array = [[OFMutableArray alloc] init]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)initWithObject: (id)object arguments: (va_list)arguments +{ + self = [super init]; + + @try { + _array = [[OFMutableArray alloc] initWithObject: object + arguments: arguments]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)initWithObjects: (id const *)objects count: (size_t)count +{ + self = [super init]; + + @try { + _array = [[OFMutableArray alloc] initWithObjects: objects + count: count]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_array release]; + + [super dealloc]; +} + +- (id)objectAtIndex: (size_t)idx +{ + return [_array objectAtIndex: idx]; +} + +- (size_t)count +{ + return [_array count]; +} + +- (void)insertObject: (id)object atIndex: (size_t)idx +{ + [_array insertObject: object atIndex: idx]; +} + +- (void)replaceObjectAtIndex: (size_t)idx withObject: (id)object +{ + [_array replaceObjectAtIndex: idx withObject: object]; +} + +- (void)removeObjectAtIndex: (size_t)idx +{ + [_array removeObjectAtIndex: idx]; +} +@end Index: new_tests/OFPBKDF2Tests.m ================================================================== --- new_tests/OFPBKDF2Tests.m +++ new_tests/OFPBKDF2Tests.m @@ -27,10 +27,12 @@ @end @implementation OFPBKDF2Tests - (void)setUp { + [super setUp]; + _HMAC = [[OFHMAC alloc] initWithHashClass: [OFSHA1Hash class] allowsSwappableMemory: true]; } - (void)dealloc Index: src/test/OTAppDelegate.m ================================================================== --- src/test/OTAppDelegate.m +++ src/test/OTAppDelegate.m @@ -99,10 +99,14 @@ } } @finally { OFFreeMemory(methods); } + if (class_getSuperclass(class) != Nil) + [tests unionSet: + [self testsInClass: class_getSuperclass(class)]]; + [tests makeImmutable]; return tests; } - (void)printStatusForTest: (SEL)test Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -15,11 +15,10 @@ DISTCLEAN = Info.plist PROG_NOINST = tests${PROG_SUFFIX} STATIC_LIB_NOINST = ${TESTS_STATIC_LIB} SRCS = ForwardingTests.m \ - OFArrayTests.m \ ${OF_BLOCK_TESTS_M} \ OFDataTests.m \ OFDictionaryTests.m \ OFHMACTests.m \ OFINIFileTests.m \ DELETED tests/OFArrayTests.m Index: tests/OFArrayTests.m ================================================================== --- tests/OFArrayTests.m +++ tests/OFArrayTests.m @@ -1,458 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * 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" - -#import "TestsAppDelegate.h" - -static OFString *module; -static OFString *const cArray[] = { - @"Foo", - @"Bar", - @"Baz" -}; - -@interface SimpleArray: OFArray -{ - OFMutableArray *_array; -} -@end - -@interface SimpleMutableArray: OFMutableArray -{ - OFMutableArray *_array; -} -@end - -@implementation SimpleArray -- (instancetype)init -{ - self = [super init]; - - @try { - _array = [[OFMutableArray alloc] init]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithObject: (id)object arguments: (va_list)arguments -{ - self = [super init]; - - @try { - _array = [[OFMutableArray alloc] initWithObject: object - arguments: arguments]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithObjects: (id const *)objects count: (size_t)count -{ - self = [super init]; - - @try { - _array = [[OFMutableArray alloc] initWithObjects: objects - count: count]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_array release]; - - [super dealloc]; -} - -- (id)objectAtIndex: (size_t)idx -{ - return [_array objectAtIndex: idx]; -} - -- (size_t)count -{ - return [_array count]; -} -@end - -@implementation SimpleMutableArray -+ (void)initialize -{ - if (self == [SimpleMutableArray class]) - [self inheritMethodsFromClass: [SimpleArray class]]; -} - -- (void)insertObject: (id)object atIndex: (size_t)idx -{ - [_array insertObject: object atIndex: idx]; -} - -- (void)replaceObjectAtIndex: (size_t)idx withObject: (id)object -{ - [_array replaceObjectAtIndex: idx withObject: object]; -} - -- (void)removeObjectAtIndex: (size_t)idx -{ - [_array removeObjectAtIndex: idx]; -} -@end - -@implementation TestsAppDelegate (OFArrayTests) -- (void)arrayTestsWithClass: (Class)arrayClass - mutableClass: (Class)mutableArrayClass -{ - void *pool = objc_autoreleasePoolPush(); - OFArray *array1, *array2; - OFMutableArray *mutableArray1, *mutableArray2; - OFEnumerator *enumerator; - id object; - bool ok; - size_t i; - - TEST(@"+[array]", (mutableArray1 = [mutableArrayClass array])) - - TEST(@"+[arrayWithObjects:]", - (array1 = - [arrayClass arrayWithObjects: @"Foo", @"Bar", @"Baz", nil])) - - TEST(@"+[arrayWithObjects:count:]", - (array2 = [arrayClass arrayWithObjects: cArray count: 3]) && - [array2 isEqual: array1]) - - TEST(@"-[description]", - [array1.description isEqual: @"(\n\tFoo,\n\tBar,\n\tBaz\n)"]) - - TEST(@"-[addObject:]", - R([mutableArray1 addObject: cArray[0]]) && - R([mutableArray1 addObject: cArray[2]])) - - TEST(@"-[insertObject:atIndex:]", - R([mutableArray1 insertObject: cArray[1] atIndex: 1])) - - TEST(@"-[count]", - mutableArray1.count == 3 && array1.count == 3 && array2.count == 3) - - TEST(@"-[isEqual:]", - [mutableArray1 isEqual: array1] && [array1 isEqual: array2]) - - TEST(@"-[objectAtIndex:]", - [[mutableArray1 objectAtIndex: 0] isEqual: cArray[0]] && - [[mutableArray1 objectAtIndex: 1] isEqual: cArray[1]] && - [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]] && - [[array1 objectAtIndex: 0] isEqual: cArray[0]] && - [[array1 objectAtIndex: 1] isEqual: cArray[1]] && - [[array1 objectAtIndex: 2] isEqual: cArray[2]] && - [[array2 objectAtIndex: 0] isEqual: cArray[0]] && - [[array2 objectAtIndex: 1] isEqual: cArray[1]] && - [[array2 objectAtIndex: 2] isEqual: cArray[2]]) - - TEST(@"-[containsObject:]", - [array1 containsObject: cArray[1]] && - ![array1 containsObject: @"nonexistent"]) - - TEST(@"-[containsObjectIdenticalTo:]", - [array1 containsObjectIdenticalTo: cArray[1]] && - ![array1 containsObjectIdenticalTo: - [OFString stringWithString: cArray[1]]]) - - TEST(@"-[indexOfObject:]", [array1 indexOfObject: cArray[1]] == 1) - - TEST(@"-[indexOfObjectIdenticalTo:]", - [array2 indexOfObjectIdenticalTo: cArray[1]] == 1) - - TEST(@"-[objectsInRange:]", - [[array1 objectsInRange: OFMakeRange(1, 2)] isEqual: - [arrayClass arrayWithObjects: cArray[1], cArray[2], nil]]) - - TEST(@"-[replaceObject:withObject:]", - R([mutableArray1 replaceObject: cArray[1] withObject: cArray[0]]) && - [[mutableArray1 objectAtIndex: 0] isEqual: cArray[0]] && - [[mutableArray1 objectAtIndex: 1] isEqual: cArray[0]] && - [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]]) - - TEST(@"-[replaceObject:identicalTo:]", - R([mutableArray1 replaceObjectIdenticalTo: cArray[0] - withObject: cArray[1]]) && - [[mutableArray1 objectAtIndex: 0] isEqual: cArray[1]] && - [[mutableArray1 objectAtIndex: 1] isEqual: cArray[0]] && - [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]]) - - TEST(@"-[replaceObjectAtIndex:withObject:]", - R([mutableArray1 replaceObjectAtIndex: 0 withObject: cArray[0]]) && - [[mutableArray1 objectAtIndex: 0] isEqual: cArray[0]] && - [[mutableArray1 objectAtIndex: 1] isEqual: cArray[0]] && - [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]]) - - TEST(@"-[removeObject:]", - R([mutableArray1 removeObject: cArray[0]]) && - mutableArray1.count == 1) - - [mutableArray1 addObject: cArray[0]]; - - TEST(@"-[removeObjectIdenticalTo:]", - R([mutableArray1 removeObjectIdenticalTo: cArray[2]]) && - mutableArray1.count == 1) - - mutableArray2 = [[array1 mutableCopy] autorelease]; - TEST(@"-[removeObjectAtIndex:]", - R([mutableArray2 removeObjectAtIndex: 1]) && - mutableArray2.count == 2 && - [[mutableArray2 objectAtIndex: 1] isEqual: cArray[2]]) - - mutableArray2 = [[array1 mutableCopy] autorelease]; - TEST(@"-[removeObjectsInRange:]", - R([mutableArray2 removeObjectsInRange: OFMakeRange(0, 2)]) && - mutableArray2.count == 1 && - [[mutableArray2 objectAtIndex: 0] isEqual: cArray[2]]) - - mutableArray2 = [[array1 mutableCopy] autorelease]; - [mutableArray2 addObject: @"qux"]; - [mutableArray2 addObject: @"last"]; - TEST(@"-[reverse]", - R([mutableArray2 reverse]) && - [mutableArray2 isEqual: [arrayClass arrayWithObjects: - @"last", @"qux", @"Baz", @"Bar", @"Foo", nil]]) - - mutableArray2 = [[array1 mutableCopy] autorelease]; - [mutableArray2 addObject: @"qux"]; - [mutableArray2 addObject: @"last"]; - TEST(@"-[reversedArray]", - [[mutableArray2 reversedArray] isEqual: - [arrayClass arrayWithObjects: - @"last", @"qux", @"Baz", @"Bar", @"Foo", nil]]) - - mutableArray2 = [[array1 mutableCopy] autorelease]; - [mutableArray2 addObject: @"0"]; - [mutableArray2 addObject: @"z"]; - TEST(@"-[sortedArray]", - [[mutableArray2 sortedArray] isEqual: [arrayClass arrayWithObjects: - @"0", @"Bar", @"Baz", @"Foo", @"z", nil]] && - [[mutableArray2 sortedArrayUsingSelector: @selector(compare:) - options: OFArraySortDescending] - isEqual: [arrayClass arrayWithObjects: - @"z", @"Foo", @"Baz", @"Bar", @"0", nil]]) - - EXPECT_EXCEPTION(@"Detect out of range in -[objectAtIndex:]", - OFOutOfRangeException, [array1 objectAtIndex: array1.count]) - - EXPECT_EXCEPTION(@"Detect out of range in -[removeObjectsInRange:]", - OFOutOfRangeException, [mutableArray1 removeObjectsInRange: - OFMakeRange(0, mutableArray1.count + 1)]) - - TEST(@"-[componentsJoinedByString:]", - (array2 = [arrayClass arrayWithObjects: @"", @"a", @"b", @"c", - nil]) && - [[array2 componentsJoinedByString: @" "] isEqual: @" a b c"] && - (array2 = [arrayClass arrayWithObject: @"foo"]) && - [[array2 componentsJoinedByString: @" "] isEqual: @"foo"]) - - TEST(@"-[componentsJoinedByString:options]", - (array2 = [arrayClass arrayWithObjects: @"", @"foo", @"", @"", - @"bar", @"", nil]) && - [[array2 componentsJoinedByString: @" " - options: OFArraySkipEmptyComponents] - isEqual: @"foo bar"]) - - mutableArray1 = [[array1 mutableCopy] autorelease]; - ok = true; - i = 0; - - TEST(@"-[objectEnumerator]", - (enumerator = [mutableArray1 objectEnumerator])) - - while ((object = [enumerator nextObject]) != nil) { - if (![object isEqual: cArray[i]]) - ok = false; - [mutableArray1 replaceObjectAtIndex: i withObject: @""]; - i++; - } - - if (mutableArray1.count != i) - ok = false; - - TEST(@"OFEnumerator's -[nextObject]", ok) - - [mutableArray1 removeObjectAtIndex: 0]; - - EXPECT_EXCEPTION(@"Detection of mutation during enumeration", - OFEnumerationMutationException, [enumerator nextObject]) - - mutableArray1 = [[array1 mutableCopy] autorelease]; - ok = true; - i = 0; - - for (OFString *string in mutableArray1) { - if (![string isEqual: cArray[i]]) - ok = false; - [mutableArray1 replaceObjectAtIndex: i withObject: @""]; - i++; - } - - if (mutableArray1.count != i) - ok = false; - - TEST(@"Fast Enumeration", ok) - - [mutableArray1 replaceObjectAtIndex: 0 withObject: cArray[0]]; - [mutableArray1 replaceObjectAtIndex: 1 withObject: cArray[1]]; - [mutableArray1 replaceObjectAtIndex: 2 withObject: cArray[2]]; - - ok = false; - i = 0; - @try { - for (OFString *string in mutableArray1) { - (void)string; - - if (i == 0) - [mutableArray1 addObject: @""]; - - i++; - } - } @catch (OFEnumerationMutationException *e) { - ok = true; - } - - TEST(@"Detection of mutation during Fast Enumeration", ok) - - [mutableArray1 removeLastObject]; - -#ifdef OF_HAVE_BLOCKS - { - __block bool blockOK = true; - __block size_t count = 0; - OFArray *compareArray = array1; - OFMutableArray *mutableArray3; - - mutableArray1 = [[array1 mutableCopy] autorelease]; - [mutableArray1 enumerateObjectsUsingBlock: - ^ (id object_, size_t idx, bool *stop) { - count++; - if (![object_ isEqual: - [compareArray objectAtIndex: idx]]) - blockOK = false; - }]; - - if (count != compareArray.count) - blockOK = false; - - TEST(@"Enumeration using blocks", blockOK) - - blockOK = false; - mutableArray3 = mutableArray1; - @try { - [mutableArray3 enumerateObjectsUsingBlock: - ^ (id object_, size_t idx, bool *stop) { - [mutableArray3 removeObjectAtIndex: idx]; - }]; - } @catch (OFEnumerationMutationException *e) { - blockOK = true; - } @catch (OFOutOfRangeException *e) { - /* - * Out of bounds access due to enumeration not being - * detected. - */ - } - - TEST(@"Detection of mutation during enumeration using blocks", - blockOK) - } - - TEST(@"-[replaceObjectsUsingBlock:]", - R([mutableArray1 replaceObjectsUsingBlock: - ^ id (id object_, size_t idx) { - switch (idx) { - case 0: - return @"foo"; - case 1: - return @"bar"; - } - - return nil; - }]) && [mutableArray1.description isEqual: @"(\n\tfoo,\n\tbar\n)"]) - - TEST(@"-[mappedArrayUsingBlock:]", - [[mutableArray1 mappedArrayUsingBlock: - ^ id (id object_, size_t idx) { - switch (idx) { - case 0: - return @"foobar"; - case 1: - return @"qux"; - } - - return nil; - }].description isEqual: @"(\n\tfoobar,\n\tqux\n)"]) - - TEST(@"-[filteredArrayUsingBlock:]", - [[mutableArray1 filteredArrayUsingBlock: - ^ bool (id object_, size_t idx) { - return [object_ isEqual: @"foo"]; - }].description isEqual: @"(\n\tfoo\n)"]) - - TEST(@"-[foldUsingBlock:]", - [[arrayClass arrayWithObjects: [OFMutableString string], @"foo", - @"bar", @"baz", nil] foldUsingBlock: ^ id (id left, id right) { - [left appendString: right]; - return left; - }]) -#endif - - TEST(@"-[valueForKey:]", - [[[arrayClass arrayWithObjects: @"foo", @"bar", @"quxqux", nil] - valueForKey: @"length"] isEqual: - [arrayClass arrayWithObjects: [OFNumber numberWithInt: 3], - [OFNumber numberWithInt: 3], [OFNumber numberWithInt: 6], nil]] && - [[[arrayClass arrayWithObjects: @"1", @"2", nil] - valueForKey: @"@count"] isEqual: [OFNumber numberWithInt: 2]]) - - mutableArray1 = [mutableArrayClass arrayWithObjects: - [OFMutableIRI IRIWithString: @"http://foo.bar/"], - [OFMutableIRI IRIWithString: @"http://bar.qux/"], - [OFMutableIRI IRIWithString: @"http://qux.quxqux/"], nil]; - TEST(@"-[setValue:forKey:]", - R([mutableArray1 setValue: [OFNumber numberWithShort: 1234] - forKey: @"port"]) && - [mutableArray1 isEqual: [arrayClass arrayWithObjects: - [OFIRI IRIWithString: @"http://foo.bar:1234/"], - [OFIRI IRIWithString: @"http://bar.qux:1234/"], - [OFIRI IRIWithString: @"http://qux.quxqux:1234/"], nil]]) - - objc_autoreleasePoolPop(pool); -} - -- (void)arrayTests -{ - module = @"OFArray"; - [self arrayTestsWithClass: [SimpleArray class] - mutableClass: [SimpleMutableArray class]]; - - module = @"OFArray_adjacent"; - [self arrayTestsWithClass: [OFArray class] - mutableClass: [OFMutableArray class]]; -} -@end Index: tests/TestsAppDelegate.h ================================================================== --- tests/TestsAppDelegate.h +++ tests/TestsAppDelegate.h @@ -57,14 +57,10 @@ - (void)outputTesting: (OFString *)test inModule: (OFString *)module; - (void)outputSuccess: (OFString *)test inModule: (OFString *)module; - (void)outputFailure: (OFString *)test inModule: (OFString *)module; @end -@interface TestsAppDelegate (OFArrayTests) -- (void)arrayTests; -@end - @interface TestsAppDelegate (OFBlockTests) - (void)blockTests; @end @interface TestsAppDelegate (OFDDPSocketTests) Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -379,11 +379,10 @@ #ifdef OF_HAVE_BLOCKS [self blockTests]; #endif [self stringTests]; [self dataTests]; - [self arrayTests]; [self dictionaryTests]; [self listTests]; [self setTests]; [self valueTests]; [self streamTests];