getRemoveSet() {
88 | return new GSet<>(removeSet.lookup());
89 | }
90 |
91 | @Override
92 | public boolean equals(Object o) {
93 | if (this == o) return true;
94 | if (o == null || getClass() != o.getClass()) return false;
95 |
96 | TwoPSet> twoPSet = (TwoPSet>) o;
97 |
98 | return addSet.equals(twoPSet.addSet) && removeSet.equals(twoPSet.removeSet);
99 | }
100 |
101 | @Override
102 | public int hashCode() {
103 | int result = addSet.hashCode();
104 | result = 31 * result + removeSet.hashCode();
105 | return result;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/io/dmitryivanov/crdt/helpers/ComparisonChain.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 The Guava Authors
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 |
17 | package io.dmitryivanov.crdt.helpers;
18 |
19 | import javax.annotation.Nullable;
20 |
21 | import java.util.Comparator;
22 |
23 | /**
24 | * A utility for performing a chained comparison statement. For example:
25 | * {@code
26 | *
27 | * public int compareTo(Foo that) {
28 | * return ComparisonChain.start()
29 | * .compare(this.aString, that.aString)
30 | * .compare(this.anInt, that.anInt)
31 | * .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
32 | * .result();
33 | * }}
34 | *
35 | * The value of this expression will have the same sign as the first
36 | * nonzero comparison result in the chain, or will be zero if every
37 | * comparison result was zero.
38 | *
39 | *
Note: {@code ComparisonChain} instances are immutable. For
40 | * this utility to work correctly, calls must be chained as illustrated above.
41 | *
42 | *
Performance note: Even though the {@code ComparisonChain} caller always
43 | * invokes its {@code compare} methods unconditionally, the {@code
44 | * ComparisonChain} implementation stops calling its inputs' {@link
45 | * Comparable#compareTo compareTo} and {@link Comparator#compare compare}
46 | * methods as soon as one of them returns a nonzero result. This optimization is
47 | * typically important only in the presence of expensive {@code compareTo} and
48 | * {@code compare} implementations.
49 | *
50 | *
See the Guava User Guide article on
52 | * {@code ComparisonChain}.
53 | *
54 | * @author Mark Davis
55 | * @author Kevin Bourrillion
56 | * @since 2.0
57 | */
58 | public abstract class ComparisonChain {
59 | private ComparisonChain() {}
60 |
61 | /**
62 | * Begins a new chained comparison statement. See example in the class
63 | * documentation.
64 | */
65 | public static ComparisonChain start() {
66 | return ACTIVE;
67 | }
68 |
69 | private static final ComparisonChain ACTIVE =
70 | new ComparisonChain() {
71 | @SuppressWarnings("unchecked")
72 | @Override
73 | public ComparisonChain compare(Comparable left, Comparable right) {
74 | return classify(left.compareTo(right));
75 | }
76 |
77 | @Override
78 | public ComparisonChain compare(
79 | @Nullable T left, @Nullable T right, Comparator comparator) {
80 | return classify(comparator.compare(left, right));
81 | }
82 |
83 | @Override
84 | public ComparisonChain compare(int left, int right) {
85 | return classify(Primitives.compare(left, right));
86 | }
87 |
88 | @Override
89 | public ComparisonChain compare(long left, long right) {
90 | return classify(Primitives.compare(left, right));
91 | }
92 |
93 | @Override
94 | public ComparisonChain compare(float left, float right) {
95 | return classify(Float.compare(left, right));
96 | }
97 |
98 | @Override
99 | public ComparisonChain compare(double left, double right) {
100 | return classify(Double.compare(left, right));
101 | }
102 |
103 | @Override
104 | public ComparisonChain compareTrueFirst(boolean left, boolean right) {
105 | return classify(Primitives.compare(right, left)); // reversed
106 | }
107 |
108 | @Override
109 | public ComparisonChain compareFalseFirst(boolean left, boolean right) {
110 | return classify(Primitives.compare(left, right));
111 | }
112 |
113 | ComparisonChain classify(int result) {
114 | return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE;
115 | }
116 |
117 | @Override
118 | public int result() {
119 | return 0;
120 | }
121 | };
122 |
123 | private static final ComparisonChain LESS = new InactiveComparisonChain(-1);
124 |
125 | private static final ComparisonChain GREATER = new InactiveComparisonChain(1);
126 |
127 | private static final class InactiveComparisonChain extends ComparisonChain {
128 | final int result;
129 |
130 | InactiveComparisonChain(int result) {
131 | this.result = result;
132 | }
133 |
134 | @Override
135 | public ComparisonChain compare(@Nullable Comparable left, @Nullable Comparable right) {
136 | return this;
137 | }
138 |
139 | @Override
140 | public ComparisonChain compare(
141 | @Nullable T left, @Nullable T right, @Nullable Comparator comparator) {
142 | return this;
143 | }
144 |
145 | @Override
146 | public ComparisonChain compare(int left, int right) {
147 | return this;
148 | }
149 |
150 | @Override
151 | public ComparisonChain compare(long left, long right) {
152 | return this;
153 | }
154 |
155 | @Override
156 | public ComparisonChain compare(float left, float right) {
157 | return this;
158 | }
159 |
160 | @Override
161 | public ComparisonChain compare(double left, double right) {
162 | return this;
163 | }
164 |
165 | @Override
166 | public ComparisonChain compareTrueFirst(boolean left, boolean right) {
167 | return this;
168 | }
169 |
170 | @Override
171 | public ComparisonChain compareFalseFirst(boolean left, boolean right) {
172 | return this;
173 | }
174 |
175 | @Override
176 | public int result() {
177 | return result;
178 | }
179 | }
180 |
181 | /**
182 | * Compares two comparable objects as specified by {@link
183 | * Comparable#compareTo}, if the result of this comparison chain
184 | * has not already been determined.
185 | */
186 | public abstract ComparisonChain compare(Comparable> left, Comparable> right);
187 |
188 | /**
189 | * Compares two objects using a comparator, if the result of this
190 | * comparison chain has not already been determined.
191 | */
192 | public abstract ComparisonChain compare(
193 | @Nullable T left, @Nullable T right, Comparator comparator);
194 |
195 | /**
196 | * Compares two {@code int} values as specified by {@link Primitives#compare},
197 | * if the result of this comparison chain has not already been
198 | * determined.
199 | */
200 | public abstract ComparisonChain compare(int left, int right);
201 |
202 | /**
203 | * Compares two {@code long} values as specified by {@link Primitives#compare},
204 | * if the result of this comparison chain has not already been
205 | * determined.
206 | */
207 | public abstract ComparisonChain compare(long left, long right);
208 |
209 | /**
210 | * Compares two {@code float} values as specified by {@link
211 | * Float#compare}, if the result of this comparison chain has not
212 | * already been determined.
213 | */
214 | public abstract ComparisonChain compare(float left, float right);
215 |
216 | /**
217 | * Compares two {@code double} values as specified by {@link
218 | * Double#compare}, if the result of this comparison chain has not
219 | * already been determined.
220 | */
221 | public abstract ComparisonChain compare(double left, double right);
222 |
223 | /**
224 | * Discouraged synonym for {@link #compareFalseFirst}.
225 | *
226 | * @deprecated Use {@link #compareFalseFirst}; or, if the parameters passed
227 | * are being either negated or reversed, undo the negation or reversal and
228 | * use {@link #compareTrueFirst}.
229 | * @since 19.0
230 | */
231 | @Deprecated
232 | public final ComparisonChain compare(Boolean left, Boolean right) {
233 | return compareFalseFirst(left, right);
234 | }
235 |
236 | /**
237 | * Compares two {@code boolean} values, considering {@code true} to be less
238 | * than {@code false}, if the result of this comparison chain has not
239 | * already been determined.
240 | *
241 | * @since 12.0
242 | */
243 | public abstract ComparisonChain compareTrueFirst(boolean left, boolean right);
244 |
245 | /**
246 | * Compares two {@code boolean} values, considering {@code false} to be less
247 | * than {@code true}, if the result of this comparison chain has not
248 | * already been determined.
249 | *
250 | * @since 12.0 (present as {@code compare} since 2.0)
251 | */
252 | public abstract ComparisonChain compareFalseFirst(boolean left, boolean right);
253 |
254 | /**
255 | * Ends this comparison chain and returns its result: a value having the
256 | * same sign as the first nonzero comparison result in the chain, or zero if
257 | * every result was zero.
258 | */
259 | public abstract int result();
260 | }
--------------------------------------------------------------------------------
/src/main/java/io/dmitryivanov/crdt/helpers/Operations.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) pakoito 2016
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 |
17 | package io.dmitryivanov.crdt.helpers;
18 |
19 | import java.util.*;
20 |
21 | public final class Operations {
22 | private Operations() {
23 | // No instances
24 | }
25 |
26 | public static Set diff(Set firstSet, final Set secondSet) {
27 | return filtered(firstSet, new Predicate() {
28 | @Override
29 | public boolean call(E element) {
30 | return !secondSet.contains(element);
31 | }
32 | });
33 | }
34 |
35 | public static Set union(Set firstSet, final Set secondSet) {
36 | final Set newSet = new HashSet<>();
37 | newSet.addAll(firstSet);
38 | newSet.addAll(secondSet);
39 | return newSet;
40 | }
41 |
42 | public static Set filtered(Set set, Predicate predicate) {
43 | final Set newSet = new HashSet<>();
44 | for (E element : set) {
45 | if (predicate.call(element)) {
46 | newSet.add(element);
47 | }
48 | }
49 | return newSet;
50 | }
51 |
52 | public static Set filteredAndMapped(Set set, Predicate predicate,
53 | Mapper mapper) {
54 | final Set newSet = new HashSet<>();
55 | for (E element : set) {
56 | if (predicate.call(element)) {
57 | newSet.add(mapper.call(element));
58 | }
59 | }
60 | return newSet;
61 | }
62 |
63 | public static E select(Set set, Predicate2 predicate) {
64 | if (set.isEmpty()) {
65 | throw new IllegalArgumentException("Empty set for select operation");
66 | }
67 | E winner = set.iterator().next();
68 | for (E element : set) {
69 | if (predicate.call(winner, element)) {
70 | winner = element;
71 | }
72 | }
73 | return winner;
74 | }
75 |
76 | public static Map> groupBy(Collection map, Mapper mapper) {
77 | final Map> newMap = new HashMap<>(map.size());
78 | for (V element : map) {
79 | K key = mapper.call(element);
80 | Collection list = newMap.get(key);
81 | if (null == list) {
82 | list = new ArrayList<>();
83 | }
84 | list.add(element);
85 | newMap.put(key, list);
86 | }
87 | return newMap;
88 | }
89 |
90 | public static Map mapValues(Map map, Mapper mapper) {
91 | final Map newMap = new HashMap<>(map.size());
92 | for (Map.Entry entry : map.entrySet()) {
93 | newMap.put(entry.getKey(), mapper.call(entry.getValue()));
94 | }
95 | return newMap;
96 | }
97 |
98 | public interface Predicate {
99 | boolean call(E element);
100 | }
101 |
102 | public interface Predicate2 {
103 | boolean call(E first, F second);
104 | }
105 |
106 | public interface Mapper {
107 | R call(E element);
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/main/java/io/dmitryivanov/crdt/helpers/Primitives.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2008 The Guava Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 |
15 | package io.dmitryivanov.crdt.helpers;
16 |
17 | public final class Primitives {
18 | private Primitives() {
19 | // No instances
20 | }
21 |
22 | /**
23 | * Compares the two specified {@code boolean} values in the standard way ({@code false} is
24 | * considered less than {@code true}). The sign of the value returned is the same as that of
25 | * {@code ((Boolean) a).compareTo(b)}.
26 | *
27 | * Note for Java 7 and later: this method should be treated as deprecated; use the
28 | * equivalent {@link Boolean#compare} method instead.
29 | *
30 | * @param a the first {@code boolean} to compare
31 | * @param b the second {@code boolean} to compare
32 | * @return a positive number if only {@code a} is {@code true}, a negative number if only
33 | * {@code b} is true, or zero if {@code a == b}
34 | */
35 | public static int compare(boolean a, boolean b) {
36 | return (a == b) ? 0 : (a ? 1 : -1);
37 | }
38 |
39 | /**
40 | * Compares the two specified {@code int} values. The sign of the value returned is the same as
41 | * that of {@code ((Integer) a).compareTo(b)}.
42 | *
43 | *
Note for Java 7 and later: this method should be treated as deprecated; use the
44 | * equivalent {@link Integer#compare} method instead.
45 | *
46 | * @param a the first {@code int} to compare
47 | * @param b the second {@code int} to compare
48 | * @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is
49 | * greater than {@code b}; or zero if they are equal
50 | */
51 | public static int compare(int a, int b) {
52 | return (a < b) ? -1 : ((a > b) ? 1 : 0);
53 | }
54 |
55 | /**
56 | * Compares the two specified {@code long} values. The sign of the value returned is the same as
57 | * that of {@code ((Long) a).compareTo(b)}.
58 | *
59 | *
Note for Java 7 and later: this method should be treated as deprecated; use the
60 | * equivalent {@link Long#compare} method instead.
61 | *
62 | * @param a the first {@code long} to compare
63 | * @param b the second {@code long} to compare
64 | * @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is
65 | * greater than {@code b}; or zero if they are equal
66 | */
67 | public static int compare(long a, long b) {
68 | return (a < b) ? -1 : ((a > b) ? 1 : 0);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/test/java/io/dmitryivanov/crdt/GSetTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2016 Dmitry Ivanov
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package io.dmitryivanov.crdt;
26 |
27 | import java.util.Set;
28 | import org.junit.Test;
29 |
30 | import static org.junit.Assert.assertEquals;
31 | import static org.junit.Assert.assertTrue;
32 |
33 | public class GSetTests {
34 |
35 | @Test
36 | public void testLookup() {
37 | GSet gSet = new GSet<>();
38 |
39 | gSet.add("dog");
40 | gSet.add("ape");
41 | gSet.add("cat");
42 |
43 | // Actual test
44 | Set result = gSet.lookup();
45 |
46 | assertEquals(3, result.size());
47 | assertTrue(result.contains("ape"));
48 | assertTrue(result.contains("dog"));
49 | assertTrue(result.contains("cat"));
50 | }
51 |
52 | @Test
53 | public void testMerge() {
54 | GSet firstGSet = new GSet<>();
55 | firstGSet.add("dog");
56 | firstGSet.add("ape");
57 |
58 | GSet secondGSet = new GSet<>();
59 | secondGSet.add("cat");
60 | secondGSet.add("dog");
61 |
62 | // Actual test
63 | GSet result = firstGSet.merge(secondGSet);
64 |
65 | assertEquals(3, result.lookup().size());
66 | assertTrue(result.lookup().contains("dog"));
67 | assertTrue(result.lookup().contains("cat"));
68 | assertTrue(result.lookup().contains("dog"));
69 |
70 | GSet reverseResult = secondGSet.merge(firstGSet);
71 |
72 | assertEquals(result, reverseResult);
73 | }
74 |
75 | @Test
76 | public void testDiff() {
77 | GSet firstGSet = new GSet<>();
78 | firstGSet.add("dog");
79 | firstGSet.add("ape");
80 |
81 | GSet secondGSet = new GSet<>();
82 | secondGSet.add("cat");
83 | secondGSet.add("dog");
84 |
85 | GSet result = firstGSet.diff(secondGSet);
86 |
87 | assertEquals(1, result.lookup().size());
88 | assertTrue(result.lookup().contains("ape"));
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/test/java/io/dmitryivanov/crdt/LWWSetTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2016 Dmitry Ivanov
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package io.dmitryivanov.crdt;
26 |
27 | import org.junit.Test;
28 |
29 | import java.util.Set;
30 |
31 | import static org.junit.Assert.assertEquals;
32 | import static org.junit.Assert.assertTrue;
33 |
34 | public class LWWSetTests {
35 |
36 | @Test
37 | public void testLookup() {
38 | final LWWSet lwwSet = new LWWSet<>();
39 |
40 | lwwSet.add(new LWWSet.ElementState<>(1, "dog"));
41 | lwwSet.add(new LWWSet.ElementState<>(1, "cat"));
42 | lwwSet.add(new LWWSet.ElementState<>(1, "ape"));
43 | lwwSet.add(new LWWSet.ElementState<>(1, "tiger"));
44 |
45 | lwwSet.remove(new LWWSet.ElementState<>(2, "cat"));
46 | lwwSet.remove(new LWWSet.ElementState<>(2, "dog"));
47 |
48 | // Actual test
49 | final Set lookup = lwwSet.lookup();
50 |
51 | assertEquals(2, lookup.size());
52 | assertTrue(lookup.contains("ape"));
53 | assertTrue(lookup.contains("tiger"));
54 | }
55 |
56 | @Test
57 | public void testMerge() {
58 | final LWWSet firstLwwSet = new LWWSet<>();
59 | firstLwwSet.add(new LWWSet.ElementState<>(3, "ape"));
60 | firstLwwSet.add(new LWWSet.ElementState<>(1, "dog"));
61 | firstLwwSet.add(new LWWSet.ElementState<>(1, "cat"));
62 | firstLwwSet.remove(new LWWSet.ElementState<>(2, "cat"));
63 |
64 | final LWWSet secondLwwSet = new LWWSet<>();
65 | secondLwwSet.add(new LWWSet.ElementState<>(1, "ape"));
66 | secondLwwSet.add(new LWWSet.ElementState<>(1, "tiger"));
67 | secondLwwSet.add(new LWWSet.ElementState<>(1, "cat"));
68 | secondLwwSet.remove(new LWWSet.ElementState<>(2, "ape"));
69 |
70 | // Actual test
71 | final LWWSet resultSet = firstLwwSet.merge(secondLwwSet);
72 |
73 | final GSet> resultAddSet = resultSet.getAddSet();
74 | final Set> addLookup = resultAddSet.lookup();
75 | assertEquals(5, addLookup.size());
76 | assertTrue(addLookup.contains(new LWWSet.ElementState<>(1, "ape")));
77 | assertTrue(addLookup.contains(new LWWSet.ElementState<>(3, "ape")));
78 | assertTrue(addLookup.contains(new LWWSet.ElementState<>(1, "dog")));
79 | assertTrue(addLookup.contains(new LWWSet.ElementState<>(1, "tiger")));
80 | assertTrue(addLookup.contains(new LWWSet.ElementState<>(1, "cat")));
81 |
82 | final GSet> resultRemoveSet = resultSet.getRemoveSet();
83 | final Set> removeLookup = resultRemoveSet.lookup();
84 | assertEquals(2, removeLookup.size());
85 | assertTrue(removeLookup.contains(new LWWSet.ElementState<>(2, "cat")));
86 | assertTrue(removeLookup.contains(new LWWSet.ElementState<>(2, "ape")));
87 | }
88 |
89 | @Test
90 | public void testDiff() {
91 | final LWWSet firstLwwSet = new LWWSet<>();
92 | firstLwwSet.add(new LWWSet.ElementState<>(3, "ape"));
93 | firstLwwSet.add(new LWWSet.ElementState<>(1, "dog"));
94 | firstLwwSet.add(new LWWSet.ElementState<>(2, "tiger"));
95 | firstLwwSet.add(new LWWSet.ElementState<>(1, "cat"));
96 | firstLwwSet.remove(new LWWSet.ElementState<>(2, "cat"));
97 |
98 | final LWWSet secondLwwSet = new LWWSet<>();
99 | secondLwwSet.add(new LWWSet.ElementState<>(1, "ape"));
100 | secondLwwSet.add(new LWWSet.ElementState<>(3, "tiger"));
101 | secondLwwSet.add(new LWWSet.ElementState<>(1, "cat"));
102 | secondLwwSet.remove(new LWWSet.ElementState<>(2, "ape"));
103 |
104 | // Actual test
105 | final LWWSet resultSet = firstLwwSet.diff(secondLwwSet);
106 |
107 | final GSet> resultAddSet = resultSet.getAddSet();
108 | assertEquals(3, resultAddSet.lookup().size());
109 | assertTrue(resultAddSet.lookup().contains(new LWWSet.ElementState<>(3, "ape")));
110 | assertTrue(resultAddSet.lookup().contains(new LWWSet.ElementState<>(1, "dog")));
111 | assertTrue(resultAddSet.lookup().contains(new LWWSet.ElementState<>(2, "tiger")));
112 |
113 | final GSet> resultRemoveSet = resultSet.getRemoveSet();
114 | assertEquals(1, resultRemoveSet.lookup().size());
115 | assertTrue(resultRemoveSet.lookup().contains(new LWWSet.ElementState<>(2, "cat")));
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/src/test/java/io/dmitryivanov/crdt/ORSetTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2016 Dmitry Ivanov
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package io.dmitryivanov.crdt;
26 |
27 | import org.junit.Test;
28 |
29 | import java.util.Set;
30 |
31 | import static org.junit.Assert.assertEquals;
32 | import static org.junit.Assert.assertTrue;
33 |
34 | public class ORSetTests {
35 |
36 | @Test
37 | public void testLookup() {
38 | final ORSet orSet = new ORSet<>();
39 |
40 | orSet.add(new ORSet.ElementState<>("#a", "dog"));
41 | orSet.add(new ORSet.ElementState<>("#b", "cat"));
42 | orSet.add(new ORSet.ElementState<>("#c", "ape"));
43 | orSet.add(new ORSet.ElementState<>("#c", "tiger"));
44 |
45 | orSet.remove(new ORSet.ElementState<>("#a", "dog"));
46 | orSet.remove(new ORSet.ElementState<>("#b", "cat"));
47 |
48 | // Actual test
49 | final Set lookup = orSet.lookup();
50 |
51 | assertEquals(2, lookup.size());
52 | assertTrue(lookup.contains("ape"));
53 | assertTrue(lookup.contains("tiger"));
54 | }
55 |
56 | @Test
57 | public void testMerge() {
58 | final ORSet firstORSet = new ORSet<>();
59 | firstORSet.add(new ORSet.ElementState<>("#b", "ape"));
60 | firstORSet.add(new ORSet.ElementState<>("#c", "dog"));
61 | firstORSet.add(new ORSet.ElementState<>("#d", "cat"));
62 | firstORSet.remove(new ORSet.ElementState<>("#d", "cat"));
63 |
64 | final ORSet secondORSet = new ORSet<>();
65 | secondORSet.add(new ORSet.ElementState<>("#a", "ape"));
66 | secondORSet.add(new ORSet.ElementState<>("#h", "tiger"));
67 | secondORSet.add(new ORSet.ElementState<>("#d", "cat"));
68 | secondORSet.remove(new ORSet.ElementState<>("#a", "ape"));
69 |
70 | // Actual test
71 | final ORSet resultSet = firstORSet.merge(secondORSet);
72 |
73 | final GSet> resultAddSet = resultSet.getAddSet();
74 | final Set> addLookup = resultAddSet.lookup();
75 | assertEquals(5, addLookup.size());
76 | assertTrue(addLookup.contains(new ORSet.ElementState<>("#a", "ape")));
77 | assertTrue(addLookup.contains(new ORSet.ElementState<>("#b", "ape")));
78 | assertTrue(addLookup.contains(new ORSet.ElementState<>("#c", "dog")));
79 | assertTrue(addLookup.contains(new ORSet.ElementState<>("#d", "cat")));
80 | assertTrue(addLookup.contains(new ORSet.ElementState<>("#h", "tiger")));
81 |
82 | final GSet> resultRemoveSet = resultSet.getRemoveSet();
83 | final Set> removeLookup = resultRemoveSet.lookup();
84 | assertEquals(2, removeLookup.size());
85 | assertTrue(removeLookup.contains(new ORSet.ElementState<>("#d", "cat")));
86 | assertTrue(removeLookup.contains(new ORSet.ElementState<>("#a", "ape")));
87 |
88 | ORSet reverseResultSet = secondORSet.merge(firstORSet);
89 | assertEquals(resultSet, reverseResultSet);
90 | }
91 |
92 | @Test
93 | public void testDiff() {
94 | final ORSet firstORSet = new ORSet<>();
95 | firstORSet.add(new ORSet.ElementState<>("#b", "ape"));
96 | firstORSet.add(new ORSet.ElementState<>("#c", "dog"));
97 | firstORSet.add(new ORSet.ElementState<>("#d", "cat"));
98 | firstORSet.remove(new ORSet.ElementState<>("#d", "cat"));
99 |
100 | final ORSet secondORSet = new ORSet<>();
101 | secondORSet.add(new ORSet.ElementState<>("#a", "ape"));
102 | secondORSet.add(new ORSet.ElementState<>("#h", "tiger"));
103 | secondORSet.add(new ORSet.ElementState<>("#d", "cat"));
104 | secondORSet.remove(new ORSet.ElementState<>("#a", "ape"));
105 |
106 | // Actual test
107 | final ORSet resultSet = firstORSet.diff(secondORSet);
108 |
109 | final GSet> resultAddSet = resultSet.getAddSet();
110 | assertEquals(2, resultAddSet.lookup().size());
111 | assertTrue(resultAddSet.lookup().contains(new ORSet.ElementState<>("#b", "ape")));
112 | assertTrue(resultAddSet.lookup().contains(new ORSet.ElementState<>("#c", "dog")));
113 |
114 | final GSet> resultRemoveSet = resultSet.getRemoveSet();
115 | assertEquals(1, resultRemoveSet.lookup().size());
116 | assertTrue(resultRemoveSet.lookup().contains(new ORSet.ElementState<>("#d", "cat")));
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/test/java/io/dmitryivanov/crdt/OURSetTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2016 Dmitry Ivanov
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package io.dmitryivanov.crdt;
26 |
27 | import org.junit.Test;
28 |
29 | import java.util.Set;
30 | import java.util.UUID;
31 |
32 | import static org.junit.Assert.assertEquals;
33 | import static org.junit.Assert.assertTrue;
34 |
35 | public class OURSetTests {
36 |
37 | @Test
38 | public void testLookup() {
39 | OURSet ourSet = new OURSet<>();
40 |
41 | final OURSet.ElementState ape = new OURSet.ElementState<>(UUID.randomUUID(), System.currentTimeMillis(), "ape");
42 | final OURSet.ElementState dog = new OURSet.ElementState<>(UUID.randomUUID(), System.currentTimeMillis(), "dog");
43 | final OURSet.ElementState cat = new OURSet.ElementState<>(UUID.randomUUID(), System.currentTimeMillis(), "cat");
44 |
45 | ourSet.add(ape);
46 | ourSet.add(dog);
47 | ourSet.add(cat);
48 |
49 | ourSet.remove(new OURSet.ElementState<>(UUID.randomUUID(), System.currentTimeMillis(), "tiger"));
50 | ourSet.remove(new OURSet.ElementState<>(cat.getId(), System.currentTimeMillis() + 1, cat.getElement()));
51 |
52 | // Actual test
53 | Set lookupResult = ourSet.lookup();
54 |
55 | assertEquals(lookupResult.size(), 2);
56 | assertTrue(lookupResult.contains("dog"));
57 | assertTrue(lookupResult.contains("ape"));
58 | }
59 |
60 | @Test
61 | public void testMerge() {
62 |
63 | final OURSet.ElementState ape = new OURSet.ElementState<>(UUID.randomUUID(), System.currentTimeMillis(), "ape");
64 | final OURSet.ElementState dog = new OURSet.ElementState<>(UUID.randomUUID(), System.currentTimeMillis(), "dog");
65 | final OURSet.ElementState cat = new OURSet.ElementState<>(UUID.randomUUID(), System.currentTimeMillis(), "cat");
66 | final OURSet.ElementState tiger = new OURSet.ElementState<>(UUID.randomUUID(), System.currentTimeMillis(), "tiger");
67 | final OURSet.ElementState removedCat = new OURSet.ElementState<>(cat.getId(), true, cat.getTimestamp() + 1, "cat");
68 |
69 | OURSet firstOURSet = new OURSet<>();
70 |
71 | firstOURSet.add(ape);
72 | firstOURSet.add(dog);
73 | firstOURSet.remove(removedCat);
74 |
75 | OURSet secondOURSet = new OURSet<>();
76 | secondOURSet.add(cat);
77 | secondOURSet.add(tiger);
78 |
79 | // Actual test
80 | OURSet mergeResult = firstOURSet.merge(secondOURSet);
81 |
82 | assertEquals(mergeResult.getElements().size(), 4);
83 | assertTrue(mergeResult.getElements().contains(ape));
84 | assertTrue(mergeResult.getElements().contains(dog));
85 | assertTrue(mergeResult.getElements().contains(tiger));
86 | assertTrue(mergeResult.getElements().contains(removedCat));
87 |
88 | OURSet reverseMergeResult = secondOURSet.merge(firstOURSet);
89 | assertEquals("'merge' should be symmetrical", mergeResult, reverseMergeResult);
90 | }
91 |
92 | @Test
93 | public void testDiff() {
94 | final OURSet.ElementState ape = new OURSet.ElementState<>(UUID.randomUUID(), System.currentTimeMillis(), "ape");
95 | final OURSet.ElementState dog = new OURSet.ElementState<>(UUID.randomUUID(), System.currentTimeMillis(), "dog");
96 | final OURSet.ElementState cat = new OURSet.ElementState<>(UUID.randomUUID(), System.currentTimeMillis(), "cat");
97 | final OURSet.ElementState tiger = new OURSet.ElementState<>(UUID.randomUUID(), System.currentTimeMillis(), "tiger");
98 | final OURSet.ElementState removedCat = new OURSet.ElementState<>(cat.getId(), true, cat.getTimestamp() + 1, "cat");
99 |
100 | OURSet firstOURSet = new OURSet<>();
101 |
102 | firstOURSet.add(ape);
103 | firstOURSet.add(dog);
104 | firstOURSet.remove(removedCat);
105 |
106 | OURSet secondOURSet = new OURSet<>();
107 | secondOURSet.add(dog);
108 | secondOURSet.add(cat);
109 | secondOURSet.add(tiger);
110 |
111 | // Actual test
112 | OURSet diffResult = firstOURSet.diff(secondOURSet);
113 |
114 | assertEquals(diffResult.getElements().size(), 2);
115 | assertTrue(diffResult.getElements().contains(ape));
116 | assertTrue(diffResult.getElements().contains(removedCat));
117 |
118 | // Reverse diff
119 | OURSet reverseDiffResult = secondOURSet.diff(firstOURSet);
120 |
121 | assertEquals(reverseDiffResult.getElements().size(), 1);
122 | assertTrue(reverseDiffResult.getElements().contains(tiger));
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/test/java/io/dmitryivanov/crdt/TwoPSetTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2016 Dmitry Ivanov
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package io.dmitryivanov.crdt;
26 |
27 | import java.util.Set;
28 |
29 | import org.junit.Test;
30 |
31 | import static org.junit.Assert.assertEquals;
32 | import static org.junit.Assert.assertTrue;
33 |
34 | public class TwoPSetTests {
35 |
36 | @Test
37 | public void testLookup() {
38 | final TwoPSet twoPSet = new TwoPSet<>();
39 |
40 | twoPSet.add("dog");
41 | twoPSet.add("cat");
42 | twoPSet.add("ape");
43 | twoPSet.add("tiger");
44 |
45 | twoPSet.remove("cat");
46 | twoPSet.remove("dog");
47 |
48 | // Actual test
49 | final Set lookup = twoPSet.lookup();
50 |
51 | assertEquals(2, lookup.size());
52 | assertTrue(lookup.contains("ape"));
53 | assertTrue(lookup.contains("tiger"));
54 | }
55 |
56 | @Test
57 | public void testMerge() {
58 | final TwoPSet firstTwoPSet = new TwoPSet<>();
59 | firstTwoPSet.add("ape");
60 | firstTwoPSet.add("dog");
61 | firstTwoPSet.add("cat");
62 | firstTwoPSet.remove("cat");
63 |
64 | final TwoPSet secondTwoPSet = new TwoPSet<>();
65 | secondTwoPSet.add("ape");
66 | secondTwoPSet.add("tiger");
67 | secondTwoPSet.add("cat");
68 | secondTwoPSet.remove("ape");
69 |
70 | // Actual test
71 | final TwoPSet resultSet = firstTwoPSet.merge(secondTwoPSet);
72 |
73 | final GSet resultAddSet = resultSet.getAddSet();
74 | final Set resultAddSetLookup = resultAddSet.lookup();
75 | assertEquals(4, resultAddSetLookup.size());
76 | assertTrue(resultAddSetLookup.contains("ape"));
77 | assertTrue(resultAddSetLookup.contains("dog"));
78 | assertTrue(resultAddSetLookup.contains("cat"));
79 | assertTrue(resultAddSetLookup.contains("tiger"));
80 |
81 | final GSet resultRemoveSet = resultSet.getRemoveSet();
82 | final Set resultRemoveSetLookup = resultRemoveSet.lookup();
83 | assertEquals(2, resultRemoveSetLookup.size());
84 | assertTrue(resultRemoveSetLookup.contains("cat"));
85 | assertTrue(resultRemoveSetLookup.contains("ape"));
86 |
87 | final TwoPSet reverseResult = secondTwoPSet.merge(firstTwoPSet);
88 | assertEquals(resultSet, reverseResult);
89 |
90 | final TwoPSet mergeItself = firstTwoPSet.merge(firstTwoPSet);
91 | assertEquals(firstTwoPSet, mergeItself);
92 | }
93 |
94 | @Test
95 | public void testDiff() {
96 | final TwoPSet firstTwoPSet = new TwoPSet<>();
97 | firstTwoPSet.add("ape");
98 | firstTwoPSet.add("dog");
99 | firstTwoPSet.add("cat");
100 | firstTwoPSet.remove("cat");
101 |
102 | final TwoPSet secondTwoPSet = new TwoPSet<>();
103 | secondTwoPSet.add("ape");
104 | secondTwoPSet.add("tiger");
105 | secondTwoPSet.add("cat");
106 | secondTwoPSet.remove("ape");
107 |
108 | // Actual test
109 | final TwoPSet resultSet = firstTwoPSet.diff(secondTwoPSet);
110 |
111 | final GSet resultAddSet = resultSet.getAddSet();
112 | assertEquals(1, resultAddSet.lookup().size());
113 | assertTrue(resultAddSet.lookup().contains("dog"));
114 |
115 | final GSet resultRemoveSet = resultSet.getRemoveSet();
116 | assertEquals(1, resultRemoveSet.lookup().size());
117 | assertTrue(resultRemoveSet.lookup().contains("cat"));
118 |
119 | // Reverse diff
120 | final TwoPSet resultSet2 = secondTwoPSet.diff(firstTwoPSet);
121 |
122 | final GSet resultAddSet2 = resultSet2.getAddSet();
123 | assertEquals(1, resultAddSet2.lookup().size());
124 | assertTrue(resultAddSet2.lookup().contains("tiger"));
125 |
126 | final GSet resultRemoveSet2 = resultSet2.getRemoveSet();
127 | assertEquals(1, resultRemoveSet2.lookup().size());
128 | assertTrue(resultRemoveSet2.lookup().contains("ape"));
129 | }
130 | }
131 |
--------------------------------------------------------------------------------