| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- #import "Firestore/third_party/Immutable/FSTArraySortedDictionary.h"
- #import <XCTest/XCTest.h>
- @interface FSTArraySortedDictionary (Test)
- // Override methods to return subtype.
- - (FSTArraySortedDictionary *)dictionaryBySettingObject:(id)aValue forKey:(id)aKey;
- - (FSTArraySortedDictionary *)dictionaryByRemovingObjectForKey:(id)aKey;
- @end
- @interface FSTArraySortedDictionaryTests : XCTestCase
- @end
- @implementation FSTArraySortedDictionaryTests
- - (NSComparator)defaultComparator {
- return ^(id obj1, id obj2) {
- NSAssert([obj1 respondsToSelector:@selector(compare:)] &&
- [obj2 respondsToSelector:@selector(compare:)],
- @"Objects must support compare: %@ %@", obj1, obj2);
- return [obj1 compare:obj2];
- };
- }
- - (void)testSearchForSpecificKey {
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- map = [map dictionaryBySettingObject:@1 forKey:@1];
- map = [map dictionaryBySettingObject:@2 forKey:@2];
- XCTAssertEqualObjects([map objectForKey:@1], @1, @"Found first object");
- XCTAssertEqualObjects([map objectForKey:@2], @2, @"Found second object");
- XCTAssertEqualObjects(map[@1], @1, @"Found first object");
- XCTAssertEqualObjects(map[@2], @2, @"Found second object");
- XCTAssertNil([map objectForKey:@3], @"Properly not found object");
- }
- - (void)testRemoveKeyValuePair {
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- map = [map dictionaryBySettingObject:@1 forKey:@1];
- map = [map dictionaryBySettingObject:@2 forKey:@2];
- FSTImmutableSortedDictionary *newMap = [map dictionaryByRemovingObjectForKey:@1];
- XCTAssertEqualObjects([newMap objectForKey:@2], @2, @"Found second object");
- XCTAssertNil([newMap objectForKey:@1], @"Properly not found object");
- // Make sure the original one is not mutated
- XCTAssertEqualObjects([map objectForKey:@1], @1, @"Found first object");
- XCTAssertEqualObjects([map objectForKey:@2], @2, @"Found second object");
- }
- - (void)testMoreRemovals {
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- map = [map dictionaryBySettingObject:@1 forKey:@1];
- map = [map dictionaryBySettingObject:@50 forKey:@50];
- map = [map dictionaryBySettingObject:@3 forKey:@3];
- map = [map dictionaryBySettingObject:@4 forKey:@4];
- map = [map dictionaryBySettingObject:@7 forKey:@7];
- map = [map dictionaryBySettingObject:@9 forKey:@9];
- map = [map dictionaryBySettingObject:@1 forKey:@20];
- map = [map dictionaryBySettingObject:@18 forKey:@18];
- map = [map dictionaryBySettingObject:@3 forKey:@2];
- map = [map dictionaryBySettingObject:@4 forKey:@71];
- map = [map dictionaryBySettingObject:@7 forKey:@42];
- map = [map dictionaryBySettingObject:@9 forKey:@88];
- XCTAssertNotNil([map objectForKey:@7], @"Found object");
- XCTAssertNotNil([map objectForKey:@3], @"Found object");
- XCTAssertNotNil([map objectForKey:@1], @"Found object");
- FSTImmutableSortedDictionary *m1 = [map dictionaryByRemovingObjectForKey:@7];
- FSTImmutableSortedDictionary *m2 = [map dictionaryByRemovingObjectForKey:@3];
- FSTImmutableSortedDictionary *m3 = [map dictionaryByRemovingObjectForKey:@1];
- XCTAssertNil([m1 objectForKey:@7], @"Removed object");
- XCTAssertNotNil([m1 objectForKey:@3], @"Found object");
- XCTAssertNotNil([m1 objectForKey:@1], @"Found object");
- XCTAssertNil([m2 objectForKey:@3], @"Removed object");
- XCTAssertNotNil([m2 objectForKey:@7], @"Found object");
- XCTAssertNotNil([m2 objectForKey:@1], @"Found object");
- XCTAssertNil([m3 objectForKey:@1], @"Removed object");
- XCTAssertNotNil([m3 objectForKey:@7], @"Found object");
- XCTAssertNotNil([m3 objectForKey:@3], @"Found object");
- }
- - (void)testRemovalBug {
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- map = [map dictionaryBySettingObject:@1 forKey:@1];
- map = [map dictionaryBySettingObject:@2 forKey:@2];
- map = [map dictionaryBySettingObject:@3 forKey:@3];
- XCTAssertEqualObjects([map objectForKey:@1], @1, @"Found object");
- XCTAssertEqualObjects([map objectForKey:@2], @2, @"Found object");
- XCTAssertEqualObjects([map objectForKey:@3], @3, @"Found object");
- FSTImmutableSortedDictionary *m1 = [map dictionaryByRemovingObjectForKey:@2];
- XCTAssertEqualObjects([m1 objectForKey:@1], @1, @"Found object");
- XCTAssertEqualObjects([m1 objectForKey:@3], @3, @"Found object");
- XCTAssertNil([m1 objectForKey:@2], @"Removed object");
- }
- - (void)testIncreasing {
- int total = 100;
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- for (int i = 0; i < total; i++) {
- NSNumber *item = @(i);
- map = [map dictionaryBySettingObject:item forKey:item];
- }
- XCTAssertTrue(map.count == 100, @"Check if all 100 objects are in the map");
- for (int i = 0; i < total; i++) {
- NSNumber *item = @(i);
- map = [map dictionaryByRemovingObjectForKey:item];
- }
- XCTAssertTrue(map.count == 0, @"Check if all 100 objects were removed");
- }
- - (void)testOverride {
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- map = [map dictionaryBySettingObject:@10 forKey:@10];
- map = [map dictionaryBySettingObject:@8 forKey:@10];
- XCTAssertEqualObjects([map objectForKey:@10], @8, @"Found first object");
- }
- - (void)testEmpty {
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- map = [map dictionaryBySettingObject:@10 forKey:@10];
- map = [map dictionaryByRemovingObjectForKey:@10];
- XCTAssertTrue([map isEmpty], @"Properly empty");
- }
- - (void)testEmptyGet {
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- XCTAssertNil([map objectForKey:@"something"], @"Properly nil");
- }
- - (void)testEmptyCount {
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- XCTAssertTrue([map count] == 0, @"Properly zero count");
- }
- - (void)testEmptyRemoval {
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- map = [map dictionaryByRemovingObjectForKey:@"something"];
- XCTAssertTrue(map.count == 0, @"Properly zero count");
- }
- - (void)testReverseTraversal {
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- map = [map dictionaryBySettingObject:@1 forKey:@1];
- map = [map dictionaryBySettingObject:@5 forKey:@5];
- map = [map dictionaryBySettingObject:@3 forKey:@3];
- map = [map dictionaryBySettingObject:@2 forKey:@2];
- map = [map dictionaryBySettingObject:@4 forKey:@4];
- __block int next = 5;
- [map enumerateKeysAndObjectsReverse:YES
- usingBlock:^(id key, id value, BOOL *stop) {
- XCTAssertEqualObjects(key, @(next), @"Properly equal");
- next = next - 1;
- }];
- }
- - (void)testInsertionAndRemovalOfAHundredItems {
- NSUInteger n = 100;
- NSMutableArray *toInsert = [NSMutableArray arrayWithCapacity:n];
- NSMutableArray *toRemove = [NSMutableArray arrayWithCapacity:n];
- for (NSUInteger i = 0; i < n; i++) {
- [toInsert addObject:@(i)];
- [toRemove addObject:@(i)];
- }
- [self shuffleArray:toInsert];
- [self shuffleArray:toRemove];
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- // add them to the dictionary
- for (NSUInteger i = 0; i < n; i++) {
- map = [map dictionaryBySettingObject:toInsert[i] forKey:toInsert[i]];
- }
- XCTAssertTrue(map.count == n, @"Check if all N objects are in the map");
- // check the order is correct
- __block int next = 0;
- [map enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
- XCTAssertEqualObjects(key, @(next), @"Correct key");
- XCTAssertEqualObjects(value, @(next), @"Correct value");
- next = next + 1;
- }];
- XCTAssertEqual(next, n, @"Check we traversed all of the items");
- // remove them
- for (NSUInteger i = 0; i < n; i++) {
- map = [map dictionaryByRemovingObjectForKey:toRemove[i]];
- }
- XCTAssertEqual(map.count, 0, @"Check we removed all of the items");
- }
- - (void)shuffleArray:(NSMutableArray *)array {
- NSUInteger count = array.count;
- for (NSUInteger i = 0; i < count; i++) {
- NSUInteger nElements = count - i;
- NSUInteger n = (arc4random() % nElements) + i;
- [array exchangeObjectAtIndex:i withObjectAtIndex:n];
- }
- }
- - (void)testBalanceProblem {
- NSArray *toInsert = @[ @1, @7, @8, @5, @2, @6, @4, @0, @3 ];
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- // add them to the dictionary
- for (NSUInteger i = 0; i < toInsert.count; i++) {
- map = [map dictionaryBySettingObject:toInsert[i] forKey:toInsert[i]];
- }
- XCTAssertTrue(map.count == toInsert.count, @"Check if all N objects are in the map");
- // check the order is correct
- __block int next = 0;
- [map enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
- XCTAssertEqualObjects(key, @(next), @"Correct key");
- XCTAssertEqualObjects(value, @(next), @"Correct value");
- next = next + 1;
- }];
- XCTAssertEqual((int)next, (int)toInsert.count, @"Check we traversed all of the items");
- }
- // This is a macro instead of a method so that the failures show on the proper lines.
- #define ASSERT_ENUMERATOR(enumerator, start, end, step) \
- do { \
- NSEnumerator *e = (enumerator); \
- id next = nil; \
- for (NSUInteger i = (start); i != (end); i += (step)) { \
- next = [e nextObject]; \
- XCTAssertNotNil(next, @"expected %lu. got nil.", (unsigned long)i); \
- XCTAssertEqualObjects(next, @(i), "expected %lu. got %@.", (unsigned long)i, next); \
- } \
- next = [e nextObject]; \
- XCTAssertNil(next, @"expected nil. got %@.", next); \
- } while (0)
- - (void)testEnumerator {
- NSUInteger n = 100;
- NSMutableArray *toInsert = [NSMutableArray arrayWithCapacity:n];
- for (int i = 0; i < n; i++) {
- [toInsert addObject:@(i)];
- }
- [self shuffleArray:toInsert];
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:self.defaultComparator];
- // add them to the dictionary
- for (NSUInteger i = 0; i < n; i++) {
- map = [map dictionaryBySettingObject:toInsert[i] forKey:toInsert[i]];
- }
- XCTAssertTrue(map.count == n, @"Check if all N objects are in the map");
- ASSERT_ENUMERATOR([map keyEnumerator], 0, 100, 1);
- }
- - (void)testReverseEnumerator {
- NSUInteger n = 20;
- NSMutableArray *toInsert = [NSMutableArray arrayWithCapacity:n];
- for (int i = 0; i < n; i++) {
- [toInsert addObject:@(i)];
- }
- [self shuffleArray:toInsert];
- FSTImmutableSortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- // Add them to the dictionary.
- for (NSUInteger i = 0; i < n; i++) {
- map = [map dictionaryBySettingObject:toInsert[i] forKey:toInsert[i]];
- }
- XCTAssertTrue(map.count == n, @"Check if all N objects are in the map");
- XCTAssertTrue([map isKindOfClass:FSTArraySortedDictionary.class],
- @"Make sure we still have a array backed dictionary");
- ASSERT_ENUMERATOR([map reverseKeyEnumerator], n - 1, -1, -1);
- }
- - (void)testEnumeratorFrom {
- // Create a dictionary with the even numbers in [2, 42).
- NSUInteger n = 20;
- NSMutableArray *toInsert = [NSMutableArray arrayWithCapacity:n];
- for (int i = 0; i < n; i++) {
- [toInsert addObject:@(i * 2 + 2)];
- }
- [self shuffleArray:toInsert];
- FSTImmutableSortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- // Add them to the dictionary.
- for (NSUInteger i = 0; i < n; i++) {
- map = [map dictionaryBySettingObject:toInsert[i] forKey:toInsert[i]];
- }
- XCTAssertTrue(map.count == n, @"Check if all N objects are in the map");
- XCTAssertTrue([map isKindOfClass:FSTArraySortedDictionary.class],
- @"Make sure we still have a array backed dictionary");
- // Test from before keys.
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@0], 2, n * 2 + 2, 2);
- // Test from after keys.
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@100], 0, 0, 2);
- // Test from key in map.
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@10], 10, n * 2 + 2, 2);
- // Test from in between keys.
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@11], 12, n * 2 + 2, 2);
- }
- - (void)testEnumeratorFromTo {
- // Create a dictionary with the even numbers in [2, 42).
- NSUInteger n = 20;
- NSMutableArray *toInsert = [NSMutableArray arrayWithCapacity:n];
- for (int i = 0; i < n; i++) {
- [toInsert addObject:@(i * 2 + 2)];
- }
- [self shuffleArray:toInsert];
- FSTImmutableSortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- // Add them to the dictionary.
- for (NSUInteger i = 0; i < n; i++) {
- map = [map dictionaryBySettingObject:toInsert[i] forKey:toInsert[i]];
- }
- XCTAssertTrue(map.count == n, @"Check if all N objects are in the map");
- XCTAssertTrue([map isKindOfClass:FSTArraySortedDictionary.class],
- @"Make sure we still have an array backed dictionary");
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@0 to:@1], 2, 2, 2); // before to before
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@0 to:@100], 2, n * 2 + 2, 2); // before to after
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@0 to:@6], 2, 6, 2); // before to key in map
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@0 to:@7], 2, 8, 2); // before to in between keys
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@100 to:@0], 2, 2, 2); // after to before
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@100 to:@110], 2, 2, 2); // after to after
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@100 to:@6], 2, 2, 2); // after to key in map
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@100 to:@7], 2, 2, 2); // after to in between
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@6 to:@0], 6, 6, 2); // key in map to before
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@6 to:@100], 6, n * 2 + 2, 2); // key in map to after
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@6 to:@10], 6, 10, 2); // key in map to key in map
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@6 to:@11], 6, 12, 2); // key in map to in between
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@7 to:@0], 8, 8, 2); // in between to before
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@7 to:@100], 8, n * 2 + 2, 2); // in between to after
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@7 to:@10], 8, 10, 2); // in between to key in map
- ASSERT_ENUMERATOR([map keyEnumeratorFrom:@7 to:@13], 8, 14, 2); // in between to in between
- }
- - (void)testReverseEnumeratorFrom {
- NSUInteger n = 20;
- NSMutableArray *toInsert = [NSMutableArray arrayWithCapacity:n];
- for (int i = 0; i < n; i++) {
- [toInsert addObject:@(i * 2 + 2)];
- }
- [self shuffleArray:toInsert];
- FSTImmutableSortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- // add them to the dictionary
- for (NSUInteger i = 0; i < n; i++) {
- map = [map dictionaryBySettingObject:toInsert[i] forKey:toInsert[i]];
- }
- XCTAssertTrue(map.count == n, @"Check if all N objects are in the map");
- XCTAssertTrue([map isKindOfClass:FSTArraySortedDictionary.class],
- @"Make sure we still have a array backed dictionary");
- // Test from before keys.
- ASSERT_ENUMERATOR([map reverseKeyEnumeratorFrom:@0], 0, 0, -2);
- // Test from after keys.
- ASSERT_ENUMERATOR([map reverseKeyEnumeratorFrom:@100], n * 2, 0, -2);
- // Test from key in map.
- ASSERT_ENUMERATOR([map reverseKeyEnumeratorFrom:@10], 10, 0, -2);
- // Test from in between keys.
- ASSERT_ENUMERATOR([map reverseKeyEnumeratorFrom:@11], 10, 0, -2);
- }
- #undef ASSERT_ENUMERATOR
- - (void)testIndexOf {
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- map = [map dictionaryBySettingObject:@1 forKey:@1];
- map = [map dictionaryBySettingObject:@50 forKey:@50];
- map = [map dictionaryBySettingObject:@3 forKey:@3];
- map = [map dictionaryBySettingObject:@4 forKey:@4];
- map = [map dictionaryBySettingObject:@7 forKey:@7];
- map = [map dictionaryBySettingObject:@9 forKey:@9];
- XCTAssertEqual([map indexOfKey:@0], NSNotFound);
- XCTAssertEqual([map indexOfKey:@1], 0);
- XCTAssertEqual([map indexOfKey:@2], NSNotFound);
- XCTAssertEqual([map indexOfKey:@3], 1);
- XCTAssertEqual([map indexOfKey:@4], 2);
- XCTAssertEqual([map indexOfKey:@5], NSNotFound);
- XCTAssertEqual([map indexOfKey:@6], NSNotFound);
- XCTAssertEqual([map indexOfKey:@7], 3);
- XCTAssertEqual([map indexOfKey:@8], NSNotFound);
- XCTAssertEqual([map indexOfKey:@9], 4);
- XCTAssertEqual([map indexOfKey:@50], 5);
- }
- @end
|