FSTTreeSortedDictionaryTests.m 27 KB

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