FRangeMergeTest.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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 <Foundation/Foundation.h>
  17. #import <XCTest/XCTest.h>
  18. #import "FRangeMerge.h"
  19. #import "FNode.h"
  20. #import "FTestHelpers.h"
  21. #import "FEmptyNode.h"
  22. @interface FRangeMergeTest : XCTestCase
  23. @end
  24. @implementation FRangeMergeTest
  25. - (void)testSmokeTest {
  26. id<FNode> node = NODE((@{@"bar": @"bar-value", @"foo": @{@"a": @{@"deep-a-1": @1, @"deep-a-2": @2}, @"b": @"b", @"c": @"c", @"d": @"d"}, @"quu": @"quu-value"}));
  27. id<FNode> updates = NODE((@{@"foo": @{@"a": @{@"deep-a-2": @"new-a-2", @"deep-a-3": @3}, @"b-2": @"new-b", @"c": @"new-c" }}));
  28. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:PATH(@"foo/a/deep-a-1") end:PATH(@"foo/c") updates:updates];
  29. id<FNode> expected = NODE((@{@"bar": @"bar-value", @"foo": @{@"a": @{@"deep-a-1": @1, @"deep-a-2": @"new-a-2", @"deep-a-3": @3}, @"b-2": @"new-b", @"c": @"new-c", @"d": @"d"}, @"quu": @"quu-value"}));
  30. id<FNode> actual = [merge applyToNode:node];
  31. XCTAssertEqualObjects(actual, expected);
  32. }
  33. - (void)testStartIsExclusive {
  34. id<FNode> node = NODE((@{@"bar": @"bar-value", @"foo": @"foo-value", @"quu": @"quu-value"}));
  35. id<FNode> updates = NODE((@{@"foo": @"new-foo-value"}));
  36. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:PATH(@"bar") end:PATH(@"foo") updates:updates];
  37. id<FNode> expected = NODE((@{@"bar": @"bar-value", @"foo": @"new-foo-value", @"quu": @"quu-value"}));
  38. id<FNode> actual = [merge applyToNode:node];
  39. XCTAssertEqualObjects(actual, expected);
  40. }
  41. - (void)testStartIsExclusiveButIncludesChildren {
  42. id<FNode> node = NODE((@{@"bar": @"bar-value", @"foo": @"foo-value", @"quu": @"quu-value"}));
  43. id<FNode> updates = NODE((@{@"bar": @{@"bar-child": @"bar-child-value"}, @"foo": @"new-foo-value"}));
  44. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:PATH(@"bar") end:PATH(@"foo") updates:updates];
  45. id<FNode> expected = NODE((@{@"bar": @{@"bar-child": @"bar-child-value"}, @"foo": @"new-foo-value", @"quu": @"quu-value"}));
  46. id<FNode> actual = [merge applyToNode:node];
  47. XCTAssertEqualObjects(actual, expected);
  48. }
  49. - (void)testEndIsInclusive {
  50. id<FNode> node = NODE((@{@"bar": @"bar-value", @"foo": @"foo-value", @"quu": @"quu-value"}));
  51. id<FNode> updates = NODE((@{@"baz": @"baz-value"}));
  52. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:PATH(@"bar") end:PATH(@"foo") updates:updates]; // foo should be deleted
  53. id<FNode> expected = NODE((@{@"bar": @"bar-value", @"baz": @"baz-value", @"quu": @"quu-value"}));
  54. id<FNode> actual = [merge applyToNode:node];
  55. XCTAssertEqualObjects(actual, expected);
  56. }
  57. - (void)testEndIsInclusiveButExcludesChildren {
  58. id<FNode> node = NODE((@{@"bar": @"bar-value", @"foo": @{@"foo-child": @"foo-child-value"}, @"quu": @"quu-value"}));
  59. id<FNode> updates = NODE((@{@"baz": @"baz-value"}));
  60. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:PATH(@"bar") end:PATH(@"foo") updates:updates]; // foo should be deleted
  61. id<FNode> expected = NODE((@{@"bar": @"bar-value", @"baz": @"baz-value", @"foo": @{@"foo-child": @"foo-child-value"}, @"quu": @"quu-value"}));
  62. id<FNode> actual = [merge applyToNode:node];
  63. XCTAssertEqualObjects(actual, expected);
  64. }
  65. - (void)testCanUpdateLeafNode {
  66. id<FNode> node = NODE(@"leaf-value");
  67. id<FNode> updates = NODE((@{@"bar": @"bar-value"}));
  68. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:nil end:PATH(@"foo") updates:updates];
  69. id<FNode> expected = NODE((@{@"bar": @"bar-value"}));
  70. id<FNode> actual = [merge applyToNode:node];
  71. XCTAssertEqualObjects(actual, expected);
  72. }
  73. - (void)testCanReplaceLeafNodeWithLeafNode{
  74. id<FNode> node = NODE(@"leaf-value");
  75. id<FNode> updates = NODE(@"new-leaf-value");
  76. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:nil end:PATH(@"") updates:updates];
  77. id<FNode> expected = NODE(@"new-leaf-value");
  78. id<FNode> actual = [merge applyToNode:node];
  79. XCTAssertEqualObjects(actual, expected);
  80. }
  81. - (void)testLeafsAreUpdatedWhenRangesIncludeDeeperPath {
  82. id<FNode> node = NODE((@{@"foo": @{@"bar": @"bar-value"}}));
  83. id<FNode> updates = NODE((@{@"foo": @{@"bar": @"new-bar-value"}}));
  84. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:PATH(@"foo") end:PATH(@"foo/bar/deep") updates:updates];
  85. id<FNode> expected = NODE((@{@"foo": @{@"bar": @"new-bar-value"}}));
  86. id<FNode> actual = [merge applyToNode:node];
  87. XCTAssertEqualObjects(actual, expected);
  88. }
  89. - (void)testLeafsAreNotUpdatedWhenRangesIncludeDeeperPaths {
  90. id<FNode> node = NODE((@{@"foo": @{@"bar": @"bar-value"}}));
  91. id<FNode> updates = NODE((@{@"foo": @{@"bar": @"new-bar-value"}}));
  92. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:PATH(@"foo/bar") end:PATH(@"foo/bar/deep") updates:updates];
  93. id<FNode> expected = NODE((@{@"foo": @{@"bar": @"bar-value"}}));
  94. id<FNode> actual = [merge applyToNode:node];
  95. XCTAssertEqualObjects(actual, expected);
  96. }
  97. - (void)testUpdatingEntireRangeUpdatesEverything {
  98. id<FNode> node = [FEmptyNode emptyNode];
  99. id<FNode> updates = NODE((@{@"foo": @"foo-value", @"bar": @{@"child": @"bar-child-value"}}));
  100. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:nil end:nil updates:updates];
  101. id<FNode> expected = NODE((@{@"foo": @"foo-value", @"bar": @{@"child": @"bar-child-value"}}));
  102. id<FNode> actual = [merge applyToNode:node];
  103. XCTAssertEqualObjects(actual, expected);
  104. }
  105. - (void)testUpdatingRangeWithUnboundedLeftPostWorks {
  106. id<FNode> node = NODE((@{@"bar": @"bar-value", @"foo": @"foo-value"}));
  107. id<FNode> updates = NODE((@{@"bar": @"new-bar"}));
  108. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:nil end:PATH(@"bar") updates:updates];
  109. id<FNode> expected = NODE((@{@"bar": @"new-bar", @"foo": @"foo-value"}));
  110. id<FNode> actual = [merge applyToNode:node];
  111. XCTAssertEqualObjects(actual, expected);
  112. }
  113. - (void)testUpdatingRangeWithRightPostChildOfLeftPostWorks {
  114. id<FNode> node = NODE((@{@"foo": @{@"a": @"a", @"b": @{@"1": @"1", @"2": @"2"}, @"c": @"c"}}));
  115. id<FNode> updates = NODE((@{@"foo": @{@"a": @"new-a", @"b": @{@"1": @"new-1"}}}));
  116. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:PATH(@"foo") end:PATH(@"foo/b/1") updates:updates];
  117. id<FNode> expected = NODE((@{@"foo": @{@"a": @"new-a", @"b": @{@"1": @"new-1", @"2": @"2"}, @"c": @"c"}}));
  118. id<FNode> actual = [merge applyToNode:node];
  119. XCTAssertEqualObjects(actual, expected);
  120. }
  121. - (void)testUpdatingRangeWithRightPostChildOfLeftPostWorksWithIntegerKeys {
  122. id<FNode> node = NODE((@{@"foo": @{@"a": @"a", @"b": @{@"1": @"1", @"2": @"2", @"10": @"10"}, @"c": @"c"}}));
  123. id<FNode> updates = NODE((@{@"foo": @{@"a": @"new-a", @"b": @{@"1": @"new-1"}}}));
  124. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:PATH(@"foo") end:PATH(@"foo/b/2") updates:updates];
  125. id<FNode> expected = NODE((@{@"foo": @{@"a": @"new-a", @"b": @{@"1": @"new-1", @"10": @"10"}, @"c": @"c"}}));
  126. id<FNode> actual = [merge applyToNode:node];
  127. XCTAssertEqualObjects(actual, expected);
  128. }
  129. - (void)testUpdatingLeafIncludesPriority {
  130. id<FNode> node = NODE((@{@"bar": @"bar-value", @"foo": @"foo-value", @"quu": @"quu-value"}));
  131. id<FNode> updates = NODE((@{@"foo": @{@".value": @"new-foo", @".priority": @"prio"}}));
  132. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:PATH(@"bar") end:PATH(@"foo") updates:updates];
  133. id<FNode> expected = NODE((@{@"bar": @"bar-value", @"foo": @{@".value": @"new-foo", @".priority": @"prio" }, @"quu": @"quu-value"}));
  134. id<FNode> actual = [merge applyToNode:node];
  135. XCTAssertEqualObjects(actual, expected);
  136. }
  137. - (void)testUpdatingPriorityInChildrenNodeWorks {
  138. id<FNode> node = NODE((@{@"bar": @"bar-value", @"foo": @"foo-value"}));
  139. id<FNode> updates = NODE((@{@"bar": @"new-bar", @".priority": @"prio"}));
  140. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:nil end:PATH(@"bar") updates:updates];
  141. id<FNode> expected = NODE((@{@"bar": @"new-bar", @"foo": @"foo-value", @".priority": @"prio"}));
  142. id<FNode> actual = [merge applyToNode:node];
  143. XCTAssertEqualObjects(actual, expected);
  144. }
  145. // TODO: this test should actuall;y work, but priorities on empty nodes are ignored :(
  146. - (void)updatingPriorityInChildrenNodeWorksAlone {
  147. id<FNode> node = NODE((@{@"bar": @"bar-value", @"foo": @"foo-value"}));
  148. id<FNode> updates = NODE((@{@".priority": @"prio" }));
  149. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:nil end:PATH(@".priority") updates:updates];
  150. id<FNode> expected = NODE((@{@"bar": @"bar-value", @"foo": @"foo-value", @".priority": @"prio"}));
  151. id<FNode> actual = [merge applyToNode:node];
  152. XCTAssertEqualObjects(actual, expected);
  153. }
  154. - (void)testUpdatingPriorityOnInitiallyEmptyNodeDoesNotBreak {
  155. id<FNode> node = NODE((@{}));
  156. id<FNode> updates = NODE((@{@".priority": @"prio", @"foo": @"foo-value" }));
  157. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:nil end:PATH(@"foo") updates:updates];
  158. id<FNode> expected = NODE((@{@"foo": @"foo-value", @".priority": @"prio"}));
  159. id<FNode> actual = [merge applyToNode:node];
  160. XCTAssertEqualObjects(actual, expected);
  161. }
  162. - (void)testPriorityIsDeletedWhenIncludedInChildrenRange {
  163. id<FNode> node = NODE((@{@"bar": @"bar-value", @"foo": @"foo-value", @".priority": @"prio"}));
  164. id<FNode> updates = NODE((@{@"bar": @"new-bar"}));
  165. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:nil end:PATH(@"bar") updates:updates]; // deletes priority
  166. id<FNode> expected = NODE((@{@"bar": @"new-bar", @"foo": @"foo-value"}));
  167. id<FNode> actual = [merge applyToNode:node];
  168. XCTAssertEqualObjects(actual, expected);
  169. }
  170. - (void)testPriorityIsIncludedInOpenStart {
  171. id<FNode> node = NODE((@{@"foo": @{@"bar": @"bar-value"}}));
  172. id<FNode> updates = NODE((@{@".priority": @"prio", @"baz": @"baz"}));
  173. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:nil end:PATH(@"foo/bar") updates:updates];
  174. id<FNode> expected = NODE((@{@"baz": @"baz", @".priority": @"prio"}));
  175. id<FNode> actual = [merge applyToNode:node];
  176. XCTAssertEqualObjects(actual, expected);
  177. }
  178. - (void)testPriorityIsIncludedInOpenEnd {
  179. id<FNode> node = NODE(@"leaf-node");
  180. id<FNode> updates = NODE((@{@".priority": @"prio", @"foo": @"bar"}));
  181. FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:PATH(@"/") end:nil updates:updates];
  182. id<FNode> expected = NODE((@{@"foo": @"bar", @".priority": @"prio"}));
  183. id<FNode> actual = [merge applyToNode:node];
  184. XCTAssertEqualObjects(actual, expected);
  185. }
  186. @end