/*
* (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others.
*
* 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.
*
* Contributors:
* Florent Guillaume
*/
package org.nuxeo.ecm.core.storage;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.nuxeo.ecm.core.storage.State.NOP;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.nuxeo.ecm.core.storage.State.ListDiff;
import org.nuxeo.ecm.core.storage.State.StateDiff;
public class TestStateHelper {
// always return a List<Serializable> that is Serializable
private static final ArrayList<Object> list(Object... strings) {
return new ArrayList<>(Arrays.asList(strings));
}
private static final StateDiff stateDiff(Serializable... values) {
assertTrue(values.length % 2 == 0);
StateDiff diff = new StateDiff();
for (int i = 0; i < values.length; i += 2) {
diff.put((String) values[i], values[i + 1]);
}
return diff;
}
private static final ListDiff listDiff(List<Object> diff, List<Object> rpush) {
ListDiff listDiff = new ListDiff();
listDiff.diff = diff;
listDiff.rpush = rpush;
return listDiff;
}
private static final ListDiff listDiff(Object... diffs) {
return listDiff(list(diffs), null);
}
private static final ListDiff rpush(Object... values) {
return listDiff(null, list(values));
}
private static final State state(Serializable... values) {
return stateDiff(values);
}
private static void assertEqualsStrict(Serializable a, Serializable b) {
assertEqualsStrict(a + "!=" + b, a, b);
}
private static void assertEqualsStrict(String message, Serializable a, Serializable b) {
assertTrue(message, StateHelper.equalsStrict(a, b));
}
private static void assertNotEqualsStrict(Serializable a, Serializable b) {
assertFalse(StateHelper.equalsStrict(a, b));
}
private static void assertEqualsLoose(Serializable a, Serializable b) {
assertTrue(a + "!=" + b, StateHelper.equalsLoose(a, b));
}
/**
* StateHelper.equals is used internally for the tests.
*
* @since 5.9.5
*/
@Test
public void testEqualsStrict() {
// null
assertEqualsStrict((Serializable) null, (Serializable) null);
assertNotEqualsStrict((Serializable) null, "foo");
// Serializable
assertEqualsStrict("foo", "foo");
assertNotEqualsStrict("foo", "bar");
assertEqualsStrict(Long.valueOf(123456), Long.valueOf(123456));
assertNotEqualsStrict(Long.valueOf(123456), Long.valueOf(789123));
assertNotEqualsStrict("foo", Long.valueOf(123456));
// mixed
assertNotEqualsStrict("foo", new State());
assertNotEqualsStrict("foo", new ArrayList<Serializable>());
assertNotEqualsStrict(new State(), new ArrayList<Serializable>());
// Arrays
assertEqualsStrict(new String[0], new String[0]);
assertEqualsStrict(new String[] { "foo" }, new String[] { "foo" });
assertNotEqualsStrict(new String[] { "foo" }, new String[] { "bar" });
// States
State a = new State();
State b = new State();
assertEqualsStrict(a, b);
a.put("foo", "bar");
assertNotEqualsStrict(a, b);
b.put("foo", "bar");
assertEqualsStrict(a, b);
b.put("foo", "moo");
assertNotEqualsStrict(a, b);
a.put("foo", new State());
b.put("foo", new State());
assertEqualsStrict(a, b);
// Lists
ArrayList<Serializable> la = new ArrayList<Serializable>();
ArrayList<Serializable> lb = new ArrayList<Serializable>();
assertEqualsStrict(la, lb);
la.add(new State());
assertNotEqualsStrict(la, lb);
lb.add(new State());
assertEqualsStrict(la, lb);
((State) la.get(0)).put("foo", "bar");
assertNotEqualsStrict(la, lb);
((State) lb.get(0)).put("foo", "bar");
assertEqualsStrict(la, lb);
((State) lb.get(0)).put("foo", "moo");
assertNotEqualsStrict(la, lb);
}
@Test
public void testEqualsLoose() {
// Arrays
assertEqualsLoose(null, new String[0]);
assertEqualsLoose(new String[0], null);
// Lists
assertEqualsLoose(null, new ArrayList<Serializable>());
assertEqualsLoose(new ArrayList<Serializable>(), null);
// States
assertEqualsLoose(new State(), null);
assertEqualsLoose(null, new State());
State a = new State();
State b = new State();
assertEqualsLoose(a, b);
a.put("foo", null);
a.put("bar", null);
assertEqualsLoose(a, b);
a.put("foo", "bar");
b.put("foo", "bar");
assertEqualsLoose(a, b);
b.put("gee", null);
assertEqualsLoose(a, b);
// empty elements considered null
State c = new State();
assertEqualsLoose(c, null);
c.put("foo", list());
assertEqualsLoose(c, null);
}
private static void assertDiff(Serializable expected, Serializable a, Serializable b) {
Serializable diff = StateHelper.diff(a, b);
assertEqualsStrict(diff.toString(), expected, diff);
}
@Test
public void testDiffList() {
assertDiff(NOP, //
list(), list());
// overwrite
assertDiff(list("B"), //
list("A"), list("B"));
assertDiff(list("B", "C"), //
list("A"), list("B", "C"));
// "RPUSH"
assertDiff(rpush("B"), //
list("A"), list("A", "B"));
assertDiff(rpush("C", "D"), //
list("A", "B"), list("A", "B", "C", "D"));
// overwrite for zero-length "a"
assertDiff(list("A"), //
list(), list("A"));
assertDiff(list("A", "B"), //
list(), list("A", "B"));
// overwrite for zero-length "b"
assertDiff(list(), //
list("A"), list());
}
@Test
public void testDiffListComplex() {
assertDiff(NOP, //
list(state("A", "B"), state("C", "D")), //
list(state("A", "B"), state("C", "D")));
assertDiff(rpush(state("C", "D")), //
list(state("A", "B")), //
list(state("A", "B"), state("C", "D")));
// TODO check this
assertDiff(listDiff(state("A", "B")), //
list(state()), //
list(state("A", "B")));
assertDiff(listDiff(list(state("C", "D")), list(state("E", "F"))), //
list(state("A", "B")), //
list(state("A", "B", "C", "D"), state("E", "F")));
}
@Test
public void testDiffState() {
assertDiff(NOP, state(), state());
// added keys
assertDiff(NOP, //
state("A", "B"), state("A", "B"));
assertDiff(stateDiff("A", "B"), //
state(), state("A", "B"));
assertDiff(stateDiff("C", "D"), //
state("A", "B"), state("A", "B", "C", "D"));
// removed keys
assertDiff(stateDiff("A", null), //
state("A", "B"), state());
assertDiff(stateDiff("A", null), //
state("A", "B", "C", "D"), state("C", "D"));
// changed values
assertDiff(stateDiff("A", "C"), //
state("A", "B"), state("A", "C"));
assertDiff(stateDiff("A", "C"), //
state("1", "2", "A", "B"), state("1", "2", "A", "C"));
// changed values which are diffs
assertDiff(stateDiff("A", rpush("C")), //
state("A", (Serializable) list("B")), state("A", (Serializable) list("B", "C")));
assertDiff(stateDiff("A", stateDiff("B", "D")), //
state("A", state("1", "2", "B", "C")), state("A", state("1", "2", "B", "D")));
}
@Test
public void testDiffStateNulls() {
assertDiff(NOP, state("X", null), state());
assertDiff(NOP, state(), state("X", null));
assertDiff(stateDiff("A", "B"), //
state("X", null), state("A", "B"));
assertDiff(stateDiff("A", "B"), //
state(), state("A", "B", "X", null));
}
}