| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526 |
- /*
- * Copyright 2017 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #import <XCTest/XCTest.h>
- #import "FNode.h"
- #import "FSnapshotUtilities.h"
- #import "FCompoundWrite.h"
- #import "FEmptyNode.h"
- #import "FLeafNode.h"
- #import "FNamedNode.h"
- @interface FCompoundWriteTest : XCTestCase
- @end
- @implementation FCompoundWriteTest
- - (id<FNode>) leafNode {
- static id<FNode> node = nil;
- if (!node) {
- node = [FSnapshotUtilities nodeFrom:@"leaf-node"];
- }
- return node;
- }
- - (id<FNode>) priorityNode {
- static id<FNode> node = nil;
- if (!node) {
- node = [FSnapshotUtilities nodeFrom:@"prio"];
- }
- return node;
- }
- - (id<FNode>) baseNode {
- static id<FNode> node = nil;
- if (!node) {
- NSDictionary *base = @{@"child-1" : @"value-1", @"child-2" : @"value-2"};
- node = [FSnapshotUtilities nodeFrom:base];
- }
- return node;
- }
- - (void) assertAppliedCompoundWrite:(FCompoundWrite *)compoundWrite equalsNode:(id<FNode>)node withPriority:(id<FNode>)priority {
- id<FNode> updatedNode = [compoundWrite applyToNode:node];
- if (node.isEmpty) {
- XCTAssertEqualObjects([FEmptyNode emptyNode], updatedNode,
- @"Applied compound write should be empty. %@", updatedNode);
- } else {
- XCTAssertEqualObjects([node updatePriority:priority], updatedNode,
- @"Applied compound write should equal node with priority. %@", updatedNode);
- }
- }
- - (void) testEmptyMergeIsEmpty {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- XCTAssertTrue(compoundWrite.isEmpty, @"Empty write should be empty %@", compoundWrite);
- }
- - (void) testCompoundWriteWithPriorityUpdateIsNotEmpty {
- FCompoundWrite *compoundWrite = [[FCompoundWrite emptyWrite] addWrite:self.priorityNode atKey:@".priority"];
- XCTAssertFalse(compoundWrite.isEmpty, @"Priority update should not be empty %@", compoundWrite);
- }
- - (void) testCompoundWriteWithUpdateIsNotEmpty {
- FCompoundWrite *compoundWrite = [[FCompoundWrite emptyWrite] addWrite:self.leafNode
- atPath:[[FPath alloc] initWith:@"foo/bar"]];
- XCTAssertFalse(compoundWrite.isEmpty, @"Update should not be empty %@", compoundWrite);
- }
- - (void) testCompoundWriteWithRootUpdateIsNotEmpty {
- FCompoundWrite *compoundWrite = [[FCompoundWrite emptyWrite] addWrite:self.leafNode
- atPath:[FPath empty]];
- XCTAssertFalse(compoundWrite.isEmpty, @"Update at root should not be empty %@", compoundWrite);
- }
- - (void) testCompoundWriteWithEmptyRootUpdateIsNotEmpty {
- FCompoundWrite *compoundWrite = [[FCompoundWrite emptyWrite] addWrite:[FEmptyNode emptyNode]
- atPath:[FPath empty]];
- XCTAssertFalse(compoundWrite.isEmpty, @"Empty root update should not be empty %@", compoundWrite);
- }
- - (void) testCompoundWriteWithRootPriorityUpdateAndChildMergeIsNotEmpty {
- FCompoundWrite *compoundWrite = [[FCompoundWrite emptyWrite] addWrite:self.priorityNode atKey:@".priority"];
- compoundWrite = [compoundWrite childCompoundWriteAtPath:[[FPath alloc] initWith:@".priority"]];
- XCTAssertFalse(compoundWrite.isEmpty, @"Compound write with root priority update and child merge should not be empty.");
- }
- - (void) testAppliesLeafOverwrite {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.leafNode atPath:[FPath empty]];
- id<FNode> updatedNode = [compoundWrite applyToNode:[FEmptyNode emptyNode]];
- XCTAssertEqualObjects(updatedNode, self.leafNode, @"Should get leaf node once applied %@", updatedNode);
- }
- - (void) testAppliesChildrenOverwrite {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- id<FNode> childNode = [[FEmptyNode emptyNode] updateImmediateChild:@"child" withNewChild:self.leafNode];
- compoundWrite = [compoundWrite addWrite:childNode atPath:[FPath empty]];
- id<FNode> updatedNode = [compoundWrite applyToNode:[FEmptyNode emptyNode]];
- XCTAssertEqualObjects(updatedNode, childNode, @"Child overwrite should work");
- }
- - (void) testAddsChildNode {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- id<FNode> expectedNode = [[FEmptyNode emptyNode] updateImmediateChild:@"child" withNewChild:self.leafNode];
- compoundWrite = [compoundWrite addWrite:self.leafNode atKey:@"child"];
- id<FNode> updatedNode = [compoundWrite applyToNode:[FEmptyNode emptyNode]];
- XCTAssertEqualObjects(updatedNode, expectedNode, @"Adding child node should work %@", updatedNode);
- }
- - (void) testAddsDeepChildNode {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- FPath *path = [[FPath alloc] initWith:@"deep/deep/node"];
- id<FNode> expectedNode = [[FEmptyNode emptyNode] updateChild:path withNewChild:self.leafNode];
- compoundWrite = [compoundWrite addWrite:self.leafNode atPath:path];
- id<FNode> updatedNode = [compoundWrite applyToNode:[FEmptyNode emptyNode]];
- XCTAssertEqualObjects(updatedNode, expectedNode, @"Should add deep child node correctly");
- }
- - (void) testOverwritesExistingChild {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- FPath *path = [[FPath alloc] initWith:@"child-1"];
- compoundWrite = [compoundWrite addWrite:self.leafNode atPath:path];
- id<FNode> updatedNode = [compoundWrite applyToNode:self.baseNode];
- id<FNode> expectedNode = [self.baseNode updateImmediateChild:[path getFront] withNewChild:self.leafNode];
- XCTAssertEqualObjects(updatedNode, expectedNode, @"Overwriting existing child should work.");
- }
- - (void) testUpdatesExistingChild {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- FPath *path = [[FPath alloc] initWith:@"child-1/foo"];
- compoundWrite = [compoundWrite addWrite:self.leafNode atPath:path];
- id<FNode> updatedNode = [compoundWrite applyToNode:self.baseNode];
- id<FNode> expectedNode = [self.baseNode updateChild:path withNewChild:self.leafNode];
- XCTAssertEqualObjects(updatedNode, expectedNode, @"Updating existing child should work");
- }
- - (void) testDoesntUpdatePriorityOnEmptyNode {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.priorityNode atKey:@".priority"];
- [self assertAppliedCompoundWrite:compoundWrite equalsNode:[FEmptyNode emptyNode] withPriority:[FEmptyNode emptyNode]];
- }
- - (void) testUpdatesPriorityOnNode {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.priorityNode atKey:@".priority"];
- id<FNode> node = [FSnapshotUtilities nodeFrom:@"value"];
- [self assertAppliedCompoundWrite:compoundWrite equalsNode:node withPriority:self.priorityNode];
- }
- - (void) testUpdatesPriorityOfChild {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- FPath *path = [[FPath alloc] initWith:@"child-1/.priority"];
- compoundWrite = [compoundWrite addWrite:self.priorityNode atPath:path];
- id<FNode> updatedNode = [compoundWrite applyToNode:self.baseNode];
- id<FNode> expectedNode = [self.baseNode updateChild:path withNewChild:self.priorityNode];
- XCTAssertEqualObjects(updatedNode, expectedNode, @"Updating priority of child should work.");
- }
- - (void) testDoesntUpdatePriorityOfNonExistentChild {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- FPath *path = [[FPath alloc] initWith:@"child-3/.priority"];
- compoundWrite = [compoundWrite addWrite:self.priorityNode atPath:path];
- id<FNode> updatedNode = [compoundWrite applyToNode:self.baseNode];
- XCTAssertEqualObjects(updatedNode, self.baseNode, @"Should not update priority of nonexistent child");
- }
- - (void) testDeepUpdateExistingUpdates {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- id<FNode> update1 = [FSnapshotUtilities nodeFrom:@{@"foo":@"foo-value", @"bar":@"bar-value"}];
- id<FNode> update2 = [FSnapshotUtilities nodeFrom:@"baz-value"];
- id<FNode> update3 = [FSnapshotUtilities nodeFrom:@"new-foo-value"];
- compoundWrite = [compoundWrite addWrite:update1 atPath:[[FPath alloc] initWith:@"child-1"]];
- compoundWrite = [compoundWrite addWrite:update2 atPath:[[FPath alloc] initWith:@"child-1/baz"]];
- compoundWrite = [compoundWrite addWrite:update3 atPath:[[FPath alloc] initWith:@"child-1/foo"]];
- NSDictionary *expectedChild1 = @{@"foo":@"new-foo-value", @"bar":@"bar-value", @"baz":@"baz-value"};
- id<FNode> expectedNode = [self.baseNode updateImmediateChild:@"child-1" withNewChild:[FSnapshotUtilities nodeFrom:expectedChild1]];
- id<FNode> updatedNode = [compoundWrite applyToNode:self.baseNode];
- XCTAssertEqualObjects(updatedNode, expectedNode, @"Deep update with existing updates should work.");
- }
- - (void) testShallowUpdateRemovesDeepUpdate {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- id<FNode> update1 = [FSnapshotUtilities nodeFrom:@"new-foo-value"];
- id<FNode> update2 = [FSnapshotUtilities nodeFrom:@"baz-value"];
- id<FNode> update3 = [FSnapshotUtilities nodeFrom:@{@"foo":@"foo-value", @"bar":@"bar-value"}];
- compoundWrite = [compoundWrite addWrite:update1 atPath:[[FPath alloc] initWith:@"child-1/foo"]];
- compoundWrite = [compoundWrite addWrite:update2 atPath:[[FPath alloc] initWith:@"child-1/baz"]];
- compoundWrite = [compoundWrite addWrite:update3 atPath:[[FPath alloc] initWith:@"child-1"]];
- NSDictionary *expectedChild1 = @{@"foo":@"foo-value", @"bar":@"bar-value"};
- id<FNode> expectedNode = [self.baseNode updateImmediateChild:@"child-1" withNewChild:[FSnapshotUtilities nodeFrom:expectedChild1]];
- id<FNode> updatedNode = [compoundWrite applyToNode:self.baseNode];
- XCTAssertEqualObjects(updatedNode, expectedNode, @"Shallow update should remove deep udpates.");
- }
- - (void) testChildPriorityDoesntUpdateEmptyNodePriorityOnChildMerge {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.priorityNode atPath:[[FPath alloc] initWith:@"child-1/.priority"]];
- compoundWrite = [compoundWrite childCompoundWriteAtPath:[[FPath alloc] initWith:@"child-1"]];
- [self assertAppliedCompoundWrite:compoundWrite equalsNode:[FEmptyNode emptyNode] withPriority:[FEmptyNode emptyNode]];
- }
- - (void) testChildPriorityUpdatesPriorityOnChildMerge {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.priorityNode atPath:[[FPath alloc] initWith:@"child-1/.priority"]];
- id<FNode> node = [FSnapshotUtilities nodeFrom:@"value"];
- compoundWrite = [compoundWrite childCompoundWriteAtPath:[[FPath alloc] initWith:@"child-1"]];
- [self assertAppliedCompoundWrite:compoundWrite equalsNode:node withPriority:self.priorityNode];
- }
- - (void) testChildPriorityUpdatesEmptyPriorityOnChildMerge {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:[FEmptyNode emptyNode] atPath:[[FPath alloc] initWith:@"child-1/.priority"]];
- id<FNode> node = [[FLeafNode alloc] initWithValue:@"foo" withPriority:self.priorityNode];
- compoundWrite = [compoundWrite childCompoundWriteAtPath:[[FPath alloc] initWith:@"child-1"]];
- [self assertAppliedCompoundWrite:compoundWrite equalsNode:node withPriority:[FEmptyNode emptyNode]];
- }
- - (void) testDeepPrioritySetWorksOnEmptyNodeWhenOtherSetIsAvailable {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.priorityNode atPath:[[FPath alloc] initWith:@"foo/.priority"]];
- compoundWrite = [compoundWrite addWrite:self.leafNode atPath:[[FPath alloc] initWith:@"foo/child"]];
- id<FNode> updatedNode = [compoundWrite applyToNode:[FEmptyNode emptyNode]];
- id<FNode> updatedPriority = [updatedNode getChild:[[FPath alloc] initWith:@"foo"]].getPriority;
- XCTAssertEqualObjects(updatedPriority, self.priorityNode, @"Should get priority");
- }
- - (void) testChildMergeLooksIntoUpdateNode {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- id<FNode> update = [FSnapshotUtilities nodeFrom:@{@"foo":@"foo-value", @"bar":@"bar-value"}];
- compoundWrite = [compoundWrite addWrite:update atPath:[FPath empty]];
- compoundWrite = [compoundWrite childCompoundWriteAtPath:[[FPath alloc] initWith:@"foo"]];
- id<FNode> updatedNode = [compoundWrite applyToNode:[FEmptyNode emptyNode]];
- id<FNode> expectedNode = [FSnapshotUtilities nodeFrom:@"foo-value"];
- XCTAssertEqualObjects(updatedNode, expectedNode, @"Child merge should get updates.");
- }
- - (void) testChildMergeRemovesNodeOnDeeperPaths {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- id<FNode> update = [FSnapshotUtilities nodeFrom:@{@"foo":@"foo-value", @"bar":@"bar-value"}];
- compoundWrite = [compoundWrite addWrite:update atPath:[FPath empty]];
- compoundWrite = [compoundWrite childCompoundWriteAtPath:[[FPath alloc] initWith:@"foo/not/existing"]];
- id<FNode> updatedNode = [compoundWrite applyToNode:self.leafNode];
- id<FNode> expectedNode = [FEmptyNode emptyNode];
- XCTAssertEqualObjects(updatedNode, expectedNode, @"Should not have node.");
- }
- - (void) testChildMergeWithEmptyPathIsSameMerge {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- id<FNode> update = [FSnapshotUtilities nodeFrom:@{@"foo":@"foo-value", @"bar":@"bar-value"}];
- compoundWrite = [compoundWrite addWrite:update atPath:[FPath empty]];
- XCTAssertEqualObjects([compoundWrite childCompoundWriteAtPath:[FPath empty]], compoundWrite,
- @"Child merge with empty path should be the same merge.");
- }
- - (void) testRootUpdateRemovesRootPriority {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.priorityNode atPath:[[FPath alloc] initWith:@".priority"]];
- id<FNode> update = [FSnapshotUtilities nodeFrom:@"foo"];
- compoundWrite = [compoundWrite addWrite:update atPath:[FPath empty]];
- id<FNode> updatedNode = [compoundWrite applyToNode:[FEmptyNode emptyNode]];
- XCTAssertEqualObjects(updatedNode, update, @"Root update should remove root priority");
- }
- - (void) testDeepUpdateRemovesPriorityThere {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.priorityNode atPath:[[FPath alloc] initWith:@"foo/.priority"]];
- id<FNode> update = [FSnapshotUtilities nodeFrom:@"bar"];
- compoundWrite = [compoundWrite addWrite:update atPath:[[FPath alloc] initWith:@"foo"]];
- id<FNode> updatedNode = [compoundWrite applyToNode:[FEmptyNode emptyNode]];
- id<FNode> expectedNode = [FSnapshotUtilities nodeFrom:@{@"foo":@"bar"}];
- XCTAssertEqualObjects(updatedNode, expectedNode, @"Deep update should remove priority there");
- }
- - (void) testAddingUpdatesAtPathWorks {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
- [updateDictionary setObject:@"foo-value" forKey:@"foo"];
- [updateDictionary setObject:@"bar-value" forKey:@"bar"];
- FCompoundWrite *updates = [FCompoundWrite compoundWriteWithValueDictionary:updateDictionary];
- compoundWrite = [compoundWrite addCompoundWrite:updates atPath:[[FPath alloc] initWith:@"child-1"]];
- NSDictionary *expectedChild1 = @{@"foo":@"foo-value", @"bar":@"bar-value"};
- id<FNode> expectedNode = [self.baseNode updateImmediateChild:@"child-1" withNewChild:[FSnapshotUtilities nodeFrom:expectedChild1]];
- id<FNode> updatedNode = [compoundWrite applyToNode:self.baseNode];
- XCTAssertEqualObjects(updatedNode, expectedNode, @"Adding updates at a path should work.");
- }
- - (void) testAddingUpdatesAtRootWorks {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
- [updateDictionary setObject:@"new-value-1" forKey:@"child-1"];
- [updateDictionary setObject:[NSNull null] forKey:@"child-2"];
- [updateDictionary setObject:@"value-3" forKey:@"child-3"];
- FCompoundWrite *updates = [FCompoundWrite compoundWriteWithValueDictionary:updateDictionary];
- compoundWrite = [compoundWrite addCompoundWrite:updates atPath:[FPath empty]];
- NSDictionary *expected = @{@"child-1":@"new-value-1", @"child-3":@"value-3"};
- id<FNode> updatedNode = [compoundWrite applyToNode:self.baseNode];
- id<FNode> expectedNode = [FSnapshotUtilities nodeFrom:expected];
- XCTAssertEqualObjects(updatedNode, expectedNode, @"Adding updates at root should work.");
- }
- - (void) testChildMergeOfRootPriorityWorks {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.priorityNode atPath:[[FPath alloc] initWith:@".priority"]];
- compoundWrite = [compoundWrite childCompoundWriteAtPath:[[FPath alloc] initWith:@".priority"]];
- id<FNode> updatedNode = [compoundWrite applyToNode:[FEmptyNode emptyNode]];
- XCTAssertEqualObjects(updatedNode, self.priorityNode, @"Child merge of root priority should work.");
- }
- - (void) testCompleteChildrenOnlyReturnsCompleteOverwrites {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.leafNode atPath:[[FPath alloc] initWith:@"child-1"]];
- NSArray *expectedChildren = @[[[FNamedNode alloc] initWithName:@"child-1" andNode:self.leafNode]];
- NSArray *completeChildren = [compoundWrite completeChildren];
- XCTAssertEqualObjects(completeChildren, expectedChildren, @"Complete children should only return on complete overwrites.");
- }
- - (void) testCompleteChildrenOnlyReturnsEmptyOverwrites {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:[FEmptyNode emptyNode] atPath:[[FPath alloc] initWith:@"child-1"]];
- NSArray *expectedChildren = @[[[FNamedNode alloc] initWithName:@"child-1" andNode:[FEmptyNode emptyNode]]];
- NSArray *completeChildren = [compoundWrite completeChildren];
- XCTAssertEqualObjects(completeChildren, expectedChildren, @"Complete children should return list with empty on empty overwrites.");
- }
- - (void) testCompleteChildrenDoesntReturnDeepOverwrites {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.leafNode atPath:[[FPath alloc] initWith:@"child-1/deep/path"]];
- NSArray *expectedChildren = @[];
- NSArray *completeChildren = [compoundWrite completeChildren];
- XCTAssertEqualObjects(completeChildren, expectedChildren, @"Should not get complete children on deep overwrites.");
- }
- - (void) testCompleteChildrenReturnAllCompleteChildrenButNoIncomplete {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.leafNode atPath:[[FPath alloc] initWith:@"child-1/deep/path"]];
- compoundWrite = [compoundWrite addWrite:self.leafNode atPath:[[FPath alloc] initWith:@"child-2"]];
- compoundWrite = [compoundWrite addWrite:[FEmptyNode emptyNode] atPath:[[FPath alloc] initWith:@"child-3"]];
- NSDictionary *expected = @{
- @"child-2":self.leafNode,
- @"child-3":[FEmptyNode emptyNode]
- };
- NSMutableDictionary *actual = [[NSMutableDictionary alloc] init];
- for (FNamedNode *node in compoundWrite.completeChildren) {
- [actual setObject:node.node forKey:node.name];
- }
- XCTAssertEqualObjects(actual, expected, @"Complete children should get returned, but not incomplete ones.");
- }
- - (void) testCompleteChildrenReturnAllChildrenForRootSet {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.baseNode atPath:[FPath empty]];
- NSDictionary *expected = @{
- @"child-1": [FSnapshotUtilities nodeFrom:@"value-1"],
- @"child-2": [FSnapshotUtilities nodeFrom:@"value-2"]
- };
- NSMutableDictionary *actual = [[NSMutableDictionary alloc] init];
- for (FNamedNode *node in compoundWrite.completeChildren) {
- [actual setObject:node.node forKey:node.name];
- }
- XCTAssertEqualObjects(actual, expected, @"Complete children should return all children on root set.");
- }
- - (void) testEmptyMergeHasNoShadowingWrite {
- XCTAssertFalse([[FCompoundWrite emptyWrite] hasCompleteWriteAtPath:[FPath empty]], @"Empty merge has no shadowing write.");
- }
- - (void) testCompoundWriteWithEmptyRootHasShadowingWrite {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:[FEmptyNode emptyNode] atPath:[FPath empty]];
- XCTAssertTrue([compoundWrite hasCompleteWriteAtPath:[FPath empty]], @"Empty write should have shadowing write at root.");
- XCTAssertTrue([compoundWrite hasCompleteWriteAtPath:[[FPath alloc] initWith:@"child"]], @"Empty write should have complete write at child.");
- }
- - (void) testCompoundWriteWithRootHasShadowingWrite {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.leafNode atPath:[FPath empty]];
- XCTAssertTrue([compoundWrite hasCompleteWriteAtPath:[FPath empty]], @"Root write should have shadowing write at root.");
- XCTAssertTrue([compoundWrite hasCompleteWriteAtPath:[[FPath alloc] initWith:@"child"]], @"Root write should have complete write at child.");
- }
- - (void) testCompoundWriteWithDeepUpdateHasShadowingWrite {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.leafNode atPath:[[FPath alloc] initWith:@"deep/update"]];
- XCTAssertFalse([compoundWrite hasCompleteWriteAtPath:[FPath empty]], @"Deep write should not have complete write at root.");
- XCTAssertFalse([compoundWrite hasCompleteWriteAtPath:[[FPath alloc] initWith:@"deep"]], @"Deep write should not have should have complete write at child.");
- XCTAssertTrue([compoundWrite hasCompleteWriteAtPath:[[FPath alloc] initWith:@"deep/update"]], @"Deep write should have complete write at deep child.");
- }
- - (void) testCompoundWriteWithPriorityUpdateHasShadowingWrite {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.priorityNode atPath:[[FPath alloc] initWith:@".priority"]];
- XCTAssertFalse([compoundWrite hasCompleteWriteAtPath:[FPath empty]], @"Write with priority at root should not have complete write at root.");
- XCTAssertTrue([compoundWrite hasCompleteWriteAtPath:[[FPath alloc] initWith:@".priority"]], @"Write with priority at root should have complete priority.");
- }
- - (void) testUpdatesCanBeRemoved {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- id<FNode> update = [FSnapshotUtilities nodeFrom:@{@"foo":@"foo-value", @"bar":@"bar-value"}];
- compoundWrite = [compoundWrite addWrite:update atPath:[[FPath alloc] initWith:@"child-1"]];
- compoundWrite = [compoundWrite removeWriteAtPath:[[FPath alloc] initWith:@"child-1"]];
- id<FNode> updatedNode = [compoundWrite applyToNode:self.baseNode];
- XCTAssertEqualObjects(updatedNode, self.baseNode, @"Updates should be removed.");
- }
- - (void) testDeepRemovesHasNoEffectOnOverlayingSet {
- // TODO I don't get this one.
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- id<FNode> update1 = [FSnapshotUtilities nodeFrom:@{@"foo":@"foo-value", @"bar":@"bar-value"}];
- id<FNode> update2 = [FSnapshotUtilities nodeFrom:@"baz-value"];
- id<FNode> update3 = [FSnapshotUtilities nodeFrom:@"new-foo-value"];
- compoundWrite = [compoundWrite addWrite:update1 atPath:[[FPath alloc] initWith:@"child-1"]];
- compoundWrite = [compoundWrite addWrite:update2 atPath:[[FPath alloc] initWith:@"child-1/baz"]];
- compoundWrite = [compoundWrite addWrite:update3 atPath:[[FPath alloc] initWith:@"child-1/foo"]];
- compoundWrite = [compoundWrite removeWriteAtPath:[[FPath alloc] initWith:@"child-1/foo"]];
- NSDictionary *expected = @{
- @"foo":@"new-foo-value",
- @"bar":@"bar-value",
- @"baz":@"baz-value"
- };
- id<FNode> updatedNode = [compoundWrite applyToNode:self.baseNode];
- id<FNode> expectedNode = [self.baseNode updateImmediateChild:@"child-1" withNewChild:[FSnapshotUtilities nodeFrom:expected]];
- XCTAssertEqualObjects(updatedNode, expectedNode, @"Deep removes should have no effect on overlaying set.");
- }
- - (void) testRemoveAtPathWithoutSetIsWithoutEffect {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- id<FNode> update1 = [FSnapshotUtilities nodeFrom:@{@"foo":@"foo-value", @"bar":@"bar-value"}];
- id<FNode> update2 = [FSnapshotUtilities nodeFrom:@"baz-value"];
- id<FNode> update3 = [FSnapshotUtilities nodeFrom:@"new-foo-value"];
- compoundWrite = [compoundWrite addWrite:update1 atPath:[[FPath alloc] initWith:@"child-1"]];
- compoundWrite = [compoundWrite addWrite:update2 atPath:[[FPath alloc] initWith:@"child-1/baz"]];
- compoundWrite = [compoundWrite addWrite:update3 atPath:[[FPath alloc] initWith:@"child-1/foo"]];
- compoundWrite = [compoundWrite removeWriteAtPath:[[FPath alloc] initWith:@"child-2"]];
- NSDictionary *expected = @{
- @"foo":@"new-foo-value",
- @"bar":@"bar-value",
- @"baz":@"baz-value"
- };
- id<FNode> updatedNode = [compoundWrite applyToNode:self.baseNode];
- id<FNode> expectedNode = [self.baseNode updateImmediateChild:@"child-1" withNewChild:[FSnapshotUtilities nodeFrom:expected]];
- XCTAssertEqualObjects(updatedNode, expectedNode, @"Removing at path without a set should have no effect.");
- }
- - (void) testCanRemovePriority {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.priorityNode atPath:[[FPath alloc] initWith:@".priority"]];
- compoundWrite = [compoundWrite removeWriteAtPath:[[FPath alloc] initWith:@".priority"]];
- [self assertAppliedCompoundWrite:compoundWrite equalsNode:self.leafNode withPriority:[FEmptyNode emptyNode]];
- }
- - (void) testRemovingOnlyAffectsRemovedPath {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- NSDictionary *updateDictionary = @{
- @"child-1": @"new-value-1",
- @"child-2": [NSNull null],
- @"child-3": @"value-3"
- };
- FCompoundWrite *updates = [FCompoundWrite compoundWriteWithValueDictionary:updateDictionary];
- compoundWrite = [compoundWrite addCompoundWrite:updates atPath:[FPath empty]];
- compoundWrite = [compoundWrite removeWriteAtPath:[[FPath alloc] initWith:@"child-2"]];
- NSDictionary *expected = @{
- @"child-1": @"new-value-1",
- @"child-2": @"value-2",
- @"child-3": @"value-3"
- };
- id<FNode> updatedNode = [compoundWrite applyToNode:self.baseNode];
- id<FNode> expectedNode = [FSnapshotUtilities nodeFrom:expected];
- XCTAssertEqualObjects(updatedNode, expectedNode, @"Removing should only affected removed paths");
- }
- - (void) testRemoveRemovesAllDeeperSets {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- id<FNode> update2 = [FSnapshotUtilities nodeFrom:@"baz-value"];
- id<FNode> update3 = [FSnapshotUtilities nodeFrom:@"new-foo-value"];
- compoundWrite = [compoundWrite addWrite:update2 atPath:[[FPath alloc] initWith:@"child-1/baz"]];
- compoundWrite = [compoundWrite addWrite:update3 atPath:[[FPath alloc] initWith:@"child-1/foo"]];
- compoundWrite = [compoundWrite removeWriteAtPath:[[FPath alloc] initWith:@"child-1"]];
- id<FNode> updatedNode = [compoundWrite applyToNode:self.baseNode];
- XCTAssertEqualObjects(updatedNode, self.baseNode, @"Remove should remove deeper sets.");
- }
- - (void) testRemoveAtRootAlsoRemovesPriority {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:[[FLeafNode alloc] initWithValue:@"foo" withPriority:self.priorityNode] atPath:[FPath empty]];
- compoundWrite = [compoundWrite removeWriteAtPath:[FPath empty]];
- id<FNode> node = [FSnapshotUtilities nodeFrom:@"value"];
- [self assertAppliedCompoundWrite:compoundWrite equalsNode:node withPriority:[FEmptyNode emptyNode]];
- }
- - (void) testUpdatingPriorityDoesntOverwriteLeafNode {
- // TODO I don't get this one.
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.leafNode atPath:[FPath empty]];
- compoundWrite = [compoundWrite addWrite:self.priorityNode atPath:[[FPath alloc] initWith:@"child/.priority"]];
- id<FNode> updatedNode = [compoundWrite applyToNode:[FEmptyNode emptyNode]];
- XCTAssertEqualObjects(updatedNode, self.leafNode, @"Updating priority should not overwrite leaf node.");
- }
- - (void) testUpdatingEmptyChildNodeDoesntOverwriteLeafNode {
- FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite];
- compoundWrite = [compoundWrite addWrite:self.leafNode atPath:[FPath empty]];
- compoundWrite = [compoundWrite addWrite:[FEmptyNode emptyNode] atPath:[[FPath alloc] initWith:@"child"]];
- id<FNode> updatedNode = [compoundWrite applyToNode:[FEmptyNode emptyNode]];
- XCTAssertEqualObjects(updatedNode, self.leafNode, @"Updating empty node should not overwrite leaf node.");
- }
- @end
|