Index: new_tests/Makefile ================================================================== --- new_tests/Makefile +++ new_tests/Makefile @@ -10,53 +10,57 @@ ${PROG_NOINST}.rpx \ testfile_bin.m \ testfile_ini.m PROG_NOINST = tests${PROG_SUFFIX} -SRCS = ${OF_BLOCK_TESTS_M} \ - ForwardingTests.m \ - OFArrayTests.m \ - OFCharacterSetTests.m \ - OFColorTests.m \ - OFConcreteArrayTests.m \ - OFConcreteMutableArrayTests.m \ - OFConcreteMutableSetTests.m \ - OFConcreteSetTests.m \ - OFCryptographicHashTests.m \ - OFDateTests.m \ - OFHMACTests.m \ - OFINIFileTests.m \ - OFIRITests.m \ - OFInvocationTests.m \ - OFJSONTests.m \ - OFListTests.m \ - OFLocaleTests.m \ - OFMatrix4x4Tests.m \ - OFMethodSignatureTests.m \ - OFMutableArrayTests.m \ - OFMutableSetTests.m \ - OFMutableStringTests.m \ - OFMutableUTF8StringTests.m \ - OFNotificationCenterTests.m \ - OFNumberTests.m \ - OFObjectTests.m \ - OFPBKDF2Tests.m \ - OFPropertyListTests.m \ - OFScryptTests.m \ - OFSetTests.m \ - OFStringTests.m \ - OFSystemInfoTests.m \ - OFUTF8StringTests.m \ - OFXMLElementBuilderTests.m \ - ${RUNTIME_ARC_TESTS_M} \ - RuntimeTests.m \ - ${USE_SRCS_PLUGINS} \ - ${USE_SRCS_SOCKETS} \ - ${USE_SRCS_SUBPROCESSES} \ - ${USE_SRCS_THREADS} \ - ${USE_SRCS_WINDOWS} \ - testfile_bin.m \ +SRCS = ${OF_BLOCK_TESTS_M} \ + ForwardingTests.m \ + OFArrayTests.m \ + OFCharacterSetTests.m \ + OFColorTests.m \ + OFConcreteArrayTests.m \ + OFConcreteDictionaryTests.m \ + OFConcreteMutableArrayTests.m \ + OFConcreteMutableDictionaryTests.m \ + OFConcreteMutableSetTests.m \ + OFConcreteSetTests.m \ + OFCryptographicHashTests.m \ + OFDateTests.m \ + OFDictionaryTests.m \ + OFHMACTests.m \ + OFINIFileTests.m \ + OFIRITests.m \ + OFInvocationTests.m \ + OFJSONTests.m \ + OFListTests.m \ + OFLocaleTests.m \ + OFMatrix4x4Tests.m \ + OFMethodSignatureTests.m \ + OFMutableArrayTests.m \ + OFMutableDictionaryTests.m \ + OFMutableSetTests.m \ + OFMutableStringTests.m \ + OFMutableUTF8StringTests.m \ + OFNotificationCenterTests.m \ + OFNumberTests.m \ + OFObjectTests.m \ + OFPBKDF2Tests.m \ + OFPropertyListTests.m \ + OFScryptTests.m \ + OFSetTests.m \ + OFStringTests.m \ + OFSystemInfoTests.m \ + OFUTF8StringTests.m \ + OFXMLElementBuilderTests.m \ + ${RUNTIME_ARC_TESTS_M} \ + RuntimeTests.m \ + ${USE_SRCS_PLUGINS} \ + ${USE_SRCS_SOCKETS} \ + ${USE_SRCS_SUBPROCESSES} \ + ${USE_SRCS_THREADS} \ + ${USE_SRCS_WINDOWS} \ + testfile_bin.m \ testfile_ini.m SRCS_PLUGINS = OFPluginTests.m SRCS_SOCKETS = OFDNSResolverTests.m \ ${OF_HTTP_CLIENT_TESTS_M} \ OFHTTPCookieManagerTests.m \ ADDED new_tests/OFConcreteDictionaryTests.m Index: new_tests/OFConcreteDictionaryTests.m ================================================================== --- new_tests/OFConcreteDictionaryTests.m +++ new_tests/OFConcreteDictionaryTests.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 "OFDictionaryTests.h" + +#import "OFConcreteDictionary.h" + +@interface OFConcreteDictionaryTests: OFDictionaryTests +@end + +@implementation OFConcreteDictionaryTests +- (Class)dictionaryClass +{ + return [OFConcreteDictionary class]; +} +@end ADDED new_tests/OFConcreteMutableDictionaryTests.m Index: new_tests/OFConcreteMutableDictionaryTests.m ================================================================== --- new_tests/OFConcreteMutableDictionaryTests.m +++ new_tests/OFConcreteMutableDictionaryTests.m @@ -0,0 +1,100 @@ +/* + * 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 "OFMutableDictionaryTests.h" + +#import "OFConcreteMutableDictionary.h" + +@interface OFConcreteMutableDictionaryTests: OFMutableDictionaryTests +@end + +@implementation OFConcreteMutableDictionaryTests +- (Class)dictionaryClass +{ + return [OFConcreteMutableDictionary class]; +} + +- (void)testDetectMutationDuringEnumeration +{ + OFMutableDictionary *mutableDictionary = + [[_dictionary mutableCopy] autorelease]; + OFEnumerator *keyEnumerator = [mutableDictionary keyEnumerator]; + OFEnumerator *objectEnumerator = [mutableDictionary objectEnumerator]; + OFString *key; + size_t i; + + i = 0; + while ((key = [keyEnumerator nextObject]) != nil) { + [mutableDictionary setObject: @"test" forKey: key]; + i++; + } + OTAssertEqual(i, mutableDictionary.count); + + [mutableDictionary removeObjectForKey: @"key2"]; + OTAssertThrowsSpecific([keyEnumerator nextObject], + OFEnumerationMutationException); + OTAssertThrowsSpecific([objectEnumerator nextObject], + OFEnumerationMutationException); +} + +- (void)testDetectMutationDuringFastEnumeration +{ + OFMutableDictionary *mutableDictionary = + [[_dictionary mutableCopy] autorelease]; + bool detected = false; + size_t i; + + i = 0; + for (OFString *key in mutableDictionary) { + [mutableDictionary setObject: @"test" forKey: key]; + i++; + } + OTAssertEqual(i, mutableDictionary.count); + + @try { + for (OFString *key in mutableDictionary) + [mutableDictionary removeObjectForKey: key]; + } @catch (OFEnumerationMutationException *e) { + detected = true; + } + OTAssertTrue(detected); +} + +#ifdef OF_HAVE_BLOCKS +- (void)testDetectMutationDuringEnumerateObjectsUsingBlock +{ + OFMutableDictionary *mutableDictionary = + [[_dictionary mutableCopy] autorelease]; + __block size_t i; + + i = 0; + [mutableDictionary enumerateKeysAndObjectsUsingBlock: + ^ (id key, id object, bool *stop) { + [mutableDictionary setObject: @"test" forKey: key]; + i++; + }]; + OTAssertEqual(i, mutableDictionary.count); + + OTAssertThrowsSpecific( + [mutableDictionary enumerateKeysAndObjectsUsingBlock: + ^ (id key, id object, bool *stop) { + [mutableDictionary removeObjectForKey: key]; + }], + OFEnumerationMutationException); +} +#endif +@end ADDED new_tests/OFDictionaryTests.h Index: new_tests/OFDictionaryTests.h ================================================================== --- new_tests/OFDictionaryTests.h +++ new_tests/OFDictionaryTests.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 OFDictionaryTests: OTTestCase +{ + OFDictionary *_dictionary; +} + +@property (readonly, nonatomic) Class dictionaryClass; +@end ADDED new_tests/OFDictionaryTests.m Index: new_tests/OFDictionaryTests.m ================================================================== --- new_tests/OFDictionaryTests.m +++ new_tests/OFDictionaryTests.m @@ -0,0 +1,299 @@ +/* + * 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 "OFDictionaryTests.h" + +static OFString *keys[] = { + @"key1", + @"key2" +}; +static OFString *objects[] = { + @"value1", + @"value2" +}; + +@interface CustomDictionary: OFDictionary +{ + OFDictionary *_dictionary; +} +@end + +@implementation OFDictionaryTests +- (Class)dictionaryClass +{ + return [CustomDictionary class]; +} + +- (void)setUp +{ + [super setUp]; + + _dictionary = [[self.dictionaryClass alloc] initWithObjects: objects + forKeys: keys + count: 2]; +} + +- (void)dealloc +{ + [_dictionary release]; + + [super dealloc]; +} + +- (void)testObjectForKey +{ + OTAssertEqualObjects([_dictionary objectForKey: keys[0]], objects[0]); + OTAssertEqualObjects([_dictionary objectForKey: keys[1]], objects[1]); +} + +- (void)testCount +{ + OTAssertEqual(_dictionary.count, 2); +} + +- (void)testIsEqual +{ + OTAssertEqualObjects(_dictionary, + [OFDictionary dictionaryWithObjects: objects + forKeys: keys + count: 2]); + OTAssertNotEqualObjects(_dictionary, + [OFDictionary dictionaryWithObjects: keys + forKeys: objects + count: 2]); +} + +/* FIXME: Hash is currently not stable. Enable test as soon as this is fixed. */ +#if 0 +- (void)testHash +{ + OTAssertEqual(_dictionary.hash, + [[OFDictionary dictionaryWithObjects: objects + forKeys: keys + count: 2] hash]); + OTAssertNotEqual(_dictionary.hash, + [[OFDictionary dictionaryWithObjects: keys + forKeys: objects + count: 2] hash]); +} +#endif + +- (void)testCopy +{ + OTAssertEqualObjects([[_dictionary copy] autorelease], _dictionary); +} + +- (void)testValueForKey +{ + OTAssertEqualObjects([_dictionary valueForKey: keys[0]], objects[0]); + OTAssertEqualObjects([_dictionary valueForKey: keys[1]], objects[1]); + OTAssertEqualObjects( + [_dictionary valueForKey: @"@count"], [OFNumber numberWithInt: 2]); +} + +- (void)testSetValueForKey +{ + OTAssertThrowsSpecific([_dictionary setValue: @"x" forKey: @"x"], + OFUndefinedKeyException); +} + +- (void)testContainsObject +{ + OTAssertTrue([_dictionary containsObject: objects[0]]); + OTAssertFalse([_dictionary containsObject: @"nonexistent"]); +} + +- (void)testContainsObjectIdenticalTo +{ + OTAssertTrue([_dictionary containsObjectIdenticalTo: objects[0]]); + OTAssertFalse([_dictionary containsObjectIdenticalTo: + [[objects[0] mutableCopy] autorelease]]); +} + +- (void)testDescription +{ + OTAssert( + [_dictionary.description isEqual: + @"{\n\tkey1 = value1;\n\tkey2 = value2;\n}"] || + [_dictionary.description isEqual: + @"{\n\tkey2 = value2;\n\tkey1 = value1;\n}"]); +} + +- (void)testAllKeys +{ + OTAssert( + [_dictionary.allKeys isEqual: + ([OFArray arrayWithObjects: keys[0], keys[1], nil])] || + [_dictionary.allKeys isEqual: + ([OFArray arrayWithObjects: keys[1], keys[0], nil])]); +} + +- (void)testAllObjects +{ + OTAssert( + [_dictionary.allObjects isEqual: + ([OFArray arrayWithObjects: objects[0], objects[1], nil])] || + [_dictionary.allObjects isEqual: + ([OFArray arrayWithObjects: objects[1], objects[0], nil])]); +} + +- (void)testKeyEnumerator +{ + OFEnumerator *enumerator = [_dictionary keyEnumerator]; + OFString *first, *second; + + first = [enumerator nextObject]; + second = [enumerator nextObject]; + OTAssertNil([enumerator nextObject]); + + OTAssert( + ([first isEqual: keys[0]] && [second isEqual: keys[1]]) || + ([first isEqual: keys[1]] && [second isEqual: keys[0]])); +} + +- (void)testObjectEnumerator +{ + OFEnumerator *enumerator = [_dictionary objectEnumerator]; + OFString *first, *second; + + first = [enumerator nextObject]; + second = [enumerator nextObject]; + OTAssertNil([enumerator nextObject]); + + OTAssert( + ([first isEqual: objects[0]] && [second isEqual: objects[1]]) || + ([first isEqual: objects[1]] && [second isEqual: objects[0]])); +} + +- (void)testFastEnumeration +{ + size_t i = 0; + OFString *first, *second; + + for (OFString *key in _dictionary) { + OTAssertLessThan(i, 2); + + switch (i++) { + case 0: + first = key; + break; + case 1: + second = key; + break; + } + } + + OTAssertEqual(i, 2); + OTAssert( + ([first isEqual: keys[0]] && [second isEqual: keys[1]]) || + ([first isEqual: keys[1]] && [second isEqual: keys[0]])); +} + +#ifdef OF_HAVE_BLOCKS +- (void)testEnumerateKeysAndObjectsUsingBlock +{ + __block size_t i = 0; + __block OFString *first, *second; + + [_dictionary enumerateKeysAndObjectsUsingBlock: + ^ (id key, id object, bool *stop) { + OTAssertLessThan(i, 2); + + switch (i++) { + case 0: + first = key; + break; + case 1: + second = key; + break; + } + }]; + + OTAssertEqual(i, 2); + OTAssert( + ([first isEqual: keys[0]] && [second isEqual: keys[1]]) || + ([first isEqual: keys[1]] && [second isEqual: keys[0]])); +} + +- (void)testMappedDictionaryUsingBlock +{ + OTAssertEqualObjects([_dictionary mappedDictionaryUsingBlock: + ^ id (id key, id object) { + if ([key isEqual: keys[0]]) + return @"val1"; + if ([key isEqual: keys[1]]) + return @"val2"; + + return nil; + }], + ([OFDictionary dictionaryWithKeysAndObjects: + @"key1", @"val1", @"key2", @"val2", nil])); +} + +- (void)testFilteredDictionaryUsingBlock +{ + OTAssertEqualObjects([_dictionary filteredDictionaryUsingBlock: + ^ bool (id key, id object) { + return [key isEqual: keys[0]]; + }], + [OFDictionary dictionaryWithObject: objects[0] + forKey: keys[0]]); +} +#endif +@end + +@implementation CustomDictionary +- (instancetype)initWithObjects: (const id *)objects_ + forKeys: (const id *)keys_ + count: (size_t)count +{ + self = [super init]; + + @try { + _dictionary = [[OFDictionary alloc] initWithObjects: objects_ + forKeys: keys_ + count: count]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_dictionary release]; + + [super dealloc]; +} + +- (id)objectForKey: (id)key +{ + return [_dictionary objectForKey: key]; +} + +- (size_t)count +{ + return _dictionary.count; +} + +- (OFEnumerator *)keyEnumerator +{ + return [_dictionary keyEnumerator]; +} +@end ADDED new_tests/OFMutableDictionaryTests.h Index: new_tests/OFMutableDictionaryTests.h ================================================================== --- new_tests/OFMutableDictionaryTests.h +++ new_tests/OFMutableDictionaryTests.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" + +#import "OFDictionaryTests.h" + +@interface OFMutableDictionaryTests: OFDictionaryTests +{ + OFMutableDictionary *_mutableDictionary; +} +@end ADDED new_tests/OFMutableDictionaryTests.m Index: new_tests/OFMutableDictionaryTests.m ================================================================== --- new_tests/OFMutableDictionaryTests.m +++ new_tests/OFMutableDictionaryTests.m @@ -0,0 +1,174 @@ +/* + * 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 "OFMutableDictionaryTests.h" + +@interface CustomMutableDictionary: OFMutableDictionary +{ + OFMutableDictionary *_dictionary; +} +@end + +@implementation OFMutableDictionaryTests +- (Class)dictionaryClass +{ + return [CustomMutableDictionary class]; +} + +- (void)setUp +{ + [super setUp]; + + _mutableDictionary = [[self.dictionaryClass alloc] init]; +} + +- (void)dealloc +{ + [_mutableDictionary release]; + + [super dealloc]; +} + +- (void)testSetObjectForKey +{ + [_mutableDictionary setObject: @"bar" forKey: @"foo"]; + OTAssertEqualObjects([_mutableDictionary objectForKey: @"foo"], @"bar"); + + [_mutableDictionary setObject: @"qux" forKey: @"baz"]; + OTAssertEqualObjects(_mutableDictionary, + ([OFDictionary dictionaryWithKeysAndObjects: + @"foo", @"bar", @"baz", @"qux", nil])); +} + +- (void)testSetValueForKey +{ + [_mutableDictionary setValue: @"bar" forKey: @"foo"]; + OTAssertEqualObjects([_mutableDictionary objectForKey: @"foo"], @"bar"); + + [_mutableDictionary setValue: @"qux" forKey: @"baz"]; + OTAssertEqualObjects(_mutableDictionary, + ([OFDictionary dictionaryWithKeysAndObjects: + @"foo", @"bar", @"baz", @"qux", nil])); +} + +- (void)testRemoveObjectForKey +{ + [_mutableDictionary addEntriesFromDictionary: _dictionary]; + OTAssertEqual(_mutableDictionary.count, 2); + + [_mutableDictionary removeObjectForKey: @"key2"]; + OTAssertEqual(_mutableDictionary.count, 1); + OTAssertEqualObjects(_mutableDictionary, + [OFDictionary dictionaryWithObject: @"value1" forKey: @"key1"]); +} + +- (void)testMutableCopy +{ + OFMutableDictionary *copy = [[_dictionary mutableCopy] autorelease]; + + OTAssertEqualObjects(copy, _dictionary); + OTAssertNotEqual(copy, _dictionary); +} + +#ifdef OF_HAVE_BLOCKS +- (void)testReplaceObjectsUsingBlock +{ + OFMutableDictionary *mutableDictionary = + [[_dictionary mutableCopy] autorelease]; + + [mutableDictionary replaceObjectsUsingBlock: ^ id (id key, id object) { + if ([key isEqual: @"key1"]) + return @"value_1"; + if ([key isEqual: @"key2"]) + return @"value_2"; + + return nil; + }]; + + OTAssertEqualObjects(mutableDictionary, + ([OFDictionary dictionaryWithKeysAndObjects: + @"key1", @"value_1", @"key2", @"value_2", nil])); +} +#endif +@end + +@implementation CustomMutableDictionary +- (instancetype)init +{ + self = [super init]; + + @try { + _dictionary = [[OFMutableDictionary alloc] init]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)initWithObjects: (const id *)objects_ + forKeys: (const id *)keys_ + count: (size_t)count +{ + self = [super init]; + + @try { + _dictionary = [[OFMutableDictionary alloc] + initWithObjects: objects_ + forKeys: keys_ + count: count]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_dictionary release]; + + [super dealloc]; +} + +- (id)objectForKey: (id)key +{ + return [_dictionary objectForKey: key]; +} + +- (size_t)count +{ + return _dictionary.count; +} + +- (OFEnumerator *)keyEnumerator +{ + return [_dictionary keyEnumerator]; +} + +- (void)setObject: (id)object forKey: (id)key +{ + [_dictionary setObject: object forKey: key]; +} + +- (void)removeObjectForKey: (id)key +{ + [_dictionary removeObjectForKey: key]; +} +@end Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -12,11 +12,10 @@ DISTCLEAN = Info.plist PROG_NOINST = tests${PROG_SUFFIX} STATIC_LIB_NOINST = ${TESTS_STATIC_LIB} SRCS = OFDataTests.m \ - OFDictionaryTests.m \ OFMemoryStreamTests.m \ OFStreamTests.m \ OFValueTests.m \ OFXMLNodeTests.m \ OFXMLParserTests.m \ DELETED tests/OFDictionaryTests.m Index: tests/OFDictionaryTests.m ================================================================== --- tests/OFDictionaryTests.m +++ tests/OFDictionaryTests.m @@ -1,380 +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 *keys[] = { - @"key1", - @"key2" -}; -static OFString *values[] = { - @"value1", - @"value2" -}; - -@interface SimpleDictionary: OFDictionary -{ - OFMutableDictionary *_dictionary; -} -@end - -@interface SimpleMutableDictionary: OFMutableDictionary -{ - OFMutableDictionary *_dictionary; - unsigned long _mutations; -} -@end - -@implementation SimpleDictionary -- (instancetype)init -{ - self = [super init]; - - @try { - _dictionary = [[OFMutableDictionary alloc] init]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithKey: (id)key arguments: (va_list)arguments -{ - self = [super init]; - - @try { - _dictionary = [[OFMutableDictionary alloc] - initWithKey: key - arguments: arguments]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithObjects: (const id *)objects - forKeys: (const id *)keys_ - count: (size_t)count -{ - self = [super init]; - - @try { - _dictionary = [[OFMutableDictionary alloc] - initWithObjects: objects - forKeys: keys_ - count: count]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_dictionary release]; - - [super dealloc]; -} - -- (id)objectForKey: (id)key -{ - return [_dictionary objectForKey: key]; -} - -- (size_t)count -{ - return _dictionary.count; -} - -- (OFEnumerator *)keyEnumerator -{ - return [_dictionary keyEnumerator]; -} -@end - -@implementation SimpleMutableDictionary -+ (void)initialize -{ - if (self == [SimpleMutableDictionary class]) - [self inheritMethodsFromClass: [SimpleDictionary class]]; -} - -- (void)setObject: (id)object forKey: (id)key -{ - bool existed = ([_dictionary objectForKey: key] == nil); - - [_dictionary setObject: object forKey: key]; - - if (existed) - _mutations++; -} - -- (void)removeObjectForKey: (id)key -{ - bool existed = ([_dictionary objectForKey: key] == nil); - - [_dictionary removeObjectForKey: key]; - - if (existed) - _mutations++; -} - -- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state - objects: (id *)objects - count: (int)count -{ - int ret = [super countByEnumeratingWithState: state - objects: objects - count: count]; - - state->mutationsPtr = &_mutations; - - return ret; -} -@end - -@implementation TestsAppDelegate (OFDictionaryTests) -- (void)dictionaryTestsWithClass: (Class)dictionaryClass - mutableClass: (Class)mutableDictionaryClass -{ - void *pool = objc_autoreleasePoolPush(); - OFMutableDictionary *mutableDict = [mutableDictionaryClass dictionary]; - OFDictionary *dict; - OFEnumerator *keyEnumerator, *objectEnumerator; - OFArray *keysArray, *valuesArray; - - [mutableDict setObject: values[0] forKey: keys[0]]; - [mutableDict setValue: values[1] forKey: keys[1]]; - - TEST(@"-[objectForKey:]", - [[mutableDict objectForKey: keys[0]] isEqual: values[0]] && - [[mutableDict objectForKey: keys[1]] isEqual: values[1]] && - [mutableDict objectForKey: @"key3"] == nil) - - TEST(@"-[valueForKey:]", - [[mutableDict valueForKey: keys[0]] isEqual: values[0]] && - [[mutableDict valueForKey: @"@count"] isEqual: - [OFNumber numberWithInt: 2]]) - - EXPECT_EXCEPTION(@"Catching -[setValue:forKey:] on immutable " - @"dictionary", OFUndefinedKeyException, - [[dictionaryClass dictionary] setValue: @"x" forKey: @"x"]) - - TEST(@"-[containsObject:]", - [mutableDict containsObject: values[0]] && - ![mutableDict containsObject: @"nonexistent"]) - - TEST(@"-[containsObjectIdenticalTo:]", - [mutableDict containsObjectIdenticalTo: values[0]] && - ![mutableDict containsObjectIdenticalTo: - [OFString stringWithString: values[0]]]) - - TEST(@"-[description]", - [[mutableDict description] isEqual: - @"{\n\tkey1 = value1;\n\tkey2 = value2;\n}"]) - - TEST(@"-[allKeys]", - [[mutableDict allKeys] isEqual: - [OFArray arrayWithObjects: keys[0], keys[1], nil]]) - - TEST(@"-[allObjects]", - [[mutableDict allObjects] isEqual: - [OFArray arrayWithObjects: values[0], values[1], nil]]) - - TEST(@"-[keyEnumerator]", (keyEnumerator = [mutableDict keyEnumerator])) - TEST(@"-[objectEnumerator]", - (objectEnumerator = [mutableDict objectEnumerator])) - - TEST(@"OFEnumerator's -[nextObject]", - [[keyEnumerator nextObject] isEqual: keys[0]] && - [[objectEnumerator nextObject] isEqual: values[0]] && - [[keyEnumerator nextObject] isEqual: keys[1]] && - [[objectEnumerator nextObject] isEqual: values[1]] && - [keyEnumerator nextObject] == nil && - [objectEnumerator nextObject] == nil) - - [mutableDict removeObjectForKey: keys[0]]; - - EXPECT_EXCEPTION(@"Detection of mutation during enumeration", - OFEnumerationMutationException, [keyEnumerator nextObject]); - - [mutableDict setObject: values[0] forKey: keys[0]]; - - size_t i = 0; - bool ok = true; - - for (OFString *key in mutableDict) { - if (i > 1 || ![key isEqual: keys[i]]) { - ok = false; - break; - } - - [mutableDict setObject: [mutableDict objectForKey: key] - forKey: key]; - i++; - } - - TEST(@"Fast Enumeration", ok) - - ok = false; - @try { - for (OFString *key in mutableDict) { - (void)key; - [mutableDict setObject: @"" forKey: @""]; - } - } @catch (OFEnumerationMutationException *e) { - ok = true; - } - - TEST(@"Detection of mutation during Fast Enumeration", ok) - - [mutableDict removeObjectForKey: @""]; - -#ifdef OF_HAVE_BLOCKS - { - __block size_t j = 0; - __block bool blockOk = true; - - [mutableDict enumerateKeysAndObjectsUsingBlock: - ^ (id key, id object, bool *stop) { - if (j > 1 || ![key isEqual: keys[j]]) { - blockOk = false; - *stop = true; - return; - } - - [mutableDict setObject: [mutableDict objectForKey: key] - forKey: key]; - j++; - }]; - - TEST(@"Enumeration using blocks", blockOk) - - blockOk = false; - @try { - [mutableDict enumerateKeysAndObjectsUsingBlock: - ^ (id key, id object, bool *stop) { - [mutableDict setObject: @"" forKey: @""]; - }]; - } @catch (OFEnumerationMutationException *e) { - blockOk = true; - } - - TEST(@"Detection of mutation during enumeration using blocks", - blockOk) - - [mutableDict removeObjectForKey: @""]; - } - - TEST(@"-[replaceObjectsUsingBlock:]", - R([mutableDict replaceObjectsUsingBlock: ^ id (id key, id object) { - if ([key isEqual: keys[0]]) - return @"value_1"; - if ([key isEqual: keys[1]]) - return @"value_2"; - - return nil; - }]) && [[mutableDict objectForKey: keys[0]] isEqual: @"value_1"] && - [[mutableDict objectForKey: keys[1]] isEqual: @"value_2"]) - - TEST(@"-[mappedDictionaryUsingBlock:]", - [[[mutableDict mappedDictionaryUsingBlock: - ^ id (id key, id object) { - if ([key isEqual: keys[0]]) - return @"val1"; - if ([key isEqual: keys[1]]) - return @"val2"; - - return nil; - }] description] isEqual: @"{\n\tkey1 = val1;\n\tkey2 = val2;\n}"]) - - TEST(@"-[filteredDictionaryUsingBlock:]", - [[[mutableDict filteredDictionaryUsingBlock: - ^ bool (id key, id object) { - return [key isEqual: keys[0]]; - }] description] isEqual: @"{\n\tkey1 = value_1;\n}"]) -#endif - - TEST(@"-[count]", mutableDict.count == 2) - - TEST(@"+[dictionaryWithKeysAndObjects:]", - (dict = [dictionaryClass dictionaryWithKeysAndObjects: - @"foo", @"bar", @"baz", @"qux", nil]) && - [[dict objectForKey: @"foo"] isEqual: @"bar"] && - [[dict objectForKey: @"baz"] isEqual: @"qux"]) - - TEST(@"+[dictionaryWithObject:forKey:]", - (dict = [dictionaryClass dictionaryWithObject: @"bar" - forKey: @"foo"]) && - [[dict objectForKey: @"foo"] isEqual: @"bar"]) - - keysArray = [OFArray arrayWithObjects: keys[0], keys[1], nil]; - valuesArray = [OFArray arrayWithObjects: values[0], values[1], nil]; - TEST(@"+[dictionaryWithObjects:forKeys:]", - (dict = [dictionaryClass dictionaryWithObjects: valuesArray - forKeys: keysArray]) && - [[dict objectForKey: keys[0]] isEqual: values[0]] && - [[dict objectForKey: keys[1]] isEqual: values[1]]) - - TEST(@"-[copy]", - (dict = [[dict copy] autorelease]) && - [[dict objectForKey: keys[0]] isEqual: values[0]] && - [[dict objectForKey: keys[1]] isEqual: values[1]]) - - TEST(@"-[mutableCopy]", - (mutableDict = [[dict mutableCopy] autorelease]) && - mutableDict.count == dict.count && - [[mutableDict objectForKey: keys[0]] isEqual: values[0]] && - [[mutableDict objectForKey: keys[1]] isEqual: values[1]] && - R([mutableDict setObject: @"value3" forKey: @"key3"]) && - [[mutableDict objectForKey: @"key3"] isEqual: @"value3"] && - [[mutableDict objectForKey: keys[0]] isEqual: values[0]] && - R([mutableDict setObject: @"foo" forKey: keys[0]]) && - [[mutableDict objectForKey: keys[0]] isEqual: @"foo"]) - - TEST(@"-[removeObjectForKey:]", - R([mutableDict removeObjectForKey: keys[0]]) && - [mutableDict objectForKey: keys[0]] == nil) - - [mutableDict setObject: @"foo" forKey: keys[0]]; - TEST(@"-[isEqual:]", ![mutableDict isEqual: dict] && - R([mutableDict removeObjectForKey: @"key3"]) && - ![mutableDict isEqual: dict] && - R([mutableDict setObject: values[0] forKey: keys[0]]) && - [mutableDict isEqual: dict]) - - objc_autoreleasePoolPop(pool); -} - -- (void)dictionaryTests -{ - module = @"OFDictionary"; - [self dictionaryTestsWithClass: [SimpleDictionary class] - mutableClass: [SimpleMutableDictionary class]]; - - module = @"OFDictionary_hashtable"; - [self dictionaryTestsWithClass: [OFDictionary class] - mutableClass: [OFMutableDictionary class]]; -} -@end Index: tests/TestsAppDelegate.h ================================================================== --- tests/TestsAppDelegate.h +++ tests/TestsAppDelegate.h @@ -61,14 +61,10 @@ @interface TestsAppDelegate (OFDataTests) - (void)dataTests; @end -@interface TestsAppDelegate (OFDictionaryTests) -- (void)dictionaryTests; -@end - @interface TestsAppDelegate (OFMemoryStreamTests) - (void)memoryStreamTests; @end @interface TestsAppDelegate (OFStreamTests) Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -369,11 +369,10 @@ [[OFFileManager defaultManager] changeCurrentDirectoryPath: @"/apps/objfw-tests"]; #endif [self dataTests]; - [self dictionaryTests]; [self valueTests]; [self streamTests]; [self memoryStreamTests]; [self XMLParserTests]; [self XMLNodeTests];