/*
* Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
*
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 3.0 only,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3.0 along with this program. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#import "OFArrayTests.h"
@interface CustomArray: OFArray
{
OFArray *_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)testHash
{
OFArray *array = [self.arrayClass arrayWithObjects: cArray count: 3];
OTAssertEqual(array.hash, _array.hash);
OTAssertNotEqual(array.hash, [[OFArray array] hash]);
}
- (void)testCopy
{
OTAssertEqualObjects([[_array copy] autorelease], _array);
}
- (void)testMutableCopy
{
OTAssertEqualObjects([[_array mutableCopy] autorelease], _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) {
OTAssertLessThan(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)initWithObjects: (id const *)objects count: (size_t)count
{
self = [super init];
@try {
_array = [[OFArray 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