/*
* 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"
#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]);
}
- (void)testHash
{
OTAssertEqual(_dictionary.hash,
[[OFDictionary dictionaryWithObjects: objects
forKeys: keys
count: 2] hash]);
OTAssertNotEqual(_dictionary.hash,
[[OFDictionary dictionaryWithObject: objects[0]
forKey: keys[0]] hash]);
}
- (void)testCopy
{
OTAssertEqualObjects([[_dictionary copy] autorelease], _dictionary);
}
- (void)testMutableCopy
{
OTAssertEqualObjects(
[[_dictionary mutableCopy] 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 = nil, *second = nil;
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 = nil, *second = nil;
[_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