FSparseSnapshotTests.m 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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 "FirebaseDatabase/Tests/Unit/FSparseSnapshotTests.h"
  17. #import "FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h"
  18. #import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h"
  19. #import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h"
  20. @implementation FSparseSnapshotTests
  21. - (void)testBasicRememberAndFind {
  22. FSparseSnapshotTree* st = [[FSparseSnapshotTree alloc] init];
  23. FPath* path = [[FPath alloc] initWith:@"a/b"];
  24. id<FNode> node = [FSnapshotUtilities nodeFrom:@"sdfsd"];
  25. [st rememberData:node onPath:path];
  26. id<FNode> found = [st findPath:path];
  27. XCTAssertFalse([found isEmpty], @"Should find node");
  28. found = [st findPath:path.parent];
  29. XCTAssertTrue(found == nil, @"Should not find a node");
  30. }
  31. - (void)testFindInsideAnExistingSnapshot {
  32. FSparseSnapshotTree* st = [[FSparseSnapshotTree alloc] init];
  33. FPath* path = [[FPath alloc] initWith:@"t/tt"];
  34. id<FNode> node = [FSnapshotUtilities nodeFrom:@{@"a" : @"sdfsd", @"x" : @5, @"999i" : @YES}];
  35. id<FNode> update = [FSnapshotUtilities nodeFrom:@{@"goats" : @88}];
  36. node = [node updateImmediateChild:@"apples" withNewChild:update];
  37. [st rememberData:node onPath:path];
  38. id<FNode> found = [st findPath:path];
  39. XCTAssertFalse([found isEmpty], @"Should find the node we set");
  40. found = [st findPath:[path childFromString:@"a"]];
  41. XCTAssertTrue([[found val] isEqualToString:@"sdfsd"], @"Find works inside data snapshot");
  42. found = [st findPath:[path childFromString:@"999i"]];
  43. XCTAssertTrue([[found val] isEqualToNumber:@YES], @"Find works inside data snapshot");
  44. found = [st findPath:[path childFromString:@"apples"]];
  45. XCTAssertFalse([found isEmpty], @"Should find the node we set");
  46. found = [st findPath:[path childFromString:@"apples/goats"]];
  47. XCTAssertTrue([[found val] isEqualToNumber:@88], @"Find works inside data snapshot");
  48. }
  49. - (void)testWriteASnapshotInsideASnapshot {
  50. FSparseSnapshotTree* st = [[FSparseSnapshotTree alloc] init];
  51. [st rememberData:[FSnapshotUtilities nodeFrom:@{@"a" : @{@"b" : @"v"}}]
  52. onPath:[[FPath alloc] initWith:@"t"]];
  53. [st rememberData:[FSnapshotUtilities nodeFrom:@19] onPath:[[FPath alloc] initWith:@"t/a/rr"]];
  54. id<FNode> found = [st findPath:[[FPath alloc] initWith:@"t/a/b"]];
  55. XCTAssertTrue([[found val] isEqualToString:@"v"], @"Find inside snap");
  56. found = [st findPath:[[FPath alloc] initWith:@"t/a/rr"]];
  57. XCTAssertTrue([[found val] isEqualToNumber:@19], @"Find inside snap");
  58. }
  59. - (void)testWriteANullValueAndConfirmItIsRemembered {
  60. FSparseSnapshotTree* st = [[FSparseSnapshotTree alloc] init];
  61. [st rememberData:[FSnapshotUtilities nodeFrom:[NSNull null]]
  62. onPath:[[FPath alloc] initWith:@"awq/fff"]];
  63. id<FNode> found = [st findPath:[[FPath alloc] initWith:@"awq/fff"]];
  64. XCTAssertTrue([found isEmpty], @"Empty node");
  65. found = [st findPath:[[FPath alloc] initWith:@"awq/sdf"]];
  66. XCTAssertTrue(found == nil, @"No node here");
  67. found = [st findPath:[[FPath alloc] initWith:@"awq/fff/jjj"]];
  68. XCTAssertTrue([found isEmpty], @"Empty node");
  69. found = [st findPath:[[FPath alloc] initWith:@"awq/sdf/sdj/q"]];
  70. XCTAssertTrue(found == nil, @"No node here");
  71. }
  72. - (void)testOverwriteWithNullAndConfirmItIsRemembered {
  73. FSparseSnapshotTree* st = [[FSparseSnapshotTree alloc] init];
  74. [st rememberData:[FSnapshotUtilities nodeFrom:@{@"a" : @{@"b" : @"v"}}]
  75. onPath:[[FPath alloc] initWith:@"t"]];
  76. id<FNode> found = [st findPath:[[FPath alloc] initWith:@"t"]];
  77. XCTAssertFalse([found isEmpty], @"non-empty node");
  78. [st rememberData:[FSnapshotUtilities nodeFrom:[NSNull null]]
  79. onPath:[[FPath alloc] initWith:@"t"]];
  80. found = [st findPath:[[FPath alloc] initWith:@"t"]];
  81. XCTAssertTrue([found isEmpty], @"Empty node");
  82. }
  83. - (void)testSimpleRememberAndForget {
  84. FSparseSnapshotTree* st = [[FSparseSnapshotTree alloc] init];
  85. [st rememberData:[FSnapshotUtilities nodeFrom:@{@"a" : @{@"b" : @"v"}}]
  86. onPath:[[FPath alloc] initWith:@"t"]];
  87. id<FNode> found = [st findPath:[[FPath alloc] initWith:@"t"]];
  88. XCTAssertFalse([found isEmpty], @"non-empty node");
  89. [st forgetPath:[[FPath alloc] initWith:@"t"]];
  90. found = [st findPath:[[FPath alloc] initWith:@"t"]];
  91. XCTAssertTrue(found == nil, @"node is gone");
  92. }
  93. - (void)testForgetTheRoot {
  94. FSparseSnapshotTree* st = [[FSparseSnapshotTree alloc] init];
  95. [st rememberData:[FSnapshotUtilities nodeFrom:@{@"a" : @{@"b" : @"v"}}]
  96. onPath:[[FPath alloc] initWith:@"t"]];
  97. id<FNode> found = [st findPath:[[FPath alloc] initWith:@"t"]];
  98. XCTAssertFalse([found isEmpty], @"non-empty node");
  99. found = [st findPath:[[FPath alloc] initWith:@""]];
  100. XCTAssertTrue(found == nil, @"node is gone");
  101. }
  102. - (void)testForgetSnapshotInsideSnapshot {
  103. FSparseSnapshotTree* st = [[FSparseSnapshotTree alloc] init];
  104. [st rememberData:[FSnapshotUtilities nodeFrom:@{@"a" : @{@"b" : @"v", @"c" : @9, @"art" : @NO}}]
  105. onPath:[[FPath alloc] initWith:@"t"]];
  106. id<FNode> found = [st findPath:[[FPath alloc] initWith:@"t/a/c"]];
  107. XCTAssertFalse([found isEmpty], @"non-empty node");
  108. found = [st findPath:[[FPath alloc] initWith:@"t"]];
  109. XCTAssertFalse([found isEmpty], @"non-empty node");
  110. [st forgetPath:PATH(@"t/a/c")];
  111. XCTAssertTrue([st findPath:PATH(@"t")] == nil, @"no more node here");
  112. XCTAssertTrue([st findPath:PATH(@"t/a")] == nil, @"no more node here");
  113. XCTAssertTrue([[[st findPath:PATH(@"t/a/b")] val] isEqualToString:@"v"], @"child still exists");
  114. XCTAssertTrue([st findPath:PATH(@"t/a/c")] == nil, @"no more node here");
  115. XCTAssertTrue([[[st findPath:PATH(@"t/a/art")] val] isEqualToNumber:@NO], @"child still exists");
  116. }
  117. - (void)testPathShallowerThanSnapshots {
  118. FSparseSnapshotTree* st = [[FSparseSnapshotTree alloc] init];
  119. [st rememberData:NODE(@NO) onPath:PATH(@"t/x1")];
  120. [st rememberData:NODE(@YES) onPath:PATH(@"t/x2")];
  121. [st forgetPath:PATH(@"t")];
  122. XCTAssertTrue([st findPath:PATH(@"t")] == nil, @"No more node here");
  123. }
  124. - (void)testIterateChildren {
  125. FSparseSnapshotTree* st = [[FSparseSnapshotTree alloc] init];
  126. id<FNode> node = [FSnapshotUtilities nodeFrom:@{@"b" : @"v", @"c" : @9, @"art" : @NO}];
  127. [st rememberData:node onPath:PATH(@"t")];
  128. [st rememberData:[FEmptyNode emptyNode] onPath:PATH(@"q")];
  129. __block int num = 0;
  130. __block BOOL gotT = NO;
  131. __block BOOL gotQ = NO;
  132. [st forEachChild:^(NSString* key, FSparseSnapshotTree* tree) {
  133. num++;
  134. if ([key isEqualToString:@"t"]) {
  135. gotT = YES;
  136. } else if ([key isEqualToString:@"q"]) {
  137. gotQ = YES;
  138. } else {
  139. XCTFail(@"Unknown child");
  140. }
  141. }];
  142. XCTAssertTrue(gotT, @"Saw t");
  143. XCTAssertTrue(gotQ, @"Saw q");
  144. XCTAssertTrue(num == 2, @"Saw two children");
  145. }
  146. - (void)testIterateTrees {
  147. FSparseSnapshotTree* st = [[FSparseSnapshotTree alloc] init];
  148. __block int count = 0;
  149. [st forEachTreeAtPath:PATH(@"")
  150. do:^(FPath* path, id<FNode> data) {
  151. count++;
  152. }];
  153. XCTAssertTrue(count == 0, @"No trees to iterate through");
  154. [st rememberData:NODE(@1) onPath:PATH(@"t")];
  155. [st rememberData:NODE(@2) onPath:PATH(@"a/b")];
  156. [st rememberData:NODE(@3) onPath:PATH(@"a/x/g")];
  157. [st rememberData:NODE([NSNull null]) onPath:PATH(@"a/x/null")];
  158. __block int num = 0;
  159. __block BOOL got1 = NO;
  160. __block BOOL got2 = NO;
  161. __block BOOL got3 = NO;
  162. __block BOOL gotNull = NO;
  163. [st forEachTreeAtPath:PATH(@"q")
  164. do:^(FPath* path, id<FNode> data) {
  165. num++;
  166. NSString* pathString = [path description];
  167. if ([pathString isEqualToString:@"/q/t"]) {
  168. got1 = YES;
  169. XCTAssertTrue([[data val] isEqualToNumber:@1], @"got 1");
  170. } else if ([pathString isEqualToString:@"/q/a/b"]) {
  171. got2 = YES;
  172. XCTAssertTrue([[data val] isEqualToNumber:@2], @"got 2");
  173. } else if ([pathString isEqualToString:@"/q/a/x/g"]) {
  174. got3 = YES;
  175. XCTAssertTrue([[data val] isEqualToNumber:@3], @"got 3");
  176. } else if ([pathString isEqualToString:@"/q/a/x/null"]) {
  177. gotNull = YES;
  178. XCTAssertTrue([data val] == [NSNull null], @"got null");
  179. } else {
  180. XCTFail(@"unknown tree");
  181. }
  182. }];
  183. XCTAssertTrue(got1 && got2 && got3 && gotNull, @"saw all the children");
  184. XCTAssertTrue(num == 4, @"Saw the right number of children");
  185. }
  186. - (void)testSetLeafAndForgetDeeperPath {
  187. FSparseSnapshotTree* st = [[FSparseSnapshotTree alloc] init];
  188. [st rememberData:NODE(@"bar") onPath:PATH(@"foo")];
  189. BOOL safeToRemove = [st forgetPath:PATH(@"foo/baz")];
  190. XCTAssertFalse(safeToRemove, @"Should not have deleted anything, nothing to remove");
  191. }
  192. @end