FIRDataSnapshotTests.m 22 KB

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