/*
* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013
* 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.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 "OFDictionary.h"
#import "OFString.h"
#import "OFArray.h"
#import "OFAutoreleasePool.h"
#import "OFEnumerationMutationException.h"
#import "TestsAppDelegate.h"
static OFString *module = @"OFDictionary";
static OFString *keys[] = {
@"key1",
@"key2"
};
static OFString *values[] = {
@"value1",
@"value2"
};
@implementation TestsAppDelegate (OFDictionaryTests)
- (void)dictionaryTests
{
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
OFMutableDictionary *dict = [OFMutableDictionary dictionary];
OFDictionary *idict;
OFEnumerator *key_enum, *obj_enum;
OFArray *akeys, *avalues;
[dict setObject: values[0]
forKey: keys[0]];
[dict setObject: values[1]
forKey: keys[1]];
TEST(@"-[objectForKey:]",
[[dict objectForKey: keys[0]] isEqual: values[0]] &&
[[dict objectForKey: keys[1]] isEqual: values[1]] &&
[dict objectForKey: @"key3"] == nil)
TEST(@"-[containsObject:]",
[dict containsObject: values[0]] &&
![dict containsObject: @"nonexistant"])
TEST(@"-[containsObjectIdenticalTo:]",
[dict containsObjectIdenticalTo: values[0]] &&
![dict containsObjectIdenticalTo:
[OFString stringWithString: values[0]]])
TEST(@"-[description]",
[[dict description] isEqual:
@"{\n\tkey1 = value1;\n\tkey2 = value2;\n}"])
TEST(@"-[allKeys]",
[[dict allKeys] isEqual: ([OFArray arrayWithObjects: keys[0],
keys[1], nil])])
TEST(@"-[allObjects]",
[[dict allObjects] isEqual: ([OFArray arrayWithObjects: values[0],
values[1], nil])])
TEST(@"-[keyEnumerator]", (key_enum = [dict keyEnumerator]))
TEST(@"-[objectEnumerator]", (obj_enum = [dict objectEnumerator]))
TEST(@"OFEnumerator's -[nextObject]",
[[key_enum nextObject] isEqual: keys[0]] &&
[[obj_enum nextObject] isEqual: values[0]] &&
[[key_enum nextObject] isEqual: keys[1]] &&
[[obj_enum nextObject] isEqual: values[1]] &&
[key_enum nextObject] == nil && [obj_enum nextObject] == nil)
[key_enum reset];
[dict removeObjectForKey: keys[0]];
EXPECT_EXCEPTION(@"Detection of mutation during enumeration",
OFEnumerationMutationException, [key_enum nextObject]);
[dict setObject: values[0]
forKey: keys[0]];
#ifdef OF_HAVE_FAST_ENUMERATION
size_t i = 0;
bool ok = true;
for (OFString *key in dict) {
if (i > 1 || ![key isEqual: keys[i]]) {
ok = false;
break;
}
[dict setObject: [dict objectForKey: key]
forKey: key];
i++;
}
TEST(@"Fast Enumeration", ok)
ok = false;
@try {
for (OFString *key in dict) {
(void)key;
[dict setObject: @""
forKey: @""];
}
} @catch (OFEnumerationMutationException *e) {
ok = true;
}
TEST(@"Detection of mutation during Fast Enumeration", ok)
[dict removeObjectForKey: @""];
#endif
#ifdef OF_HAVE_BLOCKS
{
__block size_t i = 0;
__block bool ok = true;
[dict enumerateKeysAndObjectsUsingBlock:
^ (id key, id obj, bool *stop) {
if (i > 1 || ![key isEqual: keys[i]]) {
ok = false;
*stop = true;
return;
}
[dict setObject: [dict objectForKey: key]
forKey: key];
i++;
}];
TEST(@"Enumeration using blocks", ok)
ok = false;
@try {
[dict enumerateKeysAndObjectsUsingBlock:
^ (id key, id obj, bool *stop) {
[dict setObject: @""
forKey: @""];
}];
} @catch (OFEnumerationMutationException *e) {
ok = true;
}
TEST(@"Detection of mutation during enumeration using blocks",
ok)
[dict removeObjectForKey: @""];
}
TEST(@"-[replaceObjectsUsingBlock:]",
R([dict replaceObjectsUsingBlock: ^ id (id key, id obj) {
if ([key isEqual: keys[0]])
return @"value_1";
if ([key isEqual: keys[1]])
return @"value_2";
return nil;
}]) && [[dict objectForKey: keys[0]] isEqual: @"value_1"] &&
[[dict objectForKey: keys[1]] isEqual: @"value_2"])
TEST(@"-[mappedDictionaryUsingBlock:]",
[[[dict mappedDictionaryUsingBlock: ^ id (id key, id obj) {
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:]",
[[[dict filteredDictionaryUsingBlock: ^ bool (id key, id obj) {
return [key isEqual: keys[0]];
}] description] isEqual: @"{\n\tkey1 = value_1;\n}"])
#endif
TEST(@"-[count]", [dict count] == 2)
TEST(@"+[dictionaryWithKeysAndObjects:]",
(idict = [OFDictionary dictionaryWithKeysAndObjects: @"foo", @"bar",
@"baz", @"qux",
nil]) &&
[[idict objectForKey: @"foo"] isEqual: @"bar"] &&
[[idict objectForKey: @"baz"] isEqual: @"qux"])
TEST(@"+[dictionaryWithObject:forKey:]",
(idict = [OFDictionary dictionaryWithObject: @"bar"
forKey: @"foo"]) &&
[[idict objectForKey: @"foo"] isEqual: @"bar"])
akeys = [OFArray arrayWithObjects: keys[0], keys[1], nil];
avalues = [OFArray arrayWithObjects: values[0], values[1], nil];
TEST(@"+[dictionaryWithObjects:forKeys:]",
(idict = [OFDictionary dictionaryWithObjects: avalues
forKeys: akeys]) &&
[[idict objectForKey: keys[0]] isEqual: values[0]] &&
[[idict objectForKey: keys[1]] isEqual: values[1]])
TEST(@"-[copy]",
(idict = [[idict copy] autorelease]) &&
[[idict objectForKey: keys[0]] isEqual: values[0]] &&
[[idict objectForKey: keys[1]] isEqual: values[1]])
TEST(@"-[mutableCopy]",
(dict = [[idict mutableCopy] autorelease]) &&
[dict count] == [idict count] &&
[[dict objectForKey: keys[0]] isEqual: values[0]] &&
[[dict objectForKey: keys[1]] isEqual: values[1]] &&
R([dict setObject: @"value3"
forKey: @"key3"]) &&
[[dict objectForKey: @"key3"] isEqual: @"value3"] &&
[[dict objectForKey: keys[0]] isEqual: values[0]] &&
R([dict setObject: @"foo"
forKey: keys[0]]) &&
[[dict objectForKey: keys[0]] isEqual: @"foo"])
TEST(@"-[removeObjectForKey:]",
R([dict removeObjectForKey: keys[0]]) &&
[dict objectForKey: keys[0]] == nil)
[dict setObject: @"foo"
forKey: keys[0]];
TEST(@"-[isEqual:]", ![dict isEqual: idict] &&
R([dict removeObjectForKey: @"key3"]) &&
![dict isEqual: idict] &&
R([dict setObject: values[0]
forKey: keys[0]]) &&
[dict isEqual: idict])
[pool drain];
}
@end