/*
* Copyright 2017 Google Inc.
*
* 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.
*/
package com.google.firebase.database.core;
import static com.google.firebase.database.TestHelpers.fromSingleQuotedString;
import static com.google.firebase.database.TestHelpers.path;
import static com.google.firebase.database.snapshot.NodeUtilities.NodeFromJSON;
import static org.junit.Assert.assertEquals;
import com.google.firebase.database.snapshot.EmptyNode;
import com.google.firebase.database.snapshot.Node;
import com.google.firebase.database.snapshot.RangeMerge;
import org.junit.Ignore;
import org.junit.Test;
public class RangeMergeTest {
@Test
public void smokeTest() {
Node node =
NodeFromJSON(
fromSingleQuotedString(
"{'bar': 'bar-value', 'foo': { 'a': {'deep-a-1': 1, 'deep-a-2':2}, 'b': 'b', "
+ "'c': 'c', 'd': 'd'}, 'quu': 'quu-value'}"));
Node update =
NodeFromJSON(
fromSingleQuotedString(
"{'foo': { 'a': {'deep-a-2':'new-a-2', 'deep-a-3':3}, 'b-2': 'new-b', 'c': "
+ "'new-c' }}"));
RangeMerge merge = new RangeMerge(path("foo/a/deep-a-1"), path("foo/c"), update);
Node actual = merge.applyTo(node);
Node expected =
NodeFromJSON(
fromSingleQuotedString(
"{'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'}"));
assertEquals(expected, actual);
}
@Test
public void startIsExclusive() {
Node node =
NodeFromJSON(
fromSingleQuotedString(
"{'bar': 'bar-value', 'foo': 'foo-value', 'quu': " + "'quu-value'}"));
Node update = NodeFromJSON(fromSingleQuotedString("{'foo': 'new-foo-value' }"));
RangeMerge merge = new RangeMerge(path("bar"), path("foo"), update);
Node actual = merge.applyTo(node);
Node expected =
NodeFromJSON(
fromSingleQuotedString(
"{'bar': 'bar-value', 'foo': 'new-foo-value', 'quu': 'quu-value'}"));
assertEquals(expected, actual);
}
@Test
public void startIsExclusiveButIncludesChildren() {
Node node =
NodeFromJSON(
fromSingleQuotedString(
"{'bar': 'bar-value', 'foo': 'foo-value', 'quu': " + "'quu-value'}"));
Node update =
NodeFromJSON(
fromSingleQuotedString(
"{'bar': {'bar-child': 'bar-child-value'}, 'foo': 'new-foo-value' }"));
RangeMerge merge = new RangeMerge(path("bar"), path("foo"), update);
Node actual = merge.applyTo(node);
Node expected =
NodeFromJSON(
fromSingleQuotedString(
"{'bar': { 'bar-child': 'bar-child-value'}, 'foo': 'new-foo-value', 'quu': "
+ "'quu-value'}"));
assertEquals(expected, actual);
}
@Test
public void endIsInclusive() {
Node node =
NodeFromJSON(
fromSingleQuotedString(
"{'bar': 'bar-value', 'foo': 'foo-value', 'quu': " + "'quu-value'}"));
Node update = NodeFromJSON(fromSingleQuotedString("{'baz': 'baz-value' }"));
RangeMerge merge = new RangeMerge(path("bar"), path("foo"), update); // foo should be
// deleted
Node actual = merge.applyTo(node);
Node expected =
NodeFromJSON(
fromSingleQuotedString(
"{'bar': 'bar-value', 'baz': 'baz-value', 'quu': " + "'quu-value'}"));
assertEquals(expected, actual);
}
@Test
public void endIsInclusiveButExcludesChildren() {
Node node =
NodeFromJSON(
fromSingleQuotedString(
"{'bar': 'bar-value', 'foo': {'foo-child': 'foo-child-value'}, 'quu': "
+ "'quu-value'}"));
Node update = NodeFromJSON(fromSingleQuotedString("{'baz': 'baz-value' }"));
RangeMerge merge = new RangeMerge(path("bar"), path("foo"), update);
Node actual = merge.applyTo(node);
Node expected =
NodeFromJSON(
fromSingleQuotedString(
"{'bar': 'bar-value', 'baz': 'baz-value', 'foo': {'foo-child': "
+ "'foo-child-value'}, 'quu': 'quu-value'}"));
assertEquals(expected, actual);
}
@Test
public void canUpdateLeafNode() {
Node node = NodeFromJSON("leaf-value");
Node update = NodeFromJSON(fromSingleQuotedString("{'bar': 'bar-value' }"));
RangeMerge merge = new RangeMerge(null, path("foo"), update);
Node actual = merge.applyTo(node);
Node expected = NodeFromJSON(fromSingleQuotedString("{'bar': 'bar-value'}"));
assertEquals(expected, actual);
}
@Test
public void canReplaceLeafNodeWithLeafNode() {
Node node = NodeFromJSON("leaf-value");
Node update = NodeFromJSON("new-leaf-value");
RangeMerge merge = new RangeMerge(null, path("/"), update);
Node actual = merge.applyTo(node);
Node expected = NodeFromJSON("new-leaf-value");
assertEquals(expected, actual);
}
@Test
public void leafsAreUpdatedWhenRangesIncludeDeeperPath() {
Node node = NodeFromJSON(fromSingleQuotedString("{'foo': {'bar': 'bar-value'}}"));
Node update = NodeFromJSON(fromSingleQuotedString("{'foo': {'bar': 'new-bar-value'}}"));
RangeMerge merge = new RangeMerge(path("foo/"), path("foo/bar/deep"), update);
Node actual = merge.applyTo(node);
Node expected = NodeFromJSON(fromSingleQuotedString("{'foo': {'bar': 'new-bar-value'}}"));
assertEquals(expected, actual);
}
@Test
public void leafsAreNotUpdatedWhenRangesAreAtDeeperPaths() {
Node node = NodeFromJSON(fromSingleQuotedString("{'foo': {'bar': 'bar-value'}}"));
Node update = NodeFromJSON(fromSingleQuotedString("{'foo': {'bar': 'new-bar-value'}}"));
RangeMerge merge = new RangeMerge(path("foo/bar"), path("foo/bar/deep"), update);
Node actual = merge.applyTo(node);
Node expected = NodeFromJSON(fromSingleQuotedString("{'foo': {'bar': 'bar-value'}}"));
assertEquals(expected, actual);
}
@Test
public void updatingEntireRangeUpdatesEverything() {
Node node = EmptyNode.Empty();
Node update =
NodeFromJSON(
fromSingleQuotedString("{'foo': 'foo-value', 'bar': {'child':'bar-child-value'}}"));
RangeMerge merge = new RangeMerge(null, null, update);
Node actual = merge.applyTo(node);
Node expected =
NodeFromJSON(
fromSingleQuotedString("{'foo': 'foo-value', 'bar': {'child':'bar-child-value'}}"));
assertEquals(expected, actual);
}
@Test
public void updatingRangeWithUnboundedLeftPostWorks() {
Node node =
NodeFromJSON(fromSingleQuotedString("{'bar': 'bar-value', 'foo': " + "'foo-value'}"));
Node update = NodeFromJSON(fromSingleQuotedString("{'bar': 'new-bar'}"));
RangeMerge merge = new RangeMerge(null, path("bar"), update);
Node actual = merge.applyTo(node);
Node expected =
NodeFromJSON(fromSingleQuotedString("{'bar': 'new-bar', 'foo': " + "'foo-value'}"));
assertEquals(expected, actual);
}
@Test
public void updatingRangeWithRightPostChildOfLeftPostWorks() {
Node node =
NodeFromJSON(
fromSingleQuotedString("{'foo': {'a': 'a', 'b': {'1': '1', '2': '2'}, 'c': 'c'}}"));
Node update =
NodeFromJSON(fromSingleQuotedString("{'foo': {'a': 'new-a', 'b': {'1': 'new-1'}}}"));
RangeMerge merge = new RangeMerge(path("foo"), path("foo/b/1"), update);
Node actual = merge.applyTo(node);
Node expected =
NodeFromJSON(
fromSingleQuotedString(
"{'foo': {'a': 'new-a', 'b': {'1': 'new-1', '2': '2'}, 'c': 'c'}}"));
assertEquals(expected, actual);
}
@Test
public void updatingRangeWithRightPostChildOfLeftPostWorksWithIntegerKeys() {
Node node =
NodeFromJSON(
fromSingleQuotedString(
"{'foo': {'a': 'a', 'b': {'1': '1', '2': '2', '10': '10'}, 'c': 'c'}}"));
Node update =
NodeFromJSON(fromSingleQuotedString("{'foo': {'a': 'new-a', 'b': {'1': 'new-1'}}}"));
RangeMerge merge = new RangeMerge(path("foo"), path("foo/b/2"), update);
Node actual = merge.applyTo(node);
Node expected =
NodeFromJSON(
fromSingleQuotedString(
"{'foo': {'a': 'new-a', 'b': {'1': 'new-1', '10': '10'}, 'c': 'c'}}"));
assertEquals(expected, actual);
}
@Test
public void updatingLeafIncludesPriority() {
Node node =
NodeFromJSON(
fromSingleQuotedString(
"{'bar': 'bar-value', 'foo': 'foo-value', 'quu': " + "'quu-value'}"));
Node update =
NodeFromJSON(
fromSingleQuotedString("{'foo': { '.value': 'new-foo', '.priority': 'prio' }}"));
RangeMerge merge = new RangeMerge(path("bar"), path("foo"), update);
Node actual = merge.applyTo(node);
Node expected =
NodeFromJSON(
fromSingleQuotedString(
"{'bar': 'bar-value', 'foo': { '.value': 'new-foo', '.priority': 'prio' }, "
+ "'quu': 'quu-value'}"));
assertEquals(expected, actual);
}
@Test
public void updatingPriorityInChildrenNodeWorks() {
Node node =
NodeFromJSON(fromSingleQuotedString("{'bar': 'bar-value', 'foo': " + "'foo-value'}"));
Node update =
NodeFromJSON(fromSingleQuotedString("{'bar': 'new-bar', '.priority': 'prio'" + " }"));
RangeMerge merge = new RangeMerge(null, path("bar"), update);
Node actual = merge.applyTo(node);
Node expected =
NodeFromJSON(
fromSingleQuotedString(
"{'bar': 'new-bar', 'foo': 'foo-value', '.priority': " + "'prio'}"));
assertEquals(expected, actual);
}
// TODO: this test should actually work, but priorities on empty nodes are ignored :(
@Test
@Ignore
public void updatingPriorityInChildrenNodeWorksAlone() {
Node node =
NodeFromJSON(fromSingleQuotedString("{'bar': 'bar-value', 'foo': " + "'foo-value'}"));
Node update = NodeFromJSON(fromSingleQuotedString("{'.priority': 'prio' }"));
RangeMerge merge = new RangeMerge(null, path(".priority"), update);
Node actual = merge.applyTo(node);
Node expected =
NodeFromJSON(
fromSingleQuotedString(
"{'bar': 'bar-value', 'foo': 'foo-value', '.priority': 'prio'}"));
assertEquals(expected, actual);
}
@Test
public void updatingPriorityOnInitiallyEmptyNodeDoesNotBreak() {
Node node = NodeFromJSON(fromSingleQuotedString("{}"));
Node update =
NodeFromJSON(fromSingleQuotedString("{'.priority': 'prio', 'foo': 'foo-value' }"));
RangeMerge merge = new RangeMerge(null, path("foo"), update);
Node actual = merge.applyTo(node);
Node expected =
NodeFromJSON(fromSingleQuotedString("{'foo': 'foo-value', '.priority': 'prio'}"));
assertEquals(expected, actual);
}
@Test
public void priorityIsDeletedWhenIncludedInChildrenRange() {
Node node =
NodeFromJSON(
fromSingleQuotedString(
"{'bar': 'bar-value', 'foo': 'foo-value', '.priority': 'prio'}"));
Node update = NodeFromJSON(fromSingleQuotedString("{'bar': 'new-bar'}"));
RangeMerge merge = new RangeMerge(null, path("bar"), update); // deletes priority
Node actual = merge.applyTo(node);
Node expected =
NodeFromJSON(fromSingleQuotedString("{'bar': 'new-bar', 'foo': " + "'foo-value'}"));
assertEquals(expected, actual);
}
@Test
public void priorityIsIncludedInOpenStart() {
Node node = NodeFromJSON(fromSingleQuotedString("{'foo': {'bar': 'bar-value'}}"));
Node update = NodeFromJSON(fromSingleQuotedString("{'.priority': 'prio', 'baz': 'baz' }"));
RangeMerge merge = new RangeMerge(null, path("foo/bar"), update);
Node actual = merge.applyTo(node);
Node expected = NodeFromJSON(fromSingleQuotedString("{'baz': 'baz', '.priority': 'prio'}"));
assertEquals(expected, actual);
}
@Test
public void priorityIsIncludedInOpenEnd() {
Node node = NodeFromJSON("leaf-value");
Node update = NodeFromJSON(fromSingleQuotedString("{'.priority': 'prio', 'foo': 'bar' }"));
RangeMerge merge = new RangeMerge(path("/"), null, update);
Node actual = merge.applyTo(node);
Node expected = NodeFromJSON(fromSingleQuotedString("{'foo': 'bar', '.priority': 'prio'}"));
assertEquals(expected, actual);
}
}