diff options
author | Kristóf Marussy <kristof@marussy.com> | 2022-12-14 00:57:24 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2022-12-21 18:34:11 +0100 |
commit | bfc9e33a54985797968708176690a9ecfc207f83 (patch) | |
tree | 600b4508eb1289c4e30a4f6e0aecfb9d5d56cefd | |
parent | chore(deps): bump dependencies (diff) | |
download | refinery-bfc9e33a54985797968708176690a9ecfc207f83.tar.gz refinery-bfc9e33a54985797968708176690a9ecfc207f83.tar.zst refinery-bfc9e33a54985797968708176690a9ecfc207f83.zip |
refactor(store): compare VersionedMap instances
The Java hashCode and equals API is inappropriate here, because an
AnyVersionedMap is mutable. Added new methods to hash and compare
AnyVersionedMap instances by their contents and marked the built-in Java
methods as deprecated.
6 files changed, 135 insertions, 58 deletions
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java b/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java index b94b9f38..f82a8bb1 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java | |||
@@ -2,4 +2,39 @@ package tools.refinery.store.map; | |||
2 | 2 | ||
3 | public sealed interface AnyVersionedMap extends Versioned permits VersionedMap { | 3 | public sealed interface AnyVersionedMap extends Versioned permits VersionedMap { |
4 | long getSize(); | 4 | long getSize(); |
5 | |||
6 | int contentHashCode(ContentHashCode mode); | ||
7 | |||
8 | boolean contentEquals(AnyVersionedMap other); | ||
9 | |||
10 | /** | ||
11 | * Returns a hash code value for the object. | ||
12 | * | ||
13 | * @return A hash code value for this object. | ||
14 | * @deprecated {@link AnyVersionedMap} instances are mutable, and it is inappropriate to use them as keys in | ||
15 | * hash-based collections. Use {@link AnyVersionedMap#contentHashCode(ContentHashCode)} to compute a | ||
16 | * <code>hashCode</code> for a {@link AnyVersionedMap} instance according to its contents. | ||
17 | */ | ||
18 | @Override | ||
19 | // This method is mark as @Deprecated to prevent inappropriate use of built-in Java API. | ||
20 | // Therefore, we don't follow normal procedures for removing deprecated code. | ||
21 | @SuppressWarnings("squid:S1133") | ||
22 | @Deprecated(since = "0.0.0") | ||
23 | int hashCode(); | ||
24 | |||
25 | /** | ||
26 | * Compares two objects by reference. | ||
27 | * | ||
28 | * @param obj The reference object with which to compare. | ||
29 | * @return <code>true</code> if this object is the same as the <code>obj</code> argument. | ||
30 | * @deprecated {@link AnyVersionedMap} instances are mutable, and it is inappropriate to use them as keys in | ||
31 | * hash-based collections. Use {@link AnyVersionedMap#contentEquals(AnyVersionedMap)} to compare two | ||
32 | * {@link AnyVersionedMap} instances by their contents. | ||
33 | */ | ||
34 | @Override | ||
35 | // This method is mark as @Deprecated to prevent inappropriate use of built-in Java API. | ||
36 | // Therefore, we don't follow normal procedures for removing deprecated code. | ||
37 | @SuppressWarnings("squid:S1133") | ||
38 | @Deprecated(since = "0.0.0") | ||
39 | boolean equals(Object obj); | ||
5 | } | 40 | } |
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/ContentHashCode.java b/subprojects/store/src/main/java/tools/refinery/store/map/ContentHashCode.java new file mode 100644 index 00000000..8deeab23 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/ContentHashCode.java | |||
@@ -0,0 +1,19 @@ | |||
1 | package tools.refinery.store.map; | ||
2 | |||
3 | public enum ContentHashCode { | ||
4 | /** | ||
5 | * Calculate the <code>hashCode</code> of the contents of this {@link AnyVersionedMap} to reduce hash collisions as | ||
6 | * much as possible, even iterating over the full contents in necessary. | ||
7 | */ | ||
8 | PRECISE_SLOW, | ||
9 | |||
10 | /** | ||
11 | * Compute an approximate <code>hashCode</code> of the contents of this {@link AnyVersionedMap} that may have a | ||
12 | * large number of hash collisions, but can be calculated without iterating over the full contents. | ||
13 | * <p> | ||
14 | * In the extreme case, {@link AnyVersionedMap#contentHashCode(ContentHashCode)} may return the same | ||
15 | * <code>hashCode</code> irrespectively of the actual contents of the {@link AnyVersionedMap}. | ||
16 | * </p> | ||
17 | */ | ||
18 | APPROXIMATE_FAST | ||
19 | } | ||
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java index 1698830f..91a71e3d 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java | |||
@@ -1,6 +1,7 @@ | |||
1 | package tools.refinery.store.map.internal; | 1 | package tools.refinery.store.map.internal; |
2 | 2 | ||
3 | import tools.refinery.store.map.AnyVersionedMap; | 3 | import tools.refinery.store.map.AnyVersionedMap; |
4 | import tools.refinery.store.map.ContentHashCode; | ||
4 | import tools.refinery.store.map.Cursor; | 5 | import tools.refinery.store.map.Cursor; |
5 | import tools.refinery.store.map.VersionedMap; | 6 | import tools.refinery.store.map.VersionedMap; |
6 | 7 | ||
@@ -45,7 +46,7 @@ public class MapCursor<K, V> implements Cursor<K, V> { | |||
45 | 46 | ||
46 | // Initializing state | 47 | // Initializing state |
47 | this.map = map; | 48 | this.map = map; |
48 | this.creationHash = map.hashCode(); | 49 | this.creationHash = map.contentHashCode(ContentHashCode.APPROXIMATE_FAST); |
49 | } | 50 | } |
50 | 51 | ||
51 | public K getKey() { | 52 | public K getKey() { |
@@ -87,7 +88,7 @@ public class MapCursor<K, V> implements Cursor<K, V> { | |||
87 | 88 | ||
88 | @Override | 89 | @Override |
89 | public boolean isDirty() { | 90 | public boolean isDirty() { |
90 | return this.map.hashCode() != this.creationHash; | 91 | return this.map.contentHashCode(ContentHashCode.APPROXIMATE_FAST) != this.creationHash; |
91 | } | 92 | } |
92 | 93 | ||
93 | @Override | 94 | @Override |
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java index 866e7b33..301bcb95 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java | |||
@@ -5,6 +5,7 @@ import tools.refinery.store.map.*; | |||
5 | import java.util.Iterator; | 5 | import java.util.Iterator; |
6 | import java.util.LinkedList; | 6 | import java.util.LinkedList; |
7 | import java.util.List; | 7 | import java.util.List; |
8 | import java.util.Objects; | ||
8 | 9 | ||
9 | /** | 10 | /** |
10 | * Not threadSafe in itself | 11 | * Not threadSafe in itself |
@@ -145,4 +146,15 @@ public class VersionedMapImpl<K, V> implements VersionedMap<K, V> { | |||
145 | this.root.checkIntegrity(hashProvider, defaultValue, 0); | 146 | this.root.checkIntegrity(hashProvider, defaultValue, 0); |
146 | } | 147 | } |
147 | } | 148 | } |
149 | |||
150 | @Override | ||
151 | public int contentHashCode(ContentHashCode mode) { | ||
152 | // Calculating the root hashCode is always fast, because {@link Node} caches its hashCode. | ||
153 | return Objects.hashCode(root); | ||
154 | } | ||
155 | |||
156 | @Override | ||
157 | public boolean contentEquals(AnyVersionedMap other) { | ||
158 | return other instanceof VersionedMapImpl<?, ?> otherImpl && Objects.equals(root, otherImpl.root); | ||
159 | } | ||
148 | } | 160 | } |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java index d7f77d1a..93ecfec3 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java | |||
@@ -17,12 +17,11 @@ import java.util.List; | |||
17 | import java.util.Random; | 17 | import java.util.Random; |
18 | import java.util.stream.Stream; | 18 | import java.util.stream.Stream; |
19 | 19 | ||
20 | import static org.junit.jupiter.api.Assertions.assertEquals; | 20 | import static org.junit.jupiter.api.Assertions.*; |
21 | import static org.junit.jupiter.api.Assertions.fail; | ||
22 | 21 | ||
23 | class ContentEqualsFuzzTest { | 22 | class ContentEqualsFuzzTest { |
24 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | 23 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, |
25 | boolean evilHash) { | 24 | boolean evilHash) { |
26 | String[] values = MapTestEnvironment.prepareValues(maxValue); | 25 | String[] values = MapTestEnvironment.prepareValues(maxValue); |
27 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | 26 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); |
28 | 27 | ||
@@ -31,7 +30,9 @@ class ContentEqualsFuzzTest { | |||
31 | iterativeRandomPutsAndCommitsThenCompare(scenario, chp, steps, maxKey, values, r, commitFrequency); | 30 | iterativeRandomPutsAndCommitsThenCompare(scenario, chp, steps, maxKey, values, r, commitFrequency); |
32 | } | 31 | } |
33 | 32 | ||
34 | private void iterativeRandomPutsAndCommitsThenCompare(String scenario, ContinousHashProvider<Integer> chp, int steps, int maxKey, String[] values, Random r, int commitFrequency) { | 33 | private void iterativeRandomPutsAndCommitsThenCompare(String scenario, ContinousHashProvider<Integer> chp, |
34 | int steps, int maxKey, String[] values, Random r, | ||
35 | int commitFrequency) { | ||
35 | VersionedMapStore<Integer, String> store1 = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | 36 | VersionedMapStore<Integer, String> store1 = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); |
36 | VersionedMap<Integer, String> sut1 = store1.createMap(); | 37 | VersionedMap<Integer, String> sut1 = store1.createMap(); |
37 | 38 | ||
@@ -67,58 +68,43 @@ class ContentEqualsFuzzTest { | |||
67 | int index2 = 1; | 68 | int index2 = 1; |
68 | for (SimpleEntry<Integer, String> entry : content) { | 69 | for (SimpleEntry<Integer, String> entry : content) { |
69 | sut2.put(entry.getKey(), entry.getValue()); | 70 | sut2.put(entry.getKey(), entry.getValue()); |
70 | if(index2++%commitFrequency == 0) | 71 | if (index2++ % commitFrequency == 0) |
71 | sut2.commit(); | 72 | sut2.commit(); |
72 | } | 73 | } |
73 | 74 | ||
74 | // Check the integrity of the maps | 75 | // Check the integrity of the maps |
75 | ((VersionedMapImpl<Integer,String>) sut1).checkIntegrity(); | 76 | ((VersionedMapImpl<Integer, String>) sut1).checkIntegrity(); |
76 | ((VersionedMapImpl<Integer,String>) sut2).checkIntegrity(); | 77 | ((VersionedMapImpl<Integer, String>) sut2).checkIntegrity(); |
77 | 78 | ||
78 | // // Compare the two maps | 79 | // Compare the two maps |
79 | // By size | 80 | MapTestEnvironment.compareTwoMaps(scenario, sut1, sut2); |
80 | assertEquals(sut1.getSize(), content.size()); | ||
81 | assertEquals(sut2.getSize(), content.size()); | ||
82 | |||
83 | // By cursors | ||
84 | Cursor<Integer, String> cursor1 = sut1.getAll(); | ||
85 | Cursor<Integer, String> cursor2 = sut2.getAll(); | ||
86 | int index3 = 1; | ||
87 | boolean canMove = true; | ||
88 | do{ | ||
89 | boolean canMove1 = cursor1.move(); | ||
90 | boolean canMove2 = cursor2.move(); | ||
91 | assertEquals(canMove1, canMove2, scenario + ":" + index3 +" Cursors stopped at different times!"); | ||
92 | assertEquals(cursor1.getKey(), cursor2.getKey(), scenario + ":" + index3 +" Cursors have different keys!"); | ||
93 | assertEquals(cursor1.getValue(), cursor2.getValue(), scenario + ":" + index3 +" Cursors have different values!"); | ||
94 | |||
95 | canMove = canMove1; | ||
96 | MapTestEnvironment.printStatus(scenario, index3++, content.size(), "Compare"); | ||
97 | } while (canMove); | ||
98 | } | 81 | } |
99 | 82 | ||
100 | @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 83 | @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} " + |
84 | "evil-hash={6}") | ||
101 | @MethodSource | 85 | @MethodSource |
102 | @Timeout(value = 10) | 86 | @Timeout(value = 10) |
103 | @Tag("fuzz") | 87 | @Tag("fuzz") |
104 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 88 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, |
105 | boolean evilHash) { | 89 | boolean evilHash) { |
106 | runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | 90 | runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, |
107 | commitFrequency, evilHash); | 91 | commitFrequency, evilHash); |
108 | } | 92 | } |
109 | 93 | ||
110 | static Stream<Arguments> parametrizedFastFuzz() { | 94 | static Stream<Arguments> parametrizedFastFuzz() { |
111 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | 95 | return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, |
112 | new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, | 96 | 32 * 32}, |
113 | new Object[] { false, true }); | 97 | new Object[]{2, 3}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, |
98 | new Object[]{false, true}); | ||
114 | } | 99 | } |
115 | 100 | ||
116 | @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 101 | @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} " + |
102 | "evil-hash={6}") | ||
117 | @MethodSource | 103 | @MethodSource |
118 | @Tag("fuzz") | 104 | @Tag("fuzz") |
119 | @Tag("slow") | 105 | @Tag("slow") |
120 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 106 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, |
121 | boolean evilHash) { | 107 | boolean evilHash) { |
122 | runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | 108 | runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, |
123 | commitFrequency, evilHash); | 109 | commitFrequency, evilHash); |
124 | } | 110 | } |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java index b73f8b32..2d03ebaf 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java | |||
@@ -1,8 +1,6 @@ | |||
1 | package tools.refinery.store.map.tests.utils; | 1 | package tools.refinery.store.map.tests.utils; |
2 | 2 | ||
3 | import tools.refinery.store.map.ContinousHashProvider; | 3 | import tools.refinery.store.map.*; |
4 | import tools.refinery.store.map.Cursor; | ||
5 | import tools.refinery.store.map.VersionedMap; | ||
6 | import tools.refinery.store.map.internal.VersionedMapImpl; | 4 | import tools.refinery.store.map.internal.VersionedMapImpl; |
7 | 5 | ||
8 | import java.util.*; | 6 | import java.util.*; |
@@ -50,40 +48,65 @@ public class MapTestEnvironment<K, V> { | |||
50 | 48 | ||
51 | } | 49 | } |
52 | 50 | ||
53 | public static <K, V> void compareTwoMaps(String title, VersionedMapImpl<K, V> map1, | 51 | public static <K, V> void compareTwoMaps(String title, VersionedMap<K, V> map1, |
54 | VersionedMapImpl<K, V> map2) { | 52 | VersionedMap<K, V> map2) { |
55 | compareTwoMaps(title, map1, map2, null); | 53 | compareTwoMaps(title, map1, map2, null); |
56 | } | 54 | } |
57 | public static <K, V> void compareTwoMaps(String title, VersionedMapImpl<K, V> map1, | 55 | |
58 | VersionedMapImpl<K, V> map2, List<Throwable> errors) { | 56 | public static <K, V> void compareTwoMaps(String title, VersionedMap<K, V> map1, |
57 | VersionedMap<K, V> map2, List<Throwable> errors) { | ||
58 | assertEqualsList(map1.getSize(), map2.getSize(), title + ": Sizes not equal", errors); | ||
59 | |||
59 | Cursor<K, V> cursor1 = map1.getAll(); | 60 | Cursor<K, V> cursor1 = map1.getAll(); |
60 | Cursor<K, V> cursor2 = map2.getAll(); | 61 | Cursor<K, V> cursor2 = map2.getAll(); |
61 | while (!cursor1.isTerminated()) { | 62 | while (!cursor1.isTerminated()) { |
62 | if (cursor2.isTerminated()) { | 63 | if (cursor2.isTerminated()) { |
63 | fail("cursor 2 terminated before cursor1"); | 64 | fail("cursor 2 terminated before cursor1"); |
64 | } | 65 | } |
65 | assertEqualsList(cursor1.getKey(), cursor2.getKey(),"Keys not equal", errors); | 66 | assertEqualsList(cursor1.getKey(), cursor2.getKey(), title + ": Keys not equal", errors); |
66 | assertEqualsList(cursor2.getValue(), cursor2.getValue(), "Values not equal", errors); | 67 | assertEqualsList(cursor2.getValue(), cursor2.getValue(), title + ": Values not equal", errors); |
67 | cursor1.move(); | 68 | cursor1.move(); |
68 | cursor2.move(); | 69 | cursor2.move(); |
69 | } | 70 | } |
70 | if (!cursor2.isTerminated()) | 71 | if (!cursor2.isTerminated()) { |
71 | fail("cursor 1 terminated before cursor 2"); | 72 | fail("cursor 1 terminated before cursor 2"); |
73 | } | ||
74 | |||
75 | for (var mode : ContentHashCode.values()) { | ||
76 | assertEqualsList(map1.contentHashCode(mode), map2.contentHashCode(mode), | ||
77 | title + ": " + mode + " hashCode check", errors); | ||
78 | } | ||
79 | assertContentEqualsList(map1, map2, title + ": map1.contentEquals(map2)", errors); | ||
80 | assertContentEqualsList(map2, map1, title + ": map2.contentEquals(map1)", errors); | ||
72 | } | 81 | } |
73 | 82 | ||
74 | private static void assertEqualsList(Object o1, Object o2, String message, List<Throwable> errors) { | 83 | private static void assertEqualsList(Object o1, Object o2, String message, List<Throwable> errors) { |
75 | if(errors == null) { | 84 | if (errors == null) { |
76 | assertEquals(o1, o2, message); | 85 | assertEquals(o1, o2, message); |
77 | } else { | 86 | } else { |
78 | if(o1 != null) { | 87 | if (o1 != null) { |
79 | if(!(o1.equals(o2))) { | 88 | if (!(o1.equals(o2))) { |
80 | AssertionError error = new AssertionError((message != null ? message+" " : "") + "expected: " + o1 + " but was : " + o2); | 89 | AssertionError error = |
90 | new AssertionError((message != null ? message + " " : "") + "expected: " + o1 + " but was " + | ||
91 | ": " + o2); | ||
81 | errors.add(error); | 92 | errors.add(error); |
82 | } | 93 | } |
83 | } | 94 | } |
84 | } | 95 | } |
85 | } | 96 | } |
86 | 97 | ||
98 | private static void assertContentEqualsList(AnyVersionedMap o1, AnyVersionedMap o2, String message, | ||
99 | List<Throwable> errors) { | ||
100 | boolean result = o1.contentEquals(o2); | ||
101 | if (errors == null) { | ||
102 | assertTrue(result, message); | ||
103 | } else if (!result) { | ||
104 | AssertionError error = | ||
105 | new AssertionError((message != null ? message + " " : "") + "expected: true but was: false"); | ||
106 | errors.add(error); | ||
107 | } | ||
108 | } | ||
109 | |||
87 | public VersionedMapImpl<K, V> sut; | 110 | public VersionedMapImpl<K, V> sut; |
88 | Map<K, V> oracle = new HashMap<K, V>(); | 111 | Map<K, V> oracle = new HashMap<K, V>(); |
89 | 112 | ||
@@ -99,10 +122,10 @@ public class MapTestEnvironment<K, V> { | |||
99 | } else { | 122 | } else { |
100 | oldOracleValue = oracle.remove(key); | 123 | oldOracleValue = oracle.remove(key); |
101 | } | 124 | } |
102 | if(oldSutValue == sut.getDefaultValue() && oldOracleValue != null) { | 125 | if (oldSutValue == sut.getDefaultValue() && oldOracleValue != null) { |
103 | fail("After put, SUT old nodeId was default, but oracle old value was " + oldOracleValue); | 126 | fail("After put, SUT old nodeId was default, but oracle old value was " + oldOracleValue); |
104 | } | 127 | } |
105 | if(oldSutValue != sut.getDefaultValue()) { | 128 | if (oldSutValue != sut.getDefaultValue()) { |
106 | assertEquals(oldOracleValue, oldSutValue); | 129 | assertEquals(oldOracleValue, oldSutValue); |
107 | } | 130 | } |
108 | } | 131 | } |
@@ -158,14 +181,15 @@ public class MapTestEnvironment<K, V> { | |||
158 | } | 181 | } |
159 | } | 182 | } |
160 | 183 | ||
161 | public static <K,V> void checkOrder(String scenario, VersionedMap<K,V> versionedMap) { | 184 | public static <K, V> void checkOrder(String scenario, VersionedMap<K, V> versionedMap) { |
162 | K previous = null; | 185 | K previous = null; |
163 | Cursor<K, V> cursor = versionedMap.getAll(); | 186 | Cursor<K, V> cursor = versionedMap.getAll(); |
164 | while(cursor.move()) { | 187 | while (cursor.move()) { |
165 | System.out.println(cursor.getKey() + " " + ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().getHash(cursor.getKey(), 0)); | 188 | System.out.println(cursor.getKey() + " " + ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().getHash(cursor.getKey(), 0)); |
166 | if(previous != null) { | 189 | if (previous != null) { |
167 | int comparisonResult = ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().compare(previous, cursor.getKey()); | 190 | int comparisonResult = ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().compare(previous, |
168 | assertTrue(comparisonResult<0,scenario+" Cursor order is not incremental!"); | 191 | cursor.getKey()); |
192 | assertTrue(comparisonResult < 0, scenario + " Cursor order is not incremental!"); | ||
169 | } | 193 | } |
170 | previous = cursor.getKey(); | 194 | previous = cursor.getKey(); |
171 | } | 195 | } |