FTreeSortedDictionaryTests.m 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <XCTest/XCTest.h>
  17. #import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h"
  18. #import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h"
  19. #import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h"
  20. #import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h"
  21. @interface FLLRBValueNode (Tests)
  22. - (id<FLLRBNode>)rotateLeft;
  23. - (id<FLLRBNode>)rotateRight;
  24. @end
  25. @interface FTreeSortedDictionaryTests : XCTestCase
  26. @end
  27. @implementation FTreeSortedDictionaryTests
  28. - (NSComparator)defaultComparator {
  29. return ^(id obj1, id obj2) {
  30. if ([obj1 respondsToSelector:@selector(compare:)] &&
  31. [obj2 respondsToSelector:@selector(compare:)]) {
  32. return [obj1 compare:obj2];
  33. } else {
  34. if (obj1 < obj2) {
  35. return (NSComparisonResult)NSOrderedAscending;
  36. } else if (obj1 > obj2) {
  37. return (NSComparisonResult)NSOrderedDescending;
  38. } else {
  39. return (NSComparisonResult)NSOrderedSame;
  40. }
  41. }
  42. };
  43. }
  44. - (void)testCreateNode {
  45. FTreeSortedDictionary* map = [[[FTreeSortedDictionary alloc]
  46. initWithComparator:[self defaultComparator]] insertKey:@"key" withValue:@"value"];
  47. XCTAssertTrue([map.root.left isEmpty], @"Left child is properly empty");
  48. XCTAssertTrue([map.root.right isEmpty], @"Right child is properly empty");
  49. }
  50. - (void)testGetNilReturnsNil {
  51. FImmutableSortedDictionary* map1 = [[[FTreeSortedDictionary alloc]
  52. initWithComparator:[self defaultComparator]] insertKey:@"key" withValue:@"value"];
  53. XCTAssertNil([map1 get:nil]);
  54. FImmutableSortedDictionary* map2 =
  55. [[[FTreeSortedDictionary alloc] initWithComparator:^NSComparisonResult(id obj1, id obj2) {
  56. return [obj1 compare:obj2];
  57. }] insertKey:@"key" withValue:@"value"];
  58. XCTAssertNil([map2 get:nil]);
  59. }
  60. - (void)testSearchForSpecificKey {
  61. FTreeSortedDictionary* map = [[[[FTreeSortedDictionary alloc]
  62. initWithComparator:[self defaultComparator]] insertKey:@1 withValue:@1] insertKey:@2
  63. withValue:@2];
  64. XCTAssertEqualObjects([map get:@1], @1, @"Found first object");
  65. XCTAssertEqualObjects([map get:@2], @2, @"Found second object");
  66. XCTAssertNil([map get:@3], @"Properly not found object");
  67. }
  68. - (void)testInsertNewKeyValuePair {
  69. FTreeSortedDictionary* map = [[[[FTreeSortedDictionary alloc]
  70. initWithComparator:[self defaultComparator]] insertKey:@1 withValue:@1] insertKey:@2
  71. withValue:@2];
  72. XCTAssertEqualObjects(map.root.key, @2, @"Check the root key");
  73. XCTAssertEqualObjects(map.root.left.key, @1, @"Check the root.left key");
  74. }
  75. - (void)testRemoveKeyValuePair {
  76. FTreeSortedDictionary* map = [[[[FTreeSortedDictionary alloc]
  77. initWithComparator:[self defaultComparator]] insertKey:@1 withValue:@1] insertKey:@2
  78. withValue:@2];
  79. FImmutableSortedDictionary* newMap = [map removeKey:@1];
  80. XCTAssertEqualObjects([newMap get:@2], @2, @"Found second object");
  81. XCTAssertNil([newMap get:@1], @"Properly not found object");
  82. // Make sure the original one is not mutated
  83. XCTAssertEqualObjects([map get:@1], @1, @"Found first object");
  84. XCTAssertEqualObjects([map get:@2], @2, @"Found second object");
  85. }
  86. - (void)testMoreRemovals {
  87. FTreeSortedDictionary* map =
  88. [[[[[[[[[[[[[[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]]
  89. insertKey:@1
  90. withValue:@1] insertKey:@50 withValue:@50] insertKey:@3 withValue:@3] insertKey:@4
  91. withValue:@4]
  92. insertKey:@7
  93. withValue:@7] insertKey:@9 withValue:@9] insertKey:@20 withValue:@20] insertKey:@18
  94. withValue:@18]
  95. insertKey:@2
  96. withValue:@2] insertKey:@71 withValue:@71] insertKey:@42 withValue:@42] insertKey:@88
  97. withValue:@88];
  98. XCTAssertNotNil([map get:@7], @"Found object");
  99. XCTAssertNotNil([map get:@3], @"Found object");
  100. XCTAssertNotNil([map get:@1], @"Found object");
  101. FImmutableSortedDictionary* m1 = [map removeKey:@7];
  102. FImmutableSortedDictionary* m2 = [map removeKey:@3];
  103. FImmutableSortedDictionary* m3 = [map removeKey:@1];
  104. XCTAssertNil([m1 get:@7], @"Removed object");
  105. XCTAssertNotNil([m1 get:@3], @"Found object");
  106. XCTAssertNotNil([m1 get:@1], @"Found object");
  107. XCTAssertNil([m2 get:@3], @"Removed object");
  108. XCTAssertNotNil([m2 get:@7], @"Found object");
  109. XCTAssertNotNil([m2 get:@1], @"Found object");
  110. XCTAssertNil([m3 get:@1], @"Removed object");
  111. XCTAssertNotNil([m3 get:@7], @"Found object");
  112. XCTAssertNotNil([m3 get:@3], @"Found object");
  113. }
  114. - (void)testRemovalBug {
  115. FTreeSortedDictionary* map =
  116. [[[[[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]]
  117. insertKey:@1
  118. withValue:@1] insertKey:@2 withValue:@2] insertKey:@3 withValue:@3];
  119. XCTAssertEqualObjects([map get:@1], @1, @"Found object");
  120. XCTAssertEqualObjects([map get:@2], @2, @"Found object");
  121. XCTAssertEqualObjects([map get:@3], @3, @"Found object");
  122. FImmutableSortedDictionary* m1 = [map removeKey:@2];
  123. XCTAssertEqualObjects([m1 get:@1], @1, @"Found object");
  124. XCTAssertEqualObjects([m1 get:@3], @3, @"Found object");
  125. XCTAssertNil([m1 get:@2], @"Removed object");
  126. }
  127. - (void)testIncreasing {
  128. int total = 100;
  129. FTreeSortedDictionary* map =
  130. [[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]];
  131. for (int i = 0; i < total; i++) {
  132. NSNumber* item = [NSNumber numberWithInt:i];
  133. map = [map insertKey:item withValue:item];
  134. }
  135. XCTAssertTrue([map count] == 100, @"Check if all 100 objects are in the map");
  136. XCTAssertTrue([map.root isMemberOfClass:[FLLRBValueNode class]], @"Root is a value node");
  137. XCTAssertTrue([(FLLRBValueNode*)map.root checkMaxDepth],
  138. @"Checking valid depth and tree structure");
  139. for (int i = 0; i < total; i++) {
  140. NSNumber* item = [NSNumber numberWithInt:i];
  141. map = [map removeKey:item];
  142. }
  143. XCTAssertTrue([map count] == 0, @"Check if all 100 objects were removed");
  144. // We can't check the depth here because the map no longer contains values, so we check that it
  145. // doesn't responsd to this check
  146. XCTAssertTrue([map.root isMemberOfClass:[FLLRBEmptyNode class]], @"Root is an empty node");
  147. XCTAssertFalse([map respondsToSelector:@selector(checkMaxDepth)],
  148. @"The empty node doesn't respond to this selector.");
  149. }
  150. - (void)testStructureShouldBeValidAfterInsertionA {
  151. FTreeSortedDictionary* map =
  152. [[[[[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]]
  153. insertKey:@1
  154. withValue:@1] insertKey:@2 withValue:@2] insertKey:@3 withValue:@3];
  155. XCTAssertEqualObjects(map.root.key, @2, @"Check root key");
  156. XCTAssertEqualObjects(map.root.left.key, @1, @"Check the left key is correct");
  157. XCTAssertEqualObjects(map.root.right.key, @3, @"Check the right key is correct");
  158. }
  159. - (void)testStructureShouldBeValidAfterInsertionB {
  160. FTreeSortedDictionary* map =
  161. [[[[[[[[[[[[[[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]]
  162. insertKey:@1
  163. withValue:@1] insertKey:@50 withValue:@50] insertKey:@3 withValue:@3] insertKey:@4
  164. withValue:@4]
  165. insertKey:@7
  166. withValue:@7] insertKey:@9 withValue:@9] insertKey:@20 withValue:@20] insertKey:@18
  167. withValue:@18]
  168. insertKey:@2
  169. withValue:@2] insertKey:@71 withValue:@71] insertKey:@42 withValue:@42] insertKey:@88
  170. withValue:@88];
  171. XCTAssertTrue([map count] == 12, @"Check if all 12 objects are in the map");
  172. XCTAssertTrue([map.root isMemberOfClass:[FLLRBValueNode class]], @"Root is a value node");
  173. XCTAssertTrue([(FLLRBValueNode*)map.root checkMaxDepth],
  174. @"Checking valid depth and tree structure");
  175. }
  176. - (void)testRotateLeftLeavesTreeInAValidState {
  177. FLLRBValueNode* node = [[FLLRBValueNode alloc]
  178. initWithKey:@4
  179. withValue:@4
  180. withColor:BLACK
  181. withLeft:[[FLLRBValueNode alloc] initWithKey:@2
  182. withValue:@2
  183. withColor:BLACK
  184. withLeft:nil
  185. withRight:nil]
  186. withRight:[[FLLRBValueNode alloc] initWithKey:@7
  187. withValue:@7
  188. withColor:RED
  189. withLeft:[[FLLRBValueNode alloc] initWithKey:@5
  190. withValue:@5
  191. withColor:BLACK
  192. withLeft:nil
  193. withRight:nil]
  194. withRight:[[FLLRBValueNode alloc] initWithKey:@8
  195. withValue:@8
  196. withColor:BLACK
  197. withLeft:nil
  198. withRight:nil]]];
  199. FLLRBValueNode* node2 = [node performSelector:@selector(rotateLeft)];
  200. XCTAssertTrue([node2 count] == 5, @"Make sure the count is correct");
  201. XCTAssertTrue([node2 checkMaxDepth], @"Check proper structure");
  202. }
  203. - (void)testRotateRightLeavesTreeInAValidState {
  204. FLLRBValueNode* node = [[FLLRBValueNode alloc]
  205. initWithKey:@7
  206. withValue:@7
  207. withColor:BLACK
  208. withLeft:[[FLLRBValueNode alloc] initWithKey:@4
  209. withValue:@4
  210. withColor:RED
  211. withLeft:[[FLLRBValueNode alloc] initWithKey:@2
  212. withValue:@2
  213. withColor:BLACK
  214. withLeft:nil
  215. withRight:nil]
  216. withRight:[[FLLRBValueNode alloc] initWithKey:@5
  217. withValue:@5
  218. withColor:BLACK
  219. withLeft:nil
  220. withRight:nil]]
  221. withRight:[[FLLRBValueNode alloc] initWithKey:@8
  222. withValue:@8
  223. withColor:BLACK
  224. withLeft:nil
  225. withRight:nil]];
  226. FLLRBValueNode* node2 = [node performSelector:@selector(rotateRight)];
  227. XCTAssertTrue([node2 count] == 5, @"Make sure the count is correct");
  228. XCTAssertEqualObjects(node2.key, @4, @"Check roots key");
  229. XCTAssertEqualObjects(node2.left.key, @2, @"Check first left child key");
  230. XCTAssertEqualObjects(node2.right.key, @7, @"Check first right child key");
  231. XCTAssertEqualObjects(node2.right.left.key, @5, @"Check second right left key");
  232. XCTAssertEqualObjects(node2.right.right.key, @8, @"Check second right left key");
  233. }
  234. - (void)testStructureShouldBeValidAfterInsertionC {
  235. FTreeSortedDictionary* map =
  236. [[[[[[[[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]]
  237. insertKey:@1
  238. withValue:@1] insertKey:@50 withValue:@50] insertKey:@3 withValue:@3]
  239. insertKey:@4
  240. withValue:@4] insertKey:@7 withValue:@7] insertKey:@9 withValue:@9];
  241. XCTAssertTrue([map count] == 6, @"Check if all 6 objects are in the map");
  242. XCTAssertTrue([map.root isMemberOfClass:[FLLRBValueNode class]], @"Root is a value node");
  243. XCTAssertTrue([(FLLRBValueNode*)map.root checkMaxDepth],
  244. @"Checking valid depth and tree structure");
  245. FTreeSortedDictionary* m2 =
  246. [[[map insertKey:@20 withValue:@20] insertKey:@18 withValue:@18] insertKey:@2 withValue:@2];
  247. XCTAssertTrue([m2 count] == 9, @"Check if all 9 objects are in the map");
  248. XCTAssertTrue([m2.root isMemberOfClass:[FLLRBValueNode class]], @"Root is a value node");
  249. XCTAssertTrue([(FLLRBValueNode*)m2.root checkMaxDepth],
  250. @"Checking valid depth and tree structure");
  251. FTreeSortedDictionary* m3 = [[[[m2 insertKey:@71 withValue:@71] insertKey:@42 withValue:@42]
  252. insertKey:@88
  253. withValue:@88] insertKey:@20 withValue:@20]; // Add a dupe to see if the size is correct
  254. XCTAssertTrue([m3 count] == 12, @"Check if all 12 (minus dupe @20) objects are in the map");
  255. XCTAssertTrue([m3.root isMemberOfClass:[FLLRBValueNode class]], @"Root is a value node");
  256. XCTAssertTrue([(FLLRBValueNode*)m3.root checkMaxDepth],
  257. @"Checking valid depth and tree structure");
  258. }
  259. - (void)testOverride {
  260. FTreeSortedDictionary* map = [[[[FTreeSortedDictionary alloc]
  261. initWithComparator:[self defaultComparator]] insertKey:@10 withValue:@10] insertKey:@10
  262. withValue:@8];
  263. XCTAssertEqualObjects([map get:@10], @8, @"Found first object");
  264. }
  265. - (void)testEmpty {
  266. FTreeSortedDictionary* map = [[[[FTreeSortedDictionary alloc]
  267. initWithComparator:[self defaultComparator]] insertKey:@10 withValue:@10] removeKey:@10];
  268. XCTAssertTrue([map isEmpty], @"Properly empty");
  269. }
  270. - (void)testEmptyGet {
  271. FTreeSortedDictionary* map =
  272. [[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]];
  273. XCTAssertNil([map get:@"something"], @"Properly nil");
  274. }
  275. - (void)testEmptyCount {
  276. FTreeSortedDictionary* map =
  277. [[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]];
  278. XCTAssertTrue([map count] == 0, @"Properly zero count");
  279. }
  280. - (void)testEmptyRemoval {
  281. FTreeSortedDictionary* map =
  282. [[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]];
  283. XCTAssertTrue([[map removeKey:@"sometjhing"] count] == 0, @"Properly zero count");
  284. }
  285. - (void)testReverseTraversal {
  286. FTreeSortedDictionary* map =
  287. [[[[[[[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]] insertKey:@1
  288. withValue:@1]
  289. insertKey:@5
  290. withValue:@5] insertKey:@3 withValue:@3] insertKey:@2 withValue:@2] insertKey:@4
  291. withValue:@4];
  292. __block int next = 5;
  293. [map enumerateKeysAndObjectsReverse:YES
  294. usingBlock:^(id key, id value, BOOL* stop) {
  295. XCTAssertEqualObjects(key, [NSNumber numberWithInt:next],
  296. @"Properly equal");
  297. next = next - 1;
  298. }];
  299. }
  300. - (void)testInsertionAndRemovalOfAHundredItems {
  301. int N = 100;
  302. NSMutableArray* toInsert = [[NSMutableArray alloc] initWithCapacity:N];
  303. NSMutableArray* toRemove = [[NSMutableArray alloc] initWithCapacity:N];
  304. for (int i = 0; i < N; i++) {
  305. [toInsert addObject:[NSNumber numberWithInt:i]];
  306. [toRemove addObject:[NSNumber numberWithInt:i]];
  307. }
  308. [self shuffleArray:toInsert];
  309. [self shuffleArray:toRemove];
  310. FTreeSortedDictionary* map =
  311. [[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]];
  312. // add them to the dictionary
  313. for (int i = 0; i < N; i++) {
  314. map = [map insertKey:[toInsert objectAtIndex:i] withValue:[toInsert objectAtIndex:i]];
  315. XCTAssertTrue([map.root isMemberOfClass:[FLLRBValueNode class]], @"Root is a value node");
  316. XCTAssertTrue([(FLLRBValueNode*)map.root checkMaxDepth],
  317. @"Checking valid depth and tree structure");
  318. }
  319. XCTAssertTrue([map count] == N, @"Check if all N objects are in the map");
  320. // check the order is correct
  321. __block int next = 0;
  322. [map enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL* stop) {
  323. XCTAssertEqualObjects(key, [NSNumber numberWithInt:next], @"Correct key");
  324. XCTAssertEqualObjects(value, [NSNumber numberWithInt:next], @"Correct value");
  325. next = next + 1;
  326. }];
  327. XCTAssertEqual(next, N, @"Check we traversed all of the items");
  328. // remove them
  329. for (int i = 0; i < N; i++) {
  330. if ([map.root isMemberOfClass:[FLLRBValueNode class]]) {
  331. XCTAssertTrue([map.root isMemberOfClass:[FLLRBValueNode class]], @"Root is a value node");
  332. XCTAssertTrue([(FLLRBValueNode*)map.root checkMaxDepth],
  333. @"Checking valid depth and tree structure");
  334. }
  335. map = [map removeKey:[toRemove objectAtIndex:i]];
  336. }
  337. XCTAssertEqual([map count], 0, @"Check we removed all of the items");
  338. }
  339. - (void)shuffleArray:(NSMutableArray*)array {
  340. NSUInteger count = [array count];
  341. for (NSUInteger i = 0; i < count; i++) {
  342. NSInteger nElements = count - i;
  343. NSInteger n = (arc4random() % nElements) + i;
  344. [array exchangeObjectAtIndex:i withObjectAtIndex:n];
  345. }
  346. }
  347. - (void)testBalanceProblem {
  348. NSArray* toInsert = [[NSArray alloc] initWithObjects:@1, @7, @8, @5, @2, @6, @4, @0, @3, nil];
  349. FTreeSortedDictionary* map =
  350. [[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]];
  351. // add them to the dictionary
  352. for (int i = 0; i < [toInsert count]; i++) {
  353. map = [map insertKey:[toInsert objectAtIndex:i] withValue:[toInsert objectAtIndex:i]];
  354. XCTAssertTrue([map.root isMemberOfClass:[FLLRBValueNode class]], @"Root is a value node");
  355. XCTAssertTrue([(FLLRBValueNode*)map.root checkMaxDepth],
  356. @"Checking valid depth and tree structure");
  357. }
  358. XCTAssertTrue([map count] == [toInsert count], @"Check if all N objects are in the map");
  359. // check the order is correct
  360. __block int next = 0;
  361. [map enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL* stop) {
  362. XCTAssertEqualObjects(key, [NSNumber numberWithInt:next], @"Correct key");
  363. XCTAssertEqualObjects(value, [NSNumber numberWithInt:next], @"Correct value");
  364. next = next + 1;
  365. }];
  366. XCTAssertEqual(next, [[NSNumber numberWithUnsignedInteger:[toInsert count]] intValue],
  367. @"Check we traversed all of the items");
  368. // removing one triggers the balance problem
  369. map = [map removeKey:@5];
  370. if ([map.root isMemberOfClass:[FLLRBValueNode class]]) {
  371. XCTAssertTrue([map.root isMemberOfClass:[FLLRBValueNode class]], @"Root is a value node");
  372. XCTAssertTrue([(FLLRBValueNode*)map.root checkMaxDepth],
  373. @"Checking valid depth and tree structure");
  374. }
  375. }
  376. - (void)testPredecessorKey {
  377. FTreeSortedDictionary* map =
  378. [[[[[[[[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]]
  379. insertKey:@1
  380. withValue:@1] insertKey:@50 withValue:@50] insertKey:@3 withValue:@3]
  381. insertKey:@4
  382. withValue:@4] insertKey:@7 withValue:@7] insertKey:@9 withValue:@9];
  383. XCTAssertNil([map getPredecessorKey:@1], @"First object doesn't have a predecessor");
  384. XCTAssertEqualObjects([map getPredecessorKey:@3], @1, @"@1");
  385. XCTAssertEqualObjects([map getPredecessorKey:@4], @3, @"@3");
  386. XCTAssertEqualObjects([map getPredecessorKey:@7], @4, @"@4");
  387. XCTAssertEqualObjects([map getPredecessorKey:@9], @7, @"@7");
  388. XCTAssertEqualObjects([map getPredecessorKey:@50], @9, @"@9");
  389. XCTAssertThrows([map getPredecessorKey:@777], @"Expect exception about nonexistant key");
  390. }
  391. - (void)testEnumerator {
  392. int N = 100;
  393. NSMutableArray* toInsert = [[NSMutableArray alloc] initWithCapacity:N];
  394. NSMutableArray* toRemove = [[NSMutableArray alloc] initWithCapacity:N];
  395. for (int i = 0; i < N; i++) {
  396. [toInsert addObject:[NSNumber numberWithInt:i]];
  397. [toRemove addObject:[NSNumber numberWithInt:i]];
  398. }
  399. [self shuffleArray:toInsert];
  400. [self shuffleArray:toRemove];
  401. FTreeSortedDictionary* map =
  402. [[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]];
  403. // add them to the dictionary
  404. for (int i = 0; i < N; i++) {
  405. map = [map insertKey:[toInsert objectAtIndex:i] withValue:[toInsert objectAtIndex:i]];
  406. XCTAssertTrue([map.root isMemberOfClass:[FLLRBValueNode class]], @"Root is a value node");
  407. XCTAssertTrue([(FLLRBValueNode*)map.root checkMaxDepth],
  408. @"Checking valid depth and tree structure");
  409. }
  410. XCTAssertTrue([map count] == N, @"Check if all N objects are in the map");
  411. NSEnumerator* enumerator = [map keyEnumerator];
  412. id next = [enumerator nextObject];
  413. int correctValue = 0;
  414. while (next != nil) {
  415. XCTAssertEqualObjects(next, [NSNumber numberWithInt:correctValue], @"Correct key");
  416. next = [enumerator nextObject];
  417. correctValue = correctValue + 1;
  418. }
  419. }
  420. - (void)testReverseEnumerator {
  421. int N = 20;
  422. NSMutableArray* toInsert = [[NSMutableArray alloc] initWithCapacity:N];
  423. for (int i = 0; i < N; i++) {
  424. [toInsert addObject:[NSNumber numberWithInt:i]];
  425. }
  426. [self shuffleArray:toInsert];
  427. FImmutableSortedDictionary* map =
  428. [[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]];
  429. // add them to the dictionary
  430. for (int i = 0; i < N; i++) {
  431. map = [map insertKey:[toInsert objectAtIndex:i] withValue:[toInsert objectAtIndex:i]];
  432. }
  433. XCTAssertTrue([map count] == N, @"Check if all N objects are in the map");
  434. XCTAssertTrue([map isKindOfClass:[FTreeSortedDictionary class]],
  435. @"Make sure we still have a array backed dictionary");
  436. NSEnumerator* enumerator = [map reverseKeyEnumerator];
  437. id next = [enumerator nextObject];
  438. int correctValue = N - 1;
  439. while (next != nil) {
  440. XCTAssertEqualObjects(next, [NSNumber numberWithInt:correctValue], @"Correct key");
  441. next = [enumerator nextObject];
  442. correctValue--;
  443. }
  444. }
  445. - (void)testEnumeratorFrom {
  446. int N = 20;
  447. NSMutableArray* toInsert = [[NSMutableArray alloc] initWithCapacity:N];
  448. for (int i = 0; i < N; i++) {
  449. [toInsert addObject:[NSNumber numberWithInt:i * 2]];
  450. }
  451. [self shuffleArray:toInsert];
  452. FImmutableSortedDictionary* map =
  453. [[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]];
  454. // add them to the dictionary
  455. for (int i = 0; i < N; i++) {
  456. map = [map insertKey:[toInsert objectAtIndex:i] withValue:[toInsert objectAtIndex:i]];
  457. }
  458. XCTAssertTrue([map count] == N, @"Check if all N objects are in the map");
  459. XCTAssertTrue([map isKindOfClass:[FTreeSortedDictionary class]],
  460. @"Make sure we still have a array backed dictionary");
  461. // Test from inbetween keys
  462. {
  463. NSEnumerator* enumerator = [map keyEnumeratorFrom:@11];
  464. id next = [enumerator nextObject];
  465. int correctValue = 12;
  466. while (next != nil) {
  467. XCTAssertEqualObjects(next, [NSNumber numberWithInt:correctValue], @"Correct key");
  468. next = [enumerator nextObject];
  469. correctValue = correctValue + 2;
  470. }
  471. }
  472. // Test from key in map
  473. {
  474. NSEnumerator* enumerator = [map keyEnumeratorFrom:@10];
  475. id next = [enumerator nextObject];
  476. int correctValue = 10;
  477. while (next != nil) {
  478. XCTAssertEqualObjects(next, [NSNumber numberWithInt:correctValue], @"Correct key");
  479. next = [enumerator nextObject];
  480. correctValue = correctValue + 2;
  481. }
  482. }
  483. }
  484. - (void)testReverseEnumeratorFrom {
  485. int N = 20;
  486. NSMutableArray* toInsert = [[NSMutableArray alloc] initWithCapacity:N];
  487. for (int i = 0; i < N; i++) {
  488. [toInsert addObject:[NSNumber numberWithInt:i * 2]];
  489. }
  490. [self shuffleArray:toInsert];
  491. FImmutableSortedDictionary* map =
  492. [[FTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]];
  493. // add them to the dictionary
  494. for (int i = 0; i < N; i++) {
  495. map = [map insertKey:[toInsert objectAtIndex:i] withValue:[toInsert objectAtIndex:i]];
  496. }
  497. XCTAssertTrue([map count] == N, @"Check if all N objects are in the map");
  498. XCTAssertTrue([map isKindOfClass:[FTreeSortedDictionary class]],
  499. @"Make sure we still have a array backed dictionary");
  500. // Test from inbetween keys
  501. {
  502. NSEnumerator* enumerator = [map reverseKeyEnumeratorFrom:@11];
  503. id next = [enumerator nextObject];
  504. int correctValue = 10;
  505. while (next != nil) {
  506. XCTAssertEqualObjects(next, [NSNumber numberWithInt:correctValue], @"Correct key");
  507. next = [enumerator nextObject];
  508. correctValue = correctValue - 2;
  509. }
  510. }
  511. // Test from key in map
  512. {
  513. NSEnumerator* enumerator = [map reverseKeyEnumeratorFrom:@10];
  514. id next = [enumerator nextObject];
  515. int correctValue = 10;
  516. while (next != nil) {
  517. XCTAssertEqualObjects(next, [NSNumber numberWithInt:correctValue], @"Correct key");
  518. next = [enumerator nextObject];
  519. correctValue = correctValue - 2;
  520. }
  521. }
  522. }
  523. @end