FIRDataSnapshotTests.m 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  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 "FIRDataSnapshotTests.h"
  17. #import "FChildrenNode.h"
  18. #import "FEmptyNode.h"
  19. #import "FIRDataSnapshot_Private.h"
  20. #import "FIRDatabaseConfig_Private.h"
  21. #import "FIRDatabaseReference.h"
  22. #import "FImmutableSortedDictionary.h"
  23. #import "FLeafNode.h"
  24. #import "FPathIndex.h"
  25. #import "FSnapshotUtilities.h"
  26. #import "FTestHelpers.h"
  27. #import "FUtilities.h"
  28. #import "FValueIndex.h"
  29. @implementation FIRDataSnapshotTests
  30. - (void)setUp {
  31. [super setUp];
  32. // Set-up code here.
  33. }
  34. - (void)tearDown {
  35. // Tear-down code here.
  36. [super tearDown];
  37. }
  38. - (FIRDataSnapshot*)snapshotFor:(id)jsonDict {
  39. FIRDatabaseConfig* config = [FTestHelpers defaultConfig];
  40. FRepoInfo* repoInfo = [[FRepoInfo alloc] initWithHost:@"example.com"
  41. isSecure:NO
  42. withNamespace:@"default"];
  43. FIRDatabaseReference* dummyRef =
  44. [[FIRDatabaseReference alloc] initWithRepo:[FRepoManager getRepo:repoInfo config:config]
  45. path:[FPath empty]];
  46. FIndexedNode* indexed = [FIndexedNode indexedNodeWithNode:[FSnapshotUtilities nodeFrom:jsonDict]];
  47. FIRDataSnapshot* snapshot = [[FIRDataSnapshot alloc] initWithRef:dummyRef indexedNode:indexed];
  48. return snapshot;
  49. }
  50. - (void)testCreationLeafNodesVariousTypes {
  51. id<FNode> fortyTwo = [FSnapshotUtilities nodeFrom:@42];
  52. FLeafNode* x = [[FLeafNode alloc] initWithValue:@5 withPriority:fortyTwo];
  53. XCTAssertEqualObjects(x.val, @5, @"Values are the same");
  54. XCTAssertEqualObjects(x.getPriority, [FSnapshotUtilities nodeFrom:@42], @"Priority is the same");
  55. XCTAssertTrue([x isLeafNode], @"Node is a leaf");
  56. x = [[FLeafNode alloc] initWithValue:@"test"];
  57. XCTAssertEqualObjects(x.value, @"test", @"Check if leaf node is holding onto a string value");
  58. x = [[FLeafNode alloc] initWithValue:[NSNumber numberWithBool:YES]];
  59. XCTAssertTrue([x.value boolValue], @"Check if leaf node is holding onto a YES boolean");
  60. x = [[FLeafNode alloc] initWithValue:[NSNumber numberWithBool:NO]];
  61. XCTAssertFalse([x.value boolValue], @"Check if leaf node is holding onto a NO boolean");
  62. }
  63. - (void)testUpdatingPriorityWithoutChangingOld {
  64. FLeafNode* x =
  65. [[FLeafNode alloc] initWithValue:@"test"
  66. withPriority:[FSnapshotUtilities nodeFrom:[NSNumber numberWithInt:42]]];
  67. FLeafNode* y = [x updatePriority:[FSnapshotUtilities nodeFrom:[NSNumber numberWithInt:187]]];
  68. // old node is the same
  69. XCTAssertEqualObjects(x.value, @"test", @"Values of old node are the same");
  70. XCTAssertEqualObjects(x.getPriority, [FSnapshotUtilities nodeFrom:[NSNumber numberWithInt:42]],
  71. @"Priority of old node is the same.");
  72. // new node has the new priority but the old value
  73. XCTAssertEqualObjects(y.value, @"test", @"Values of old node are the same");
  74. XCTAssertEqualObjects(y.getPriority, [FSnapshotUtilities nodeFrom:[NSNumber numberWithInt:187]],
  75. @"Priority of new node is update");
  76. }
  77. - (void)testUpdateImmediateChildReturnsANewChildrenNode {
  78. FLeafNode* x =
  79. [[FLeafNode alloc] initWithValue:@"test"
  80. withPriority:[FSnapshotUtilities nodeFrom:[NSNumber numberWithInt:42]]];
  81. FChildrenNode* y = [x updateImmediateChild:@"test"
  82. withNewChild:[[FLeafNode alloc] initWithValue:@"foo"]];
  83. XCTAssertFalse([y isLeafNode], @"New node is no longer a leaf");
  84. XCTAssertEqualObjects(y.getPriority, [FSnapshotUtilities nodeFrom:[NSNumber numberWithInt:42]],
  85. @"Priority of new node is update");
  86. XCTAssertEqualObjects([[y getImmediateChild:@"test"] val], @"foo",
  87. @"Child node has the correct value");
  88. }
  89. - (void)testGetImmediateChildOnLeafNode {
  90. FLeafNode* x = [[FLeafNode alloc] initWithValue:@"test"];
  91. XCTAssertEqualObjects([x getImmediateChild:@"foo"], [FEmptyNode emptyNode],
  92. @"Get immediate child on leaf node returns empty node");
  93. }
  94. - (void)testGetChildReturnsEmptyNode {
  95. FLeafNode* x = [[FLeafNode alloc] initWithValue:@"test"];
  96. XCTAssertEqualObjects([x getChild:[[FPath alloc] initWith:@"foo/bar"]], [FEmptyNode emptyNode],
  97. @"Get child returns an empty node.");
  98. }
  99. - (NSComparator)defaultComparator {
  100. return ^(id obj1, id obj2) {
  101. if ([obj1 respondsToSelector:@selector(compare:)] &&
  102. [obj2 respondsToSelector:@selector(compare:)]) {
  103. return [obj1 compare:obj2];
  104. } else {
  105. if (obj1 < obj2) {
  106. return (NSComparisonResult)NSOrderedAscending;
  107. } else if (obj1 > obj2) {
  108. return (NSComparisonResult)NSOrderedDescending;
  109. } else {
  110. return (NSComparisonResult)NSOrderedSame;
  111. }
  112. }
  113. };
  114. }
  115. - (void)testUpdateImmediateChildWithNewNode {
  116. FImmutableSortedDictionary* children =
  117. [FImmutableSortedDictionary dictionaryWithComparator:[self defaultComparator]];
  118. FChildrenNode* x = [[FChildrenNode alloc] initWithChildren:children];
  119. FLeafNode* newValue = [[FLeafNode alloc] initWithValue:@"new value"];
  120. FChildrenNode* y = [x updateImmediateChild:@"test" withNewChild:newValue];
  121. XCTAssertEqualObjects(x.children, children, @"Original object stays the same");
  122. XCTAssertEqualObjects([y.children objectForKey:@"test"], newValue,
  123. @"New internal node with the proper new value");
  124. XCTAssertEqualObjects([[y.children objectForKey:@"test"] val], @"new value",
  125. @"Check the payload");
  126. }
  127. - (void)testUpdatechildWithNewNode {
  128. FImmutableSortedDictionary* children =
  129. [FImmutableSortedDictionary dictionaryWithComparator:[self defaultComparator]];
  130. FChildrenNode* x = [[FChildrenNode alloc] initWithChildren:children];
  131. FLeafNode* newValue = [[FLeafNode alloc] initWithValue:@"new value"];
  132. FChildrenNode* y = [x updateChild:[[FPath alloc] initWith:@"test/foo"] withNewChild:newValue];
  133. XCTAssertEqualObjects(x.children, children, @"Original object stays the same");
  134. XCTAssertEqualObjects([y getChild:[[FPath alloc] initWith:@"test/foo"]], newValue,
  135. @"Check if the updateChild held");
  136. XCTAssertEqualObjects([[y getChild:[[FPath alloc] initWith:@"test/foo"]] val], @"new value",
  137. @"Check the payload");
  138. }
  139. - (void)testObjectTypes {
  140. XCTAssertEqualObjects(@"string", [FUtilities getJavascriptType:@""], @"Check string type");
  141. XCTAssertEqualObjects(@"string", [FUtilities getJavascriptType:@"moo"], @"Check string type");
  142. XCTAssertEqualObjects(@"boolean", [FUtilities getJavascriptType:@YES], @"Check boolean type");
  143. XCTAssertEqualObjects(@"boolean", [FUtilities getJavascriptType:@NO], @"Check boolean type");
  144. XCTAssertEqualObjects(@"number", [FUtilities getJavascriptType:@5], @"Check number type");
  145. XCTAssertEqualObjects(@"number", [FUtilities getJavascriptType:@5.5], @"Check number type");
  146. XCTAssertEqualObjects(@"number", [FUtilities getJavascriptType:@0], @"Check number type");
  147. XCTAssertEqualObjects(@"number", [FUtilities getJavascriptType:@8273482734],
  148. @"Check number type");
  149. XCTAssertEqualObjects(@"number", [FUtilities getJavascriptType:@-2], @"Check number type");
  150. XCTAssertEqualObjects(@"number", [FUtilities getJavascriptType:@-2.11], @"Check number type");
  151. }
  152. - (void)testNodeHashWorksCorrectly {
  153. id<FNode> node = [FSnapshotUtilities nodeFrom:@{
  154. @"intNode" : @4,
  155. @"doubleNode" : @4.5623,
  156. @"stringNode" : @"hey guys",
  157. @"boolNode" : @YES
  158. }];
  159. XCTAssertEqualObjects(@"eVih19a6ZDz3NL32uVBtg9KSgQY=",
  160. [[node getImmediateChild:@"intNode"] dataHash], @"Check integer node");
  161. XCTAssertEqualObjects(@"vf1CL0tIRwXXunHcG/irRECk3lY=",
  162. [[node getImmediateChild:@"doubleNode"] dataHash], @"Check double node");
  163. XCTAssertEqualObjects(@"CUNLXWpCVoJE6z7z1vE57lGaKAU=",
  164. [[node getImmediateChild:@"stringNode"] dataHash], @"Check string node");
  165. XCTAssertEqualObjects(@"E5z61QM0lN/U2WsOnusszCTkR8M=",
  166. [[node getImmediateChild:@"boolNode"] dataHash], @"Check boolean node");
  167. XCTAssertEqualObjects(@"6Mc4jFmNdrLVIlJJjz2/MakTK9I=", [node dataHash], @"Check compound node");
  168. }
  169. - (void)testNodeHashWorksCorrectlyWithPriorities {
  170. id<FNode> node = [FSnapshotUtilities nodeFrom:@{
  171. @"root" : @{@"c" : @{@".value" : @99, @".priority" : @"abc"}, @".priority" : @"def"}
  172. }];
  173. XCTAssertEqualObjects(@"Fm6tzN4CVEu5WxFDZUdTtqbTVaA=", [node dataHash], @"Check compound node");
  174. }
  175. - (void)testGetPredecessorChild {
  176. id<FNode> node = [FSnapshotUtilities
  177. nodeFrom:@{@"d" : @YES, @"a" : @YES, @"g" : @YES, @"c" : @YES, @"e" : @YES}];
  178. XCTAssertNil([node predecessorChildKey:@"a"], @"Check the first one sorted properly");
  179. XCTAssertEqualObjects([node predecessorChildKey:@"c"], @"a", @"Check a comes before c");
  180. XCTAssertEqualObjects([node predecessorChildKey:@"d"], @"c", @"Check c comes before d");
  181. XCTAssertEqualObjects([node predecessorChildKey:@"e"], @"d", @"Check d comes before e");
  182. XCTAssertEqualObjects([node predecessorChildKey:@"g"], @"e", @"Check e comes before g");
  183. }
  184. - (void)testSortedChildrenGetPredecessorChildWorksCorrectly {
  185. // XXX impl SortedChildren
  186. }
  187. - (void)testSortedChildrenUpdateImmediateChildrenWorksCorrectly {
  188. // XXX imple SortedChildren
  189. }
  190. - (void)testDataSnapshotHasChildrenWorks {
  191. FIRDataSnapshot* snap = [self snapshotFor:@{}];
  192. XCTAssertFalse([snap hasChildren], @"Empty dict has no children");
  193. snap = [self snapshotFor:@5];
  194. XCTAssertFalse([snap hasChildren], @"Leaf node has no children");
  195. snap = [self snapshotFor:@{@"x" : @5}];
  196. XCTAssertTrue([snap hasChildren], @"Properly has children");
  197. }
  198. - (void)testDataSnapshotValWorks {
  199. FIRDataSnapshot* snap = [self snapshotFor:@5];
  200. XCTAssertEqualObjects([snap value], @5, @"Leaf node values are correct");
  201. snap = [self snapshotFor:@{}];
  202. XCTAssertTrue([snap value] == [NSNull null], @"Snapshot value is properly null");
  203. NSDictionary* dict = @{@"x" : @5, @"y" : @{@"ya" : @1, @"yb" : @2, @"yc" : @{@"yca" : @3}}};
  204. snap = [self snapshotFor:dict];
  205. XCTAssertTrue([dict isEqualToDictionary:[snap value]], @"Check if the dictionaries are the same");
  206. }
  207. - (void)testDataSnapshotChildWorks {
  208. FIRDataSnapshot* snap = [self snapshotFor:@{@"x" : @5, @"y" : @{@"yy" : @3, @"yz" : @4}}];
  209. XCTAssertEqualObjects([[snap childSnapshotForPath:@"x"] value], @5, @"Check x");
  210. NSDictionary* dict = @{@"yy" : @3, @"yz" : @4};
  211. XCTAssertTrue([[[snap childSnapshotForPath:@"y"] value] isEqualToDictionary:dict], @"Check y");
  212. XCTAssertEqualObjects([[[snap childSnapshotForPath:@"y"] childSnapshotForPath:@"yy"] value], @3,
  213. @"Check y/yy");
  214. XCTAssertEqualObjects([[snap childSnapshotForPath:@"y/yz"] value], @4, @"Check y/yz");
  215. XCTAssertTrue([[snap childSnapshotForPath:@"z"] value] == [NSNull null], @"Check nonexistent z");
  216. XCTAssertTrue([[snap childSnapshotForPath:@"x/y"] value] == [NSNull null],
  217. @"Check value of existent internal node");
  218. XCTAssertTrue(
  219. [[[snap childSnapshotForPath:@"x"] childSnapshotForPath:@"y"] value] == [NSNull null],
  220. @"Check value of existent internal node");
  221. }
  222. - (void)testDataSnapshotHasChildWorks {
  223. FIRDataSnapshot* snap = [self snapshotFor:@{@"x" : @5, @"y" : @{@"yy" : @3, @"yz" : @4}}];
  224. XCTAssertTrue([snap hasChild:@"x"], @"Has child");
  225. XCTAssertTrue([snap hasChild:@"y/yy"], @"Has child");
  226. XCTAssertFalse([snap hasChild:@"dinosaur dinosaucer"], @"No child");
  227. XCTAssertFalse([[snap childSnapshotForPath:@"x"] hasChild:@"anything"], @"No child");
  228. XCTAssertFalse([snap hasChild:@"x/anything/at/all"], @"No child");
  229. }
  230. - (void)testDataSnapshotNameWorks {
  231. FIRDataSnapshot* snap = [self snapshotFor:@{@"a" : @{@"b" : @{@"c" : @5}}}];
  232. XCTAssertEqualObjects([[snap childSnapshotForPath:@"a"] key], @"a", @"Check child key");
  233. XCTAssertEqualObjects([[snap childSnapshotForPath:@"a/b/c"] key], @"c", @"Check child key");
  234. XCTAssertEqualObjects([[snap childSnapshotForPath:@"/a/b/c"] key], @"c", @"Check child key");
  235. XCTAssertEqualObjects([[snap childSnapshotForPath:@"/a/b/c/"] key], @"c", @"Check child key");
  236. XCTAssertEqualObjects([[snap childSnapshotForPath:@"////a///b////c///"] key], @"c",
  237. @"Check child key");
  238. XCTAssertEqualObjects([[snap childSnapshotForPath:@"////"] key], [snap key], @"Check root key");
  239. XCTAssertEqualObjects([[snap childSnapshotForPath:@"/z/q/r/v////m"] key], @"m",
  240. @"Should also work for nonexistent paths");
  241. }
  242. - (void)testDataSnapshotForEachWithNoPriorities {
  243. FIRDataSnapshot* snap = [self snapshotFor:@{
  244. @"a" : @1,
  245. @"z" : @26,
  246. @"m" : @13,
  247. @"n" : @14,
  248. @"c" : @3,
  249. @"b" : @2,
  250. @"e" : @5
  251. }];
  252. NSMutableString* out = [[NSMutableString alloc] init];
  253. for (FIRDataSnapshot* child in snap.children) {
  254. [out appendFormat:@"%@:%@:", [child key], [child value]];
  255. }
  256. XCTAssertTrue([out isEqualToString:@"a:1:b:2:c:3:e:5:m:13:n:14:z:26:"], @"Proper order");
  257. }
  258. - (void)testDataSnapshotForEachWorksWithNumericPriorities {
  259. FIRDataSnapshot* snap = [self snapshotFor:@{
  260. @"a" : @{@".value" : @1, @".priority" : @26},
  261. @"z" : @{@".value" : @26, @".priority" : @1},
  262. @"m" : @{@".value" : @13, @".priority" : @14},
  263. @"n" : @{@".value" : @14, @".priority" : @12},
  264. @"c" : @{@".value" : @3, @".priority" : @24},
  265. @"b" : @{@".value" : @2, @".priority" : @25},
  266. @"e" : @{@".value" : @5, @".priority" : @22},
  267. }];
  268. NSMutableString* out = [[NSMutableString alloc] init];
  269. for (FIRDataSnapshot* child in snap.children) {
  270. [out appendFormat:@"%@:%@:", [child key], [child value]];
  271. }
  272. XCTAssertTrue([out isEqualToString:@"z:26:n:14:m:13:e:5:c:3:b:2:a:1:"], @"Proper order");
  273. }
  274. - (void)testDataSnapshotForEachWorksWithNumericPrioritiesAsStrings {
  275. FIRDataSnapshot* snap = [self snapshotFor:@{
  276. @"a" : @{@".value" : @1, @".priority" : @"26"},
  277. @"z" : @{@".value" : @26, @".priority" : @"1"},
  278. @"m" : @{@".value" : @13, @".priority" : @"14"},
  279. @"n" : @{@".value" : @14, @".priority" : @"12"},
  280. @"c" : @{@".value" : @3, @".priority" : @"24"},
  281. @"b" : @{@".value" : @2, @".priority" : @"25"},
  282. @"e" : @{@".value" : @5, @".priority" : @"22"},
  283. }];
  284. NSMutableString* out = [[NSMutableString alloc] init];
  285. for (FIRDataSnapshot* child in snap.children) {
  286. [out appendFormat:@"%@:%@:", [child key], [child value]];
  287. }
  288. XCTAssertTrue([out isEqualToString:@"z:26:n:14:m:13:e:5:c:3:b:2:a:1:"], @"Proper order");
  289. }
  290. - (void)testDataSnapshotForEachWorksAlphaPriorities {
  291. FIRDataSnapshot* snap = [self snapshotFor:@{
  292. @"a" : @{@".value" : @1, @".priority" : @"first"},
  293. @"z" : @{@".value" : @26, @".priority" : @"second"},
  294. @"m" : @{@".value" : @13, @".priority" : @"third"},
  295. @"n" : @{@".value" : @14, @".priority" : @"fourth"},
  296. @"c" : @{@".value" : @3, @".priority" : @"fifth"},
  297. @"b" : @{@".value" : @2, @".priority" : @"sixth"},
  298. @"e" : @{@".value" : @5, @".priority" : @"seventh"},
  299. }];
  300. NSMutableString* output = [[NSMutableString alloc] init];
  301. NSMutableArray* priorities = [[NSMutableArray alloc] init];
  302. for (FIRDataSnapshot* child in snap.children) {
  303. [output appendFormat:@"%@:%@:", child.key, child.value];
  304. [priorities addObject:child.priority];
  305. }
  306. XCTAssertTrue([output isEqualToString:@"c:3:a:1:n:14:z:26:e:5:b:2:m:13:"], @"Proper order");
  307. NSArray* expected = @[ @"fifth", @"first", @"fourth", @"second", @"seventh", @"sixth", @"third" ];
  308. XCTAssertTrue([priorities isEqualToArray:expected], @"Correct priorities");
  309. XCTAssertTrue(snap.childrenCount == 7, @"Got correct children count");
  310. }
  311. - (void)testDataSnapshotForEachWorksWithMixedPriorities {
  312. FIRDataSnapshot* snap = [self snapshotFor:@{
  313. @"alpha42" : @{@".value" : @1, @".priority" : @"zed"},
  314. @"noPriorityC" : @{@".value" : @1, @".priority" : [NSNull null]},
  315. @"alpha14" : @{@".value" : @1, @".priority" : @"500"},
  316. @"noPriorityB" : @{@".value" : @1, @".priority" : [NSNull null]},
  317. @"num80" : @{@".value" : @1, @".priority" : @4000.1},
  318. @"alpha13" : @{@".value" : @1, @".priority" : @"4000"},
  319. @"alpha11" : @{@".value" : @1, @".priority" : @"24"},
  320. @"alpha41" : @{@".value" : @1, @".priority" : @"zed"},
  321. @"alpha20" : @{@".value" : @1, @".priority" : @"horse"},
  322. @"num20" : @{@".value" : @1, @".priority" : @123},
  323. @"num70" : @{@".value" : @1, @".priority" : @4000.01},
  324. @"noPriorityA" : @{@".value" : @1, @".priority" : [NSNull null]},
  325. @"alpha30" : @{@".value" : @1, @".priority" : @"tree"},
  326. @"alpha12" : @{@".value" : @1, @".priority" : @"300"},
  327. @"num60" : @{@".value" : @1, @".priority" : @4000.001},
  328. @"alpha10" : @{@".value" : @1, @".priority" : @"0horse"},
  329. @"num42" : @{@".value" : @1, @".priority" : @500},
  330. @"alpha40" : @{@".value" : @1, @".priority" : @"zed"},
  331. @"num40" : @{@".value" : @1, @".priority" : @500}
  332. }];
  333. NSMutableString* out = [[NSMutableString alloc] init];
  334. for (FIRDataSnapshot* child in snap.children) {
  335. [out appendFormat:@"%@, ", [child key]];
  336. }
  337. NSString* expected =
  338. @"noPriorityA, noPriorityB, noPriorityC, num20, num40, num42, num60, num70, num80, alpha10, "
  339. @"alpha11, alpha12, alpha13, alpha14, alpha20, alpha30, alpha40, alpha41, alpha42, ";
  340. XCTAssertTrue([expected isEqualToString:out], @"Proper ordering seen");
  341. }
  342. - (void)testIgnoresNullValues {
  343. FIRDataSnapshot* snap = [self snapshotFor:@{@"a" : @1, @"b" : [NSNull null]}];
  344. XCTAssertFalse([snap hasChild:@"b"], @"Should not have b, it was null");
  345. }
  346. - (void)testNameComparator {
  347. NSComparator keyComparator = [FUtilities keyComparator];
  348. XCTAssertEqual(keyComparator(@"1234", @"1234"), NSOrderedSame, @"NameComparator compares ints");
  349. XCTAssertEqual(keyComparator(@"1234", @"12345"), NSOrderedAscending,
  350. @"NameComparator compares ints");
  351. XCTAssertEqual(keyComparator(@"4321", @"1234"), NSOrderedDescending,
  352. @"NameComparator compares ints");
  353. XCTAssertEqual(keyComparator(@"1234", @"zzzz"), NSOrderedAscending,
  354. @"NameComparator priorities ints");
  355. XCTAssertEqual(keyComparator(@"4321", @"12a"), NSOrderedAscending,
  356. @"NameComparator priorities ints");
  357. XCTAssertEqual(keyComparator(@"abc", @"abcd"), NSOrderedAscending,
  358. @"NameComparator uses lexiographical sorting for strings.");
  359. XCTAssertEqual(keyComparator(@"zzzz", @"aaaa"), NSOrderedDescending,
  360. @"NameComparator compares strings");
  361. XCTAssertEqual(keyComparator(@"-1234", @"0"), NSOrderedAscending,
  362. @"NameComparator compares negative values");
  363. XCTAssertEqual(keyComparator(@"-1234", @"-1234"), NSOrderedSame,
  364. @"NameComparator compares negative values");
  365. XCTAssertEqual(keyComparator(@"-1234", @"-4321"), NSOrderedDescending,
  366. @"NameComparator compares negative values");
  367. XCTAssertEqual(keyComparator(@"-1234", @"-"), NSOrderedAscending,
  368. @"NameComparator does not parse - as integer");
  369. XCTAssertEqual(keyComparator(@"-", @"1234"), NSOrderedDescending,
  370. @"NameComparator does not parse - as integer");
  371. }
  372. - (void)testExistsWorks {
  373. FIRDataSnapshot* snap;
  374. snap = [self snapshotFor:@{}];
  375. XCTAssertFalse([snap exists], @"Should not exist");
  376. snap = [self snapshotFor:@{@".priority" : @"1"}];
  377. XCTAssertFalse([snap exists], @"Should not exist");
  378. snap = [self snapshotFor:[NSNull null]];
  379. XCTAssertFalse([snap exists], @"Should not exist");
  380. snap = [self snapshotFor:[NSNumber numberWithBool:YES]];
  381. XCTAssertTrue([snap exists], @"Should exist");
  382. snap = [self snapshotFor:@5];
  383. XCTAssertTrue([snap exists], @"Should exist");
  384. snap = [self snapshotFor:@{@"x" : @5}];
  385. XCTAssertTrue([snap exists], @"Should exist");
  386. }
  387. - (void)testUpdatingEmptyChildDoesntOverwriteLeafNode {
  388. FLeafNode* node = [[FLeafNode alloc] initWithValue:@"value"];
  389. XCTAssertEqualObjects(node,
  390. [node updateChild:[[FPath alloc] initWith:@".priority"]
  391. withNewChild:[FEmptyNode emptyNode]],
  392. @"Update should not affect node.");
  393. XCTAssertEqualObjects(node,
  394. [node updateChild:[[FPath alloc] initWith:@"child"]
  395. withNewChild:[FEmptyNode emptyNode]],
  396. @"Update should not affect node.");
  397. XCTAssertEqualObjects(node,
  398. [node updateChild:[[FPath alloc] initWith:@"child/.priority"]
  399. withNewChild:[FEmptyNode emptyNode]],
  400. @"Update should not affect node.");
  401. XCTAssertEqualObjects(node,
  402. [node updateImmediateChild:@"child" withNewChild:[FEmptyNode emptyNode]],
  403. @"Update should not affect node.");
  404. XCTAssertEqualObjects(
  405. node, [node updateImmediateChild:@".priority" withNewChild:[FEmptyNode emptyNode]],
  406. @"Update should not affect node.");
  407. }
  408. /* This was reported by a customer, which broke because 유주연 > 윤규완오빠 but also 윤규완오빠 >
  409. * 유주연 with the default string comparison... */
  410. - (void)testUnicodeEquality {
  411. FNamedNode* node1 = [[FNamedNode alloc] initWithName:@"a"
  412. andNode:[[FLeafNode alloc] initWithValue:@"유주연"]];
  413. FNamedNode* node2 =
  414. [[FNamedNode alloc] initWithName:@"a"
  415. andNode:[[FLeafNode alloc] initWithValue:@"윤규완오빠"]];
  416. id<FIndex> index = [FValueIndex valueIndex];
  417. // x < y should imply y > x
  418. XCTAssertEqual([index compareNamedNode:node1 toNamedNode:node2], -[index compareNamedNode:node2
  419. toNamedNode:node1]);
  420. }
  421. @end