aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store/src/test
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-09-05 20:33:31 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-09-05 20:33:31 +0200
commite5f14a3e9d92194c3f972f90a2f78c9c3dacaef4 (patch)
treeff1ebefb45348be48a23a89fa12b4817bc52bf51 /subprojects/store/src/test
parentfeat(web): control server settings with env vars (diff)
parentrestructured DSE framework, failing build (diff)
downloadrefinery-e5f14a3e9d92194c3f972f90a2f78c9c3dacaef4.tar.gz
refinery-e5f14a3e9d92194c3f972f90a2f78c9c3dacaef4.tar.zst
refinery-e5f14a3e9d92194c3f972f90a2f78c9c3dacaef4.zip
Merge remote-tracking branch 'OszkarSemerath/datastructure' into partial-interpretation
Diffstat (limited to 'subprojects/store/src/test')
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java56
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java75
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java70
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java57
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java161
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java91
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java58
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java60
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java50
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java66
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java72
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java66
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java53
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java12
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java19
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java84
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java13
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java217
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/statecoding/ExperimentalSetupTest.java199
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java171
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderUnitTest.java195
22 files changed, 1449 insertions, 401 deletions
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java
new file mode 100644
index 00000000..98756460
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java
@@ -0,0 +1,56 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.map.tests;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.map.VersionedMapStore;
10import tools.refinery.store.map.VersionedMapStoreFactoryBuilder;
11import tools.refinery.store.map.internal.state.InOrderMapCursor;
12import tools.refinery.store.map.internal.state.VersionedMapStateImpl;
13import tools.refinery.store.map.tests.utils.MapTestEnvironment;
14
15import static org.junit.jupiter.api.Assertions.*;
16
17class InOrderCursorTest {
18 @Test
19 void testCursor() {
20 var store = VersionedMapStore.<Integer,String>builder()
21 .strategy(VersionedMapStoreFactoryBuilder.StoreStrategy.STATE)
22 .stateBasedImmutableWhenCommitting(true)
23 .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false))
24 .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE)
25 .defaultValue("x")
26 .build()
27 .createOne();
28
29 VersionedMapStateImpl<Integer,String> map = (VersionedMapStateImpl<Integer,String>) store.createMap();
30 checkMove(map,0);
31
32 map.put(1,"A");
33 map.commit();
34 checkMove(map,1);
35
36
37 map.put(2,"B");
38 map.commit();
39 checkMove(map,2);
40
41 map.put(3,"C");
42 map.commit();
43 checkMove(map,3);
44
45 }
46
47 private void checkMove(VersionedMapStateImpl<Integer,String> map, int num) {
48 InOrderMapCursor<Integer,String> cursor = new InOrderMapCursor<>(map);
49 for(int i=0; i<num; i++) {
50 assertTrue(cursor.move());
51 assertFalse(cursor.isTerminated());
52 }
53 assertFalse(cursor.move());
54 assertTrue(cursor.isTerminated());
55 }
56}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java
index 153f2e78..cc2e425c 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java
@@ -7,7 +7,7 @@ package tools.refinery.store.map.tests;
7 7
8import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
9import tools.refinery.store.map.VersionedMapStore; 9import tools.refinery.store.map.VersionedMapStore;
10import tools.refinery.store.map.VersionedMapStoreImpl; 10import tools.refinery.store.map.internal.state.VersionedMapStoreStateImpl;
11import tools.refinery.store.model.TupleHashProvider; 11import tools.refinery.store.model.TupleHashProvider;
12import tools.refinery.store.tuple.Tuple; 12import tools.refinery.store.tuple.Tuple;
13 13
@@ -16,11 +16,82 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
16class MapUnitTests { 16class MapUnitTests {
17 @Test 17 @Test
18 void defaultTest() { 18 void defaultTest() {
19 VersionedMapStore<Tuple, Boolean> store = new VersionedMapStoreImpl<>(TupleHashProvider.INSTANCE, false); 19 VersionedMapStore<Tuple, Boolean> store = new VersionedMapStoreStateImpl<>(TupleHashProvider.INSTANCE, false);
20 var map = store.createMap(); 20 var map = store.createMap();
21 var out1 = map.put(Tuple.of(0), true); 21 var out1 = map.put(Tuple.of(0), true);
22 assertEquals(false, out1); 22 assertEquals(false, out1);
23 var out2 = map.put(Tuple.of(1), true); 23 var out2 = map.put(Tuple.of(1), true);
24 assertEquals(false, out2); 24 assertEquals(false, out2);
25 } 25 }
26
27 @Test
28 void deltaRestoreTest() {
29 VersionedMapStore<Integer,String> store =
30 VersionedMapStore.<Integer,String>builder().defaultValue("x").build().createOne();
31 var map = store.createMap();
32 map.put(1,"val");
33 var version1 = map.commit();
34 map.put(1,"x");
35 map.restore(version1);
36 System.out.println(map.getSize());
37 assertEquals(1,map.getSize());
38 }
39
40 @Test
41 void deltaRestoreTest2() {
42 VersionedMapStore<Integer,String> store =
43 VersionedMapStore.<Integer,String>builder().defaultValue("x").build().createOne();
44 var map = store.createMap();
45 map.put(1,"x");
46 var version1 = map.commit();
47 map.put(1,"1");
48 map.restore(version1);
49 System.out.println(map.getSize());
50 assertEquals(0,map.getSize());
51 }
52 @Test
53 void deltaRestoreTest3() {
54 VersionedMapStore<Integer,String> store =
55 VersionedMapStore.<Integer,String>builder().defaultValue("x").build().createOne();
56 var map = store.createMap();
57 map.commit();
58 map.put(1,"1");
59 map.put(2,"x");
60 assertEquals(1,map.getSize());
61 var version1 = map.commit();
62 map.put(1,"x");
63 assertEquals(0,map.getSize());
64 map.put(2,"2");
65 assertEquals(1,map.getSize());
66 map.put(2,"x");
67 assertEquals(0,map.getSize());
68 var version2 = map.commit();
69 map.restore(version1);
70 assertEquals(1,map.getSize());
71 map.restore(version2);
72 assertEquals(0,map.getSize());
73 }
74
75 @Test
76 void deltaRestoreTest4() {
77 VersionedMapStore<Integer,String> store =
78 VersionedMapStore.<Integer,String>builder().defaultValue("x").build().createOne();
79 var map = store.createMap();
80 map.commit();
81 map.put(1,"1");
82 map.put(2,"x");
83 assertEquals(1,map.getSize());
84 var version1 = map.commit();
85 map.put(1,"x");
86 assertEquals(0,map.getSize());
87 map.put(2,"2");
88 assertEquals(1,map.getSize());
89 map.put(2,"x");
90 assertEquals(0,map.getSize());
91 var version2 = map.commit();
92 map.restore(version1);
93 assertEquals(1,map.getSize());
94 map.restore(version2);
95 assertEquals(0,map.getSize());
96 }
26} 97}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java
index eabe5bd1..58206eda 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java
@@ -5,33 +5,32 @@
5 */ 5 */
6package tools.refinery.store.map.tests.fuzz; 6package tools.refinery.store.map.tests.fuzz;
7 7
8import static org.junit.jupiter.api.Assertions.fail;
9
10import java.util.Random;
11import java.util.stream.Stream;
12
13import org.junit.jupiter.api.Tag; 8import org.junit.jupiter.api.Tag;
14import org.junit.jupiter.api.Timeout; 9import org.junit.jupiter.api.Timeout;
15import org.junit.jupiter.params.ParameterizedTest; 10import org.junit.jupiter.params.ParameterizedTest;
16import org.junit.jupiter.params.provider.Arguments; 11import org.junit.jupiter.params.provider.Arguments;
17import org.junit.jupiter.params.provider.MethodSource; 12import org.junit.jupiter.params.provider.MethodSource;
18
19import tools.refinery.store.map.ContinousHashProvider;
20import tools.refinery.store.map.VersionedMapStore; 13import tools.refinery.store.map.VersionedMapStore;
21import tools.refinery.store.map.VersionedMapStoreImpl; 14import tools.refinery.store.map.VersionedMapStoreFactoryBuilder;
22import tools.refinery.store.map.internal.VersionedMapImpl;
23import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; 15import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
24import tools.refinery.store.map.tests.utils.MapTestEnvironment; 16import tools.refinery.store.map.tests.utils.MapTestEnvironment;
25 17
18import java.util.Random;
19import java.util.stream.Stream;
20
21import static org.junit.jupiter.api.Assertions.fail;
22import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*;
23
26class CommitFuzzTest { 24class CommitFuzzTest {
27 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency,
28 boolean evilHash) {
29 String[] values = MapTestEnvironment.prepareValues(maxValue);
30 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash);
31 25
32 VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); 26 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue,
33 VersionedMapImpl<Integer, String> sut = (VersionedMapImpl<Integer, String>) store.createMap(); 27 boolean nullDefault, int commitFrequency,
34 MapTestEnvironment<Integer, String> e = new MapTestEnvironment<Integer, String>(sut); 28 VersionedMapStoreFactoryBuilder<Integer, String> builder) {
29 String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault);
30
31 VersionedMapStore<Integer, String> store = builder.defaultValue(values[0]).build().createOne();
32 var sut = store.createMap();
33 MapTestEnvironment<Integer, String> e = new MapTestEnvironment<>(sut);
35 34
36 Random r = new Random(seed); 35 Random r = new Random(seed);
37 36
@@ -39,24 +38,13 @@ class CommitFuzzTest {
39 } 38 }
40 39
41 private void iterativeRandomPutsAndCommits(String scenario, int steps, int maxKey, String[] values, 40 private void iterativeRandomPutsAndCommits(String scenario, int steps, int maxKey, String[] values,
42 MapTestEnvironment<Integer, String> e, Random r, int commitFrequency) { 41 MapTestEnvironment<Integer, String> e, Random r, int commitFrequency) {
43 int stopAt = -1;
44 for (int i = 0; i < steps; i++) { 42 for (int i = 0; i < steps; i++) {
45 int index = i + 1; 43 int index = i + 1;
46 int nextKey = r.nextInt(maxKey); 44 int nextKey = r.nextInt(maxKey);
47 String nextValue = values[r.nextInt(values.length)]; 45 String nextValue = values[r.nextInt(values.length)];
48 if (index == stopAt) {
49 System.out.println("issue!");
50 System.out.println("State before:");
51 e.printComparison();
52 e.sut.prettyPrint();
53 System.out.println("Next: put(" + nextKey + "," + nextValue + ")");
54 }
55 try { 46 try {
56 e.put(nextKey, nextValue); 47 e.put(nextKey, nextValue);
57 if (index == stopAt) {
58 e.sut.prettyPrint();
59 }
60 e.checkEquivalence(scenario + ":" + index); 48 e.checkEquivalence(scenario + ":" + index);
61 } catch (Exception exception) { 49 } catch (Exception exception) {
62 exception.printStackTrace(); 50 exception.printStackTrace();
@@ -64,35 +52,37 @@ class CommitFuzzTest {
64 } 52 }
65 MapTestEnvironment.printStatus(scenario, index, steps, null); 53 MapTestEnvironment.printStatus(scenario, index, steps, null);
66 if (index % commitFrequency == 0) { 54 if (index % commitFrequency == 0) {
67 e.sut.commit(); 55 e.commit();
68 } 56 }
69 } 57 }
70 } 58 }
71 59
72 @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") 60 public static final String title = "Commit {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5} " +
61 "seed={6} config={7}";
62
63 @ParameterizedTest(name = title)
73 @MethodSource 64 @MethodSource
74 @Timeout(value = 10) 65 @Timeout(value = 10)
75 @Tag("fuzz") 66 @Tag("fuzz")
76 void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, 67 void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency,
77 boolean evilHash) { 68 int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) {
78 runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, 69 runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
79 commitFrequency, evilHash); 70 nullDefault, commitFrequency, builder);
80 } 71 }
81 72
82 static Stream<Arguments> parametrizedFastFuzz() { 73 static Stream<Arguments> parametrizedFastFuzz() {
83 return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, 74 return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions,
84 new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, 75 commitFrequencyOptions, randomSeedOptions, storeConfigs);
85 new Object[] { false, true });
86 } 76 }
87 77
88 @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") 78 @ParameterizedTest(name = title)
89 @MethodSource 79 @MethodSource
90 @Tag("fuzz") 80 @Tag("fuzz")
91 @Tag("slow") 81 @Tag("slow")
92 void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, 82 void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency,
93 boolean evilHash) { 83 int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) {
94 runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, 84 runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
95 commitFrequency, evilHash); 85 nullDefault, commitFrequency, builder);
96 } 86 }
97 87
98 static Stream<Arguments> parametrizedSlowFuzz() { 88 static Stream<Arguments> parametrizedSlowFuzz() {
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 b0502a2b..c49911b8 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
@@ -10,8 +10,10 @@ import org.junit.jupiter.api.Timeout;
10import org.junit.jupiter.params.ParameterizedTest; 10import org.junit.jupiter.params.ParameterizedTest;
11import org.junit.jupiter.params.provider.Arguments; 11import org.junit.jupiter.params.provider.Arguments;
12import org.junit.jupiter.params.provider.MethodSource; 12import org.junit.jupiter.params.provider.MethodSource;
13import tools.refinery.store.map.*; 13import tools.refinery.store.map.Cursor;
14import tools.refinery.store.map.internal.VersionedMapImpl; 14import tools.refinery.store.map.VersionedMap;
15import tools.refinery.store.map.VersionedMapStore;
16import tools.refinery.store.map.VersionedMapStoreFactoryBuilder;
15import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; 17import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
16import tools.refinery.store.map.tests.utils.MapTestEnvironment; 18import tools.refinery.store.map.tests.utils.MapTestEnvironment;
17 19
@@ -22,23 +24,25 @@ import java.util.List;
22import java.util.Random; 24import java.util.Random;
23import java.util.stream.Stream; 25import java.util.stream.Stream;
24 26
25import static org.junit.jupiter.api.Assertions.*; 27import static org.junit.jupiter.api.Assertions.fail;
28import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*;
26 29
27class ContentEqualsFuzzTest { 30class ContentEqualsFuzzTest {
28 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, 31 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue,
29 boolean evilHash) { 32 boolean nullDefault, int commitFrequency,
30 String[] values = MapTestEnvironment.prepareValues(maxValue); 33 VersionedMapStoreFactoryBuilder<Integer, String> builder) {
31 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); 34 String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault);
35
32 36
33 Random r = new Random(seed); 37 Random r = new Random(seed);
34 38
35 iterativeRandomPutsAndCommitsThenCompare(scenario, chp, steps, maxKey, values, r, commitFrequency); 39 iterativeRandomPutsAndCommitsThenCompare(scenario, builder, steps, maxKey, values, r, commitFrequency);
36 } 40 }
37 41
38 private void iterativeRandomPutsAndCommitsThenCompare(String scenario, ContinousHashProvider<Integer> chp, 42 private void iterativeRandomPutsAndCommitsThenCompare(String scenario, VersionedMapStoreFactoryBuilder<Integer, String> builder,
39 int steps, int maxKey, String[] values, Random r, 43 int steps, int maxKey, String[] values, Random r,
40 int commitFrequency) { 44 int commitFrequency) {
41 VersionedMapStore<Integer, String> store1 = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); 45 VersionedMapStore<Integer, String> store1 = builder.defaultValue(values[0]).build().createOne();
42 VersionedMap<Integer, String> sut1 = store1.createMap(); 46 VersionedMap<Integer, String> sut1 = store1.createMap();
43 47
44 // Fill one map 48 // Fill one map
@@ -68,7 +72,7 @@ class ContentEqualsFuzzTest {
68 // Randomize the order of the content 72 // Randomize the order of the content
69 Collections.shuffle(content, r); 73 Collections.shuffle(content, r);
70 74
71 VersionedMapStore<Integer, String> store2 = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); 75 VersionedMapStore<Integer, String> store2 = builder.defaultValue(values[0]).build().createOne();
72 VersionedMap<Integer, String> sut2 = store2.createMap(); 76 VersionedMap<Integer, String> sut2 = store2.createMap();
73 int index2 = 1; 77 int index2 = 1;
74 for (SimpleEntry<Integer, String> entry : content) { 78 for (SimpleEntry<Integer, String> entry : content) {
@@ -78,40 +82,39 @@ class ContentEqualsFuzzTest {
78 } 82 }
79 83
80 // Check the integrity of the maps 84 // Check the integrity of the maps
81 ((VersionedMapImpl<Integer, String>) sut1).checkIntegrity(); 85 sut1.checkIntegrity();
82 ((VersionedMapImpl<Integer, String>) sut2).checkIntegrity(); 86 sut2.checkIntegrity();
83 87
84 // Compare the two maps 88 // Compare the two maps
85 MapTestEnvironment.compareTwoMaps(scenario, sut1, sut2); 89 MapTestEnvironment.compareTwoMaps(scenario, sut1, sut2);
86 } 90 }
87 91
88 @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} " + 92 public static final String title = "Compare {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit frequency={5}" +
89 "evil-hash={6}") 93 "seed={6} config={7}";
94
95 @ParameterizedTest(name = title)
90 @MethodSource 96 @MethodSource
91 @Timeout(value = 10) 97 @Timeout(value = 10)
92 @Tag("fuzz") 98 @Tag("fuzz")
93 void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, 99 void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency,
94 boolean evilHash) { 100 int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) {
95 runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, 101 runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
96 commitFrequency, evilHash); 102 nullDefault, commitFrequency, builder);
97 } 103 }
98 104
99 static Stream<Arguments> parametrizedFastFuzz() { 105 static Stream<Arguments> parametrizedFastFuzz() {
100 return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, 106 return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions,
101 32 * 32}, 107 commitFrequencyOptions, randomSeedOptions, storeConfigs);
102 new Object[]{2, 3}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3},
103 new Object[]{false, true});
104 } 108 }
105 109
106 @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} " + 110 @ParameterizedTest(name = title)
107 "evil-hash={6}")
108 @MethodSource 111 @MethodSource
109 @Tag("fuzz") 112 @Tag("fuzz")
110 @Tag("slow") 113 @Tag("slow")
111 void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, 114 void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, int commitFrequency,
112 boolean evilHash) { 115 int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) {
113 runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, 116 runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
114 commitFrequency, evilHash); 117 defaultNull, commitFrequency, builder);
115 } 118 }
116 119
117 static Stream<Arguments> parametrizedSlowFuzz() { 120 static Stream<Arguments> parametrizedSlowFuzz() {
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java
index 8274336e..94259edc 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java
@@ -5,115 +5,134 @@
5 */ 5 */
6package tools.refinery.store.map.tests.fuzz; 6package tools.refinery.store.map.tests.fuzz;
7 7
8import static org.junit.jupiter.api.Assertions.fail;
9
10import java.util.Random;
11import java.util.stream.Stream;
12
13import org.junit.jupiter.api.Tag; 8import org.junit.jupiter.api.Tag;
14import org.junit.jupiter.api.Timeout; 9import org.junit.jupiter.api.Timeout;
15import org.junit.jupiter.params.ParameterizedTest; 10import org.junit.jupiter.params.ParameterizedTest;
16import org.junit.jupiter.params.provider.Arguments; 11import org.junit.jupiter.params.provider.Arguments;
17import org.junit.jupiter.params.provider.MethodSource; 12import org.junit.jupiter.params.provider.MethodSource;
18 13import tools.refinery.store.map.*;
19import tools.refinery.store.map.ContinousHashProvider;
20import tools.refinery.store.map.DiffCursor;
21import tools.refinery.store.map.VersionedMapStore;
22import tools.refinery.store.map.VersionedMapStoreImpl;
23import tools.refinery.store.map.internal.VersionedMapImpl;
24import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; 14import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
25import tools.refinery.store.map.tests.utils.MapTestEnvironment; 15import tools.refinery.store.map.tests.utils.MapTestEnvironment;
26 16
17import java.util.HashMap;
18import java.util.Map;
19import java.util.Random;
20import java.util.stream.Stream;
21
22import static org.junit.jupiter.api.Assertions.fail;
23import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*;
24
27class DiffCursorFuzzTest { 25class DiffCursorFuzzTest {
28 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, 26 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault,
29 boolean evilHash) { 27 int commitFrequency, boolean commitBeforeDiffCursor,
30 String[] values = MapTestEnvironment.prepareValues(maxValue); 28 VersionedMapStoreFactoryBuilder<Integer, String> builder) {
31 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); 29 String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault);
32 30
33 VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); 31 VersionedMapStore<Integer, String> store = builder.defaultValue(values[0]).build().createOne();
34 iterativeRandomPutsAndCommitsThenDiffcursor(scenario, store, steps, maxKey, values, seed, commitFrequency); 32 iterativeRandomPutsAndCommitsThenDiffCursor(scenario, store, steps, maxKey, values, seed, commitFrequency,
33 commitBeforeDiffCursor);
35 } 34 }
36 35
37 private void iterativeRandomPutsAndCommitsThenDiffcursor(String scenario, VersionedMapStore<Integer, String> store, 36 private void iterativeRandomPutsAndCommitsThenDiffCursor(String scenario, VersionedMapStore<Integer, String> store,
38 int steps, int maxKey, String[] values, int seed, int commitFrequency) { 37 int steps, int maxKey, String[] values, int seed,
39 // 1. build a map with versions 38 int commitFrequency, boolean commitBeforeDiffCursor) {
40 Random r = new Random(seed); 39
41 VersionedMapImpl<Integer, String> versioned = (VersionedMapImpl<Integer, String>) store.createMap();
42 int largestCommit = -1; 40 int largestCommit = -1;
41 Map<Integer,Version> index2Version = new HashMap<>();
43 42
44 for (int i = 0; i < steps; i++) { 43 {
45 int index = i + 1; 44 // 1. build a map with versions
46 int nextKey = r.nextInt(maxKey); 45 Random r = new Random(seed);
47 String nextValue = values[r.nextInt(values.length)]; 46 VersionedMap<Integer, String> versioned = store.createMap();
48 try { 47 for (int i = 0; i < steps; i++) {
49 versioned.put(nextKey, nextValue); 48 int index = i + 1;
50 } catch (Exception exception) { 49 int nextKey = r.nextInt(maxKey);
51 exception.printStackTrace(); 50 String nextValue = values[r.nextInt(values.length)];
52 fail(scenario + ":" + index + ": exception happened: " + exception);
53 }
54 if (index % commitFrequency == 0) {
55 long version = versioned.commit();
56 largestCommit = (int) version;
57 }
58 if (index % 10000 == 0)
59 System.out.println(scenario + ":" + index + "/" + steps + " building finished");
60 }
61 // 2. create a non-versioned map,
62 VersionedMapImpl<Integer, String> moving = (VersionedMapImpl<Integer, String>) store.createMap();
63 Random r2 = new Random(seed + 1);
64
65 final int diffTravelFrequency = commitFrequency * 2;
66 for (int i = 0; i < steps; i++) {
67 int index = i + 1;
68 if (index % diffTravelFrequency == 0) {
69 // difftravel
70 long travelToVersion = r2.nextInt(largestCommit + 1);
71 DiffCursor<Integer, String> diffCursor = moving.getDiffCursor(travelToVersion);
72 moving.putAll(diffCursor);
73
74 } else {
75 // random puts
76 int nextKey = r2.nextInt(maxKey);
77 String nextValue = values[r2.nextInt(values.length)];
78 try { 51 try {
79 moving.put(nextKey, nextValue); 52 versioned.put(nextKey, nextValue);
80 } catch (Exception exception) { 53 } catch (Exception exception) {
81 exception.printStackTrace(); 54 exception.printStackTrace();
82 fail(scenario + ":" + index + ": exception happened: " + exception); 55 fail(scenario + ":" + index + ": exception happened: " + exception);
83 } 56 }
84 if (index % commitFrequency == 0) { 57 if (index % commitFrequency == 0) {
85 versioned.commit(); 58 Version version = versioned.commit();
59 index2Version.put(index,version);
60 largestCommit = index;
86 } 61 }
87 if (index % 10000 == 0) 62 if (index % 10000 == 0)
88 System.out.println(scenario + ":" + index + "/" + steps + " building finished"); 63 System.out.println(scenario + ":" + index + "/" + steps + " building finished");
89 } 64 }
90 } 65 }
91 66
67 {
68 // 2. create a non-versioned map,
69 VersionedMap<Integer, String> moving = store.createMap();
70 Random r2 = new Random(seed + 1);
71
72 final int diffTravelFrequency = commitFrequency * 2;
73 for (int i = 0; i < steps; i++) {
74 int index = i + 1;
75 if (index % diffTravelFrequency == 0) {
76 // diff-travel
77 int travelToVersion = r2.nextInt(largestCommit + 1);
78
79 VersionedMap<Integer, String> oracle = store.createMap(index2Version.get(travelToVersion));
80
81 if(commitBeforeDiffCursor) {
82 moving.commit();
83 }
84 DiffCursor<Integer, String> diffCursor = moving.getDiffCursor(index2Version.get(travelToVersion));
85 moving.putAll(diffCursor);
86 moving.commit();
87
88 MapTestEnvironment.compareTwoMaps(scenario + ":c" + index, oracle, moving);
89
90 moving.restore(index2Version.get(travelToVersion));
91
92 } else {
93 // random puts
94 int nextKey = r2.nextInt(maxKey);
95 String nextValue = values[r2.nextInt(values.length)];
96 try {
97 moving.put(nextKey, nextValue);
98 } catch (Exception exception) {
99 exception.printStackTrace();
100 fail(scenario + ":" + index + ": exception happened: " + exception);
101 }
102 if (index % 10000 == 0)
103 System.out.println(scenario + ":" + index + "/" + steps + " building finished");
104 }
105 }
106 }
92 } 107 }
93 108
94 @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") 109 public static final String title = "DiffCursor {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " +
110 "commit frequency={5} seed={6} commit before diff={7} config={8}";
111
112 @ParameterizedTest(name = title)
95 @MethodSource 113 @MethodSource
96 @Timeout(value = 10) 114 @Timeout(value = 10)
97 @Tag("fuzz") 115 @Tag("fuzz")
98 void parametrizedFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, 116 void parametrizedFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault,
99 boolean evilHash) { 117 int commitFrequency, int seed, boolean commitBeforeDiffCursor,
100 runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, 118 VersionedMapStoreFactoryBuilder<Integer, String> builder) {
101 noKeys, noValues, commitFrequency, evilHash); 119 runFuzzTest("DiffCursorS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps,
120 noKeys, noValues, nullDefault, commitFrequency, commitBeforeDiffCursor, builder);
102 } 121 }
103 122
104 static Stream<Arguments> parametrizedFuzz() { 123 static Stream<Arguments> parametrizedFuzz() {
105 return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, 124 return FuzzTestUtils.permutationWithSize(new Object[]{100}, keyCounts, valueCounts, nullDefaultOptions,
106 new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, 125 commitFrequencyOptions, randomSeedOptions, new Object[]{false,true}, storeConfigs);
107 new Object[] { false, true });
108 } 126 }
109 @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") 127
128 @ParameterizedTest(name = title)
110 @MethodSource 129 @MethodSource
111 @Tag("fuzz") 130 @Tag("fuzz")
112 @Tag("slow") 131 @Tag("slow")
113 void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, 132 void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency,
114 boolean evilHash) { 133 int seed, boolean commitBeforeDiffCursor, VersionedMapStoreFactoryBuilder<Integer, String> builder) {
115 runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, 134 runFuzzTest("DiffCursorS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
116 commitFrequency, evilHash); 135 nullDefault, commitFrequency, commitBeforeDiffCursor, builder);
117 } 136 }
118 137
119 static Stream<Arguments> parametrizedSlowFuzz() { 138 static Stream<Arguments> parametrizedSlowFuzz() {
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java
index ab2b9435..3b55434c 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java
@@ -5,95 +5,96 @@
5 */ 5 */
6package tools.refinery.store.map.tests.fuzz; 6package tools.refinery.store.map.tests.fuzz;
7 7
8import static org.junit.jupiter.api.Assertions.assertEquals;
9import static org.junit.jupiter.api.Assertions.fail;
10
11import java.util.Collections;
12import java.util.LinkedList;
13import java.util.List;
14import java.util.stream.Stream;
15
16import org.junit.jupiter.api.Tag; 8import org.junit.jupiter.api.Tag;
17import org.junit.jupiter.api.Timeout; 9import org.junit.jupiter.api.Timeout;
18import org.junit.jupiter.params.ParameterizedTest; 10import org.junit.jupiter.params.ParameterizedTest;
19import org.junit.jupiter.params.provider.Arguments; 11import org.junit.jupiter.params.provider.Arguments;
20import org.junit.jupiter.params.provider.MethodSource; 12import org.junit.jupiter.params.provider.MethodSource;
21
22import tools.refinery.store.map.ContinousHashProvider;
23import tools.refinery.store.map.VersionedMapStore; 13import tools.refinery.store.map.VersionedMapStore;
24import tools.refinery.store.map.VersionedMapStoreImpl; 14import tools.refinery.store.map.VersionedMapStoreFactoryBuilder;
25import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; 15import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
26import tools.refinery.store.map.tests.utils.MapTestEnvironment; 16import tools.refinery.store.map.tests.utils.MapTestEnvironment;
27 17
18import java.util.Collections;
19import java.util.LinkedList;
20import java.util.List;
21import java.util.stream.Stream;
22
23import static org.junit.jupiter.api.Assertions.assertEquals;
24import static org.junit.jupiter.api.Assertions.fail;
25import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*;
26
28class MultiThreadFuzzTest { 27class MultiThreadFuzzTest {
29 public static final int noThreads = 32; 28 public static final int noThreads = 10;
30 29
31 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, 30 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, VersionedMapStoreFactoryBuilder<Integer, String> builder) {
32 boolean evilHash) { 31 String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault);
33 String[] values = MapTestEnvironment.prepareValues(maxValue); 32
34 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); 33 VersionedMapStore<Integer, String> store = builder.defaultValue(values[0]).build().createOne();
35 34
36 VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]);
37
38 // initialize runnables 35 // initialize runnables
39 MultiThreadTestRunnable[] runnables = new MultiThreadTestRunnable[noThreads]; 36 MultiThreadTestRunnable[] runnables = new MultiThreadTestRunnable[noThreads];
40 for(int i = 0; i<noThreads; i++) { 37 for (int i = 0; i < noThreads; i++) {
41 runnables[i] = new MultiThreadTestRunnable(scenario+"-T"+(i+1), store, steps, maxKey, values, seed, commitFrequency); 38 runnables[i] = new MultiThreadTestRunnable(scenario + "-T" + (i + 1), store, steps, maxKey, values, seed
39 , commitFrequency);
42 } 40 }
43 41
44 // initialize threads 42 // initialize threads
45 Thread[] threads = new Thread[noThreads]; 43 Thread[] threads = new Thread[noThreads];
46 for(int i = 0; i<noThreads; i++) { 44 for (int i = 0; i < noThreads; i++) {
47 threads[i] = new Thread(runnables[i]); 45 threads[i] = new Thread(runnables[i]);
48 } 46 }
49 47
50 // start threads; 48 // start threads;
51 for(int i = 0; i<noThreads; i++) { 49 for (int i = 0; i < noThreads; i++) {
52 threads[i].start(); 50 runnables[i].run();
51 //threads[i].start();
53 } 52 }
54 53
55 // wait all the threads; 54 // wait all the threads;
56 for(int i = 0; i<noThreads; i++) { 55 for (int i = 0; i < noThreads; i++) {
57 try { 56 try {
58 threads[i].join(); 57 threads[i].join();
59 } catch (InterruptedException e) { 58 } catch (InterruptedException e) {
60 fail("Thread "+i+" interrupted."); 59 fail("Thread " + i + " interrupted.");
61 } 60 }
62 } 61 }
63 62
64 // collect errors 63 // collect errors
65 List<Throwable> errors = new LinkedList<>(); 64 List<Throwable> errors = new LinkedList<>();
66 for(int i = 0; i<noThreads; i++) { 65 for (int i = 0; i < noThreads; i++) {
67 errors.addAll(runnables[i].getErrors()); 66 errors.addAll(runnables[i].getErrors());
68 } 67 }
69 68
70 assertEquals(Collections.EMPTY_LIST, errors); 69 assertEquals(Collections.EMPTY_LIST, errors);
71 } 70 }
72 71
73 @ParameterizedTest(name = "Multithread {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") 72 static final String title = "MultiThread {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit " +
73 "frequency={5} seed={6} config={7}";
74
75 @ParameterizedTest(name = title)
74 @MethodSource 76 @MethodSource
75 @Timeout(value = 10) 77 @Timeout(value = 10)
76 @Tag("fuzz") 78 @Tag("fuzz")
77 void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, 79 void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull,
78 boolean evilHash) { 80 int commitFrequency, int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) {
79 runFuzzTest("MultithreadS" + steps + "K" + noKeys + "V" + noValues + "CF" + commitFrequency + "s" + seed, seed, steps, noKeys, noValues, 81 runFuzzTest("MultiThreadS" + steps + "K" + noKeys + "V" + noValues + defaultNull + "CF" + commitFrequency +
80 commitFrequency, evilHash); 82 "s" + seed, seed, steps, noKeys, noValues, defaultNull, commitFrequency, builder);
81 } 83 }
82 84
83 static Stream<Arguments> parametrizedFastFuzz() { 85 static Stream<Arguments> parametrizedFastFuzz() {
84 return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, 86 return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions,
85 new Object[] { 2, 3 }, new Object[] { 10, 100 }, new Object[] { 1, 2, 3 }, 87 new Object[]{10, 100}, randomSeedOptions, storeConfigs);
86 new Object[] { false, true });
87 } 88 }
88 89
89 @ParameterizedTest(name = "Multithread {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") 90 @ParameterizedTest(name = title)
90 @MethodSource 91 @MethodSource
91 @Tag("fuzz") 92 @Tag("fuzz")
92 @Tag("slow") 93 @Tag("slow")
93 void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, 94 void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault,
94 boolean evilHash) { 95 int commitFrequency, int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) {
95 runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, 96 runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
96 commitFrequency, evilHash); 97 nullDefault, commitFrequency, builder);
97 } 98 }
98 99
99 static Stream<Arguments> parametrizedSlowFuzz() { 100 static Stream<Arguments> parametrizedSlowFuzz() {
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java
index 502c8362..dfe46bae 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java
@@ -13,22 +13,23 @@ import java.util.List;
13import java.util.Map; 13import java.util.Map;
14import java.util.Random; 14import java.util.Random;
15 15
16import tools.refinery.store.map.Version;
17import tools.refinery.store.map.VersionedMap;
16import tools.refinery.store.map.VersionedMapStore; 18import tools.refinery.store.map.VersionedMapStore;
17import tools.refinery.store.map.internal.VersionedMapImpl;
18import tools.refinery.store.map.tests.utils.MapTestEnvironment; 19import tools.refinery.store.map.tests.utils.MapTestEnvironment;
19 20
20public class MultiThreadTestRunnable implements Runnable { 21public class MultiThreadTestRunnable implements Runnable {
21 String scenario; 22 final String scenario;
22 VersionedMapStore<Integer, String> store; 23 final VersionedMapStore<Integer, String> store;
23 int steps; 24 final int steps;
24 int maxKey; 25 final int maxKey;
25 String[] values; 26 final String[] values;
26 int seed; 27 final int seed;
27 int commitFrequency; 28 final int commitFrequency;
28 List<Throwable> errors = new LinkedList<>(); 29 final List<Throwable> errors = new LinkedList<>();
29 30
30 public MultiThreadTestRunnable(String scenario, VersionedMapStore<Integer, String> store, int steps, 31 public MultiThreadTestRunnable(String scenario, VersionedMapStore<Integer, String> store, int steps,
31 int maxKey, String[] values, int seed, int commitFrequency) { 32 int maxKey, String[] values, int seed, int commitFrequency) {
32 super(); 33 super();
33 this.scenario = scenario; 34 this.scenario = scenario;
34 this.store = store; 35 this.store = store;
@@ -43,17 +44,25 @@ public class MultiThreadTestRunnable implements Runnable {
43 AssertionError error = new AssertionError(message); 44 AssertionError error = new AssertionError(message);
44 errors.add(error); 45 errors.add(error);
45 } 46 }
46 47
47 public List<Throwable> getErrors() { 48 public List<Throwable> getErrors() {
48 return errors; 49 return errors;
49 } 50 }
50 51
51 @Override 52 @Override
52 public void run() { 53 public void run() {
54 try{
55 task();
56 } catch(Exception e) {
57 e.printStackTrace();
58 }
59 }
60
61 private void task() {
53 // 1. build a map with versions 62 // 1. build a map with versions
54 Random r = new Random(seed); 63 Random r = new Random(seed);
55 VersionedMapImpl<Integer, String> versioned = (VersionedMapImpl<Integer, String>) store.createMap(); 64 VersionedMap<Integer, String> versioned = store.createMap();
56 Map<Integer, Long> index2Version = new HashMap<>(); 65 Map<Integer, Version> index2Version = new HashMap<>();
57 66
58 for (int i = 0; i < steps; i++) { 67 for (int i = 0; i < steps; i++) {
59 int index = i + 1; 68 int index = i + 1;
@@ -66,15 +75,15 @@ public class MultiThreadTestRunnable implements Runnable {
66 logAndThrowError(scenario + ":" + index + ": exception happened: " + exception); 75 logAndThrowError(scenario + ":" + index + ": exception happened: " + exception);
67 } 76 }
68 if (index % commitFrequency == 0) { 77 if (index % commitFrequency == 0) {
69 long version = versioned.commit(); 78 Version version = versioned.commit();
70 index2Version.put(i, version); 79 index2Version.put(i, version);
71 } 80 }
72 MapTestEnvironment.printStatus(scenario, index, steps, "building"); 81 MapTestEnvironment.printStatus(scenario, index, steps, "building");
73 } 82 }
74 // 2. create a non-versioned 83 // 2. create a non-versioned
75 VersionedMapImpl<Integer, String> reference = (VersionedMapImpl<Integer, String>) store.createMap(); 84 VersionedMap<Integer, String> reference = store.createMap();
76 r = new Random(seed); 85 r = new Random(seed);
77 Random r2 = new Random(seed+1); 86 Random r2 = new Random(seed + 1);
78 87
79 for (int i = 0; i < steps; i++) { 88 for (int i = 0; i < steps; i++) {
80 int index = i + 1; 89 int index = i + 1;
@@ -89,13 +98,16 @@ public class MultiThreadTestRunnable implements Runnable {
89 // go back to an existing state and compare to the reference 98 // go back to an existing state and compare to the reference
90 if (index % (commitFrequency) == 0) { 99 if (index % (commitFrequency) == 0) {
91 versioned.restore(index2Version.get(i)); 100 versioned.restore(index2Version.get(i));
92 MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference, versioned,errors); 101 MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference, versioned, null);
93 102
94 // go back to a random state (probably created by another thread) 103 // go back to a random state (probably created by another thread)
95 List<Long> states = new ArrayList<>(store.getStates()); 104 List<Version> states = new ArrayList<>(index2Version.values());
105 //states.sort(Long::compare);
96 Collections.shuffle(states, r2); 106 Collections.shuffle(states, r2);
97 for(Long state : states.subList(0, Math.min(states.size(), 100))) { 107 for (Version state : states.subList(0, Math.min(states.size(), 100))) {
98 versioned.restore(state); 108 versioned.restore(state);
109 var clean = store.createMap(state);
110 MapTestEnvironment.compareTwoMaps(scenario + ":" + index, clean, versioned, null);
99 } 111 }
100 versioned.restore(index2Version.get(i)); 112 versioned.restore(index2Version.get(i));
101 } 113 }
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java
index 32dde0da..fdcd7f9f 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java
@@ -6,6 +6,7 @@
6package tools.refinery.store.map.tests.fuzz; 6package tools.refinery.store.map.tests.fuzz;
7 7
8import static org.junit.jupiter.api.Assertions.fail; 8import static org.junit.jupiter.api.Assertions.fail;
9import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*;
9 10
10import java.util.Random; 11import java.util.Random;
11import java.util.stream.Stream; 12import java.util.stream.Stream;
@@ -16,21 +17,18 @@ import org.junit.jupiter.params.ParameterizedTest;
16import org.junit.jupiter.params.provider.Arguments; 17import org.junit.jupiter.params.provider.Arguments;
17import org.junit.jupiter.params.provider.MethodSource; 18import org.junit.jupiter.params.provider.MethodSource;
18 19
19import tools.refinery.store.map.ContinousHashProvider; 20import tools.refinery.store.map.*;
20import tools.refinery.store.map.VersionedMapStore;
21import tools.refinery.store.map.VersionedMapStoreImpl;
22import tools.refinery.store.map.internal.VersionedMapImpl;
23import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; 21import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
24import tools.refinery.store.map.tests.utils.MapTestEnvironment; 22import tools.refinery.store.map.tests.utils.MapTestEnvironment;
25 23
26class MutableFuzzTest { 24class MutableFuzzTest {
27 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean evilHash) { 25 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue,
28 String[] values = MapTestEnvironment.prepareValues(maxValue); 26 boolean nullDefault, VersionedMapStoreFactoryBuilder<Integer, String> builder) {
29 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); 27 String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault);
30 28
31 VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); 29 VersionedMapStore<Integer, String> store = builder.defaultValue(values[0]).build().createOne();
32 VersionedMapImpl<Integer, String> sut = (VersionedMapImpl<Integer, String>) store.createMap(); 30 VersionedMap<Integer, String> sut = store.createMap();
33 MapTestEnvironment<Integer, String> e = new MapTestEnvironment<Integer, String>(sut); 31 MapTestEnvironment<Integer, String> e = new MapTestEnvironment<>(sut);
34 32
35 Random r = new Random(seed); 33 Random r = new Random(seed);
36 34
@@ -38,24 +36,14 @@ class MutableFuzzTest {
38 } 36 }
39 37
40 private void iterativeRandomPuts(String scenario, int steps, int maxKey, String[] values, 38 private void iterativeRandomPuts(String scenario, int steps, int maxKey, String[] values,
41 MapTestEnvironment<Integer, String> e, Random r) { 39 MapTestEnvironment<Integer, String> e, Random r) {
42 int stopAt = -1;
43 for (int i = 0; i < steps; i++) { 40 for (int i = 0; i < steps; i++) {
44 int index = i + 1; 41 int index = i + 1;
45 int nextKey = r.nextInt(maxKey); 42 int nextKey = r.nextInt(maxKey);
46 String nextValue = values[r.nextInt(values.length)]; 43 String nextValue = values[r.nextInt(values.length)];
47 if (index == stopAt) { 44
48 System.out.println("issue!");
49 System.out.println("State before:");
50 e.printComparison();
51 e.sut.prettyPrint();
52 System.out.println("Next: put(" + nextKey + "," + nextValue + ")");
53 }
54 try { 45 try {
55 e.put(nextKey, nextValue); 46 e.put(nextKey, nextValue);
56 if (index == stopAt) {
57 e.sut.prettyPrint();
58 }
59 e.checkEquivalence(scenario + ":" + index); 47 e.checkEquivalence(scenario + ":" + index);
60 } catch (Exception exception) { 48 } catch (Exception exception) {
61 exception.printStackTrace(); 49 exception.printStackTrace();
@@ -65,30 +53,34 @@ class MutableFuzzTest {
65 } 53 }
66 } 54 }
67 55
68 @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} seed={4} evil-hash={5}") 56 final String title = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} seed={5} " +
57 "config={6}";
58
59 @ParameterizedTest(name = title)
69 @MethodSource 60 @MethodSource
70 @Timeout(value = 10) 61 @Timeout(value = 10)
71 @Tag("fuzz") 62 @Tag("fuzz")
72 void parametrizedFuzz(int test, int steps, int noKeys, int noValues, int seed, boolean evilHash) { 63 void parametrizedFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, int seed,
64 VersionedMapStoreFactoryBuilder<Integer, String> builder) {
73 runFuzzTest( 65 runFuzzTest(
74 "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed + "H" + (evilHash ? "Evil" : "Normal"), 66 "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed,
75 seed, steps, noKeys, noValues, evilHash); 67 seed, steps, noKeys, noValues, defaultNull, builder);
76 } 68 }
77 69
78 static Stream<Arguments> parametrizedFuzz() { 70 static Stream<Arguments> parametrizedFuzz() {
79 return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, 71 return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions,
80 new Object[] { 3, 32, 32 * 32, 32 * 32 * 32 * 32 }, new Object[] { 2, 3 }, new Object[] { 1, 2, 3 }, 72 randomSeedOptions, storeConfigs);
81 new Object[] { false, true });
82 } 73 }
83 74
84 @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} seed={4} evil-hash={5}") 75 @ParameterizedTest(name = title)
85 @MethodSource 76 @MethodSource
86 @Tag("fuzz") 77 @Tag("fuzz")
87 @Tag("slow") 78 @Tag("slow")
88 void parametrizedSlowFuzz(int test, int steps, int noKeys, int noValues, int seed, boolean evilHash) { 79 void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int seed,
80 VersionedMapStoreFactoryBuilder<Integer, String> builder) {
89 runFuzzTest( 81 runFuzzTest(
90 "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed + "H" + (evilHash ? "Evil" : "Normal"), 82 "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed,
91 seed, steps, noKeys, noValues, evilHash); 83 seed, steps, noKeys, noValues, nullDefault, builder);
92 } 84 }
93 85
94 static Stream<Arguments> parametrizedSlowFuzz() { 86 static Stream<Arguments> parametrizedSlowFuzz() {
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java
index 347c49be..abfb4791 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java
@@ -6,6 +6,7 @@
6package tools.refinery.store.map.tests.fuzz; 6package tools.refinery.store.map.tests.fuzz;
7 7
8import static org.junit.jupiter.api.Assertions.fail; 8import static org.junit.jupiter.api.Assertions.fail;
9import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*;
9 10
10import java.util.Random; 11import java.util.Random;
11import java.util.stream.Stream; 12import java.util.stream.Stream;
@@ -16,22 +17,22 @@ import org.junit.jupiter.params.ParameterizedTest;
16import org.junit.jupiter.params.provider.Arguments; 17import org.junit.jupiter.params.provider.Arguments;
17import org.junit.jupiter.params.provider.MethodSource; 18import org.junit.jupiter.params.provider.MethodSource;
18 19
19import tools.refinery.store.map.ContinousHashProvider; 20import tools.refinery.store.map.ContinuousHashProvider;
20import tools.refinery.store.map.VersionedMapStore; 21import tools.refinery.store.map.VersionedMapStore;
21import tools.refinery.store.map.VersionedMapStoreImpl; 22import tools.refinery.store.map.internal.state.VersionedMapStoreStateImpl;
22import tools.refinery.store.map.internal.VersionedMapImpl; 23import tools.refinery.store.map.internal.state.VersionedMapStateImpl;
23import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; 24import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
24import tools.refinery.store.map.tests.utils.MapTestEnvironment; 25import tools.refinery.store.map.tests.utils.MapTestEnvironment;
25 26
26class MutableImmutableCompareFuzzTest { 27class MutableImmutableCompareFuzzTest {
27 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, 28 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue,
28 boolean evilHash) { 29 boolean nullDefault, int commitFrequency, boolean evilHash) {
29 String[] values = MapTestEnvironment.prepareValues(maxValue); 30 String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault);
30 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); 31 ContinuousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash);
31 32
32 VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); 33 VersionedMapStore<Integer, String> store = new VersionedMapStoreStateImpl<>(chp, values[0]);
33 VersionedMapImpl<Integer, String> immutable = (VersionedMapImpl<Integer, String>) store.createMap(); 34 VersionedMapStateImpl<Integer, String> immutable = (VersionedMapStateImpl<Integer, String>) store.createMap();
34 VersionedMapImpl<Integer, String> mutable = (VersionedMapImpl<Integer, String>) store.createMap(); 35 VersionedMapStateImpl<Integer, String> mutable = (VersionedMapStateImpl<Integer, String>) store.createMap();
35 36
36 Random r = new Random(seed); 37 Random r = new Random(seed);
37 38
@@ -39,9 +40,9 @@ class MutableImmutableCompareFuzzTest {
39 commitFrequency); 40 commitFrequency);
40 } 41 }
41 42
42 private void iterativeRandomPutsAndCommitsAndCompare(String scenario, VersionedMapImpl<Integer, String> immutable, 43 private void iterativeRandomPutsAndCommitsAndCompare(String scenario, VersionedMapStateImpl<Integer, String> immutable,
43 VersionedMapImpl<Integer, String> mutable, int steps, int maxKey, String[] values, Random r, 44 VersionedMapStateImpl<Integer, String> mutable, int steps, int maxKey, String[] values, Random r,
44 int commitFrequency) { 45 int commitFrequency) {
45 for (int i = 0; i < steps; i++) { 46 for (int i = 0; i < steps; i++) {
46 int index = i + 1; 47 int index = i + 1;
47 int nextKey = r.nextInt(maxKey); 48 int nextKey = r.nextInt(maxKey);
@@ -62,30 +63,31 @@ class MutableImmutableCompareFuzzTest {
62 } 63 }
63 } 64 }
64 65
65 @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") 66 @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " +
67 "commit frequency={5} seed={6} evil-hash={7}")
66 @MethodSource 68 @MethodSource
67 @Timeout(value = 10) 69 @Timeout(value = 10)
68 @Tag("fuzz") 70 @Tag("fuzz")
69 void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, 71 void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency,
70 boolean evilHash) { 72 int seed, boolean evilHash) {
71 runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, 73 runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps,
72 noKeys, noValues, commitFrequency, evilHash); 74 noKeys, noValues, nullDefault, commitFrequency, evilHash);
73 } 75 }
74 76
75 static Stream<Arguments> parametrizedFastFuzz() { 77 static Stream<Arguments> parametrizedFastFuzz() {
76 return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, 78 return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions,
77 new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, 79 commitFrequencyOptions, randomSeedOptions, new Object[]{false, true});
78 new Object[] { false, true });
79 } 80 }
80 81
81 @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") 82 @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " +
83 "commit frequency={5} seed={6} evil-hash={7}")
82 @MethodSource 84 @MethodSource
83 @Tag("fuzz") 85 @Tag("fuzz")
84 @Tag("slow") 86 @Tag("slow")
85 void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, 87 void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency,
86 boolean evilHash) { 88 int seed, boolean evilHash) {
87 runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, 89 runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps,
88 noKeys, noValues, commitFrequency, evilHash); 90 noKeys, noValues, nullDefault, commitFrequency, evilHash);
89 } 91 }
90 92
91 static Stream<Arguments> parametrizedSlowFuzz() { 93 static Stream<Arguments> parametrizedSlowFuzz() {
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java
index f7b9d61e..5c768788 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java
@@ -5,43 +5,43 @@
5 */ 5 */
6package tools.refinery.store.map.tests.fuzz; 6package tools.refinery.store.map.tests.fuzz;
7 7
8import static org.junit.jupiter.api.Assertions.fail;
9
10import java.util.HashMap;
11import java.util.Map;
12import java.util.Random;
13import java.util.stream.Stream;
14
15import org.junit.jupiter.api.Tag; 8import org.junit.jupiter.api.Tag;
16import org.junit.jupiter.api.Timeout; 9import org.junit.jupiter.api.Timeout;
17import org.junit.jupiter.params.ParameterizedTest; 10import org.junit.jupiter.params.ParameterizedTest;
18import org.junit.jupiter.params.provider.Arguments; 11import org.junit.jupiter.params.provider.Arguments;
19import org.junit.jupiter.params.provider.MethodSource; 12import org.junit.jupiter.params.provider.MethodSource;
20 13import tools.refinery.store.map.Version;
21import tools.refinery.store.map.ContinousHashProvider; 14import tools.refinery.store.map.VersionedMap;
22import tools.refinery.store.map.VersionedMapStore; 15import tools.refinery.store.map.VersionedMapStore;
23import tools.refinery.store.map.VersionedMapStoreImpl; 16import tools.refinery.store.map.VersionedMapStoreFactoryBuilder;
24import tools.refinery.store.map.internal.VersionedMapImpl;
25import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; 17import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
26import tools.refinery.store.map.tests.utils.MapTestEnvironment; 18import tools.refinery.store.map.tests.utils.MapTestEnvironment;
27 19
20import java.util.HashMap;
21import java.util.Map;
22import java.util.Random;
23import java.util.stream.Stream;
24
25import static org.junit.jupiter.api.Assertions.fail;
26import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*;
27
28class RestoreFuzzTest { 28class RestoreFuzzTest {
29 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, 29 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue,
30 boolean evilHash) { 30 boolean nullDefault, int commitFrequency,
31 String[] values = MapTestEnvironment.prepareValues(maxValue); 31 VersionedMapStoreFactoryBuilder<Integer, String> builder) {
32 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); 32 String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault);
33 33
34 VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); 34 VersionedMapStore<Integer, String> store = builder.defaultValue(values[0]).build().createOne();
35 35
36 iterativeRandomPutsAndCommitsThenRestore(scenario, store, steps, maxKey, values, seed, commitFrequency); 36 iterativeRandomPutsAndCommitsThenRestore(scenario, store, steps, maxKey, values, seed, commitFrequency);
37 } 37 }
38 38
39 private void iterativeRandomPutsAndCommitsThenRestore(String scenario, VersionedMapStore<Integer, String> store, 39 private void iterativeRandomPutsAndCommitsThenRestore(String scenario, VersionedMapStore<Integer, String> store,
40 int steps, int maxKey, String[] values, int seed, int commitFrequency) { 40 int steps, int maxKey, String[] values, int seed, int commitFrequency) {
41 // 1. build a map with versions 41 // 1. build a map with versions
42 Random r = new Random(seed); 42 Random r = new Random(seed);
43 VersionedMapImpl<Integer, String> versioned = (VersionedMapImpl<Integer, String>) store.createMap(); 43 VersionedMap<Integer, String> versioned = store.createMap();
44 Map<Integer, Long> index2Version = new HashMap<>(); 44 Map<Integer, Version> index2Version = new HashMap<>();
45 45
46 for (int i = 0; i < steps; i++) { 46 for (int i = 0; i < steps; i++) {
47 int index = i + 1; 47 int index = i + 1;
@@ -54,13 +54,13 @@ class RestoreFuzzTest {
54 fail(scenario + ":" + index + ": exception happened: " + exception); 54 fail(scenario + ":" + index + ": exception happened: " + exception);
55 } 55 }
56 if (index % commitFrequency == 0) { 56 if (index % commitFrequency == 0) {
57 long version = versioned.commit(); 57 Version version = versioned.commit();
58 index2Version.put(i, version); 58 index2Version.put(i, version);
59 } 59 }
60 MapTestEnvironment.printStatus(scenario, index, steps, "building"); 60 MapTestEnvironment.printStatus(scenario, index, steps, "building");
61 } 61 }
62 // 2. create a non-versioned and 62 // 2. create a non-versioned and
63 VersionedMapImpl<Integer, String> reference = (VersionedMapImpl<Integer, String>) store.createMap(); 63 VersionedMap<Integer, String> reference = store.createMap();
64 r = new Random(seed); 64 r = new Random(seed);
65 65
66 for (int i = 0; i < steps; i++) { 66 for (int i = 0; i < steps; i++) {
@@ -82,30 +82,32 @@ class RestoreFuzzTest {
82 82
83 } 83 }
84 84
85 @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") 85 public static final String title = "Commit {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5} " +
86 "seed={6} config={7}";
87
88 @ParameterizedTest(name = title)
86 @MethodSource 89 @MethodSource
87 @Timeout(value = 10) 90 @Timeout(value = 10)
88 @Tag("smoke") 91 @Tag("smoke")
89 void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, 92 void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency,
90 boolean evilHash) { 93 int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) {
91 runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, 94 runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
92 commitFrequency, evilHash); 95 nullDefault, commitFrequency, builder);
93 } 96 }
94 97
95 static Stream<Arguments> parametrizedFastFuzz() { 98 static Stream<Arguments> parametrizedFastFuzz() {
96 return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, 99 return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions,
97 new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, 100 commitFrequencyOptions, randomSeedOptions, storeConfigs);
98 new Object[] { false, true });
99 } 101 }
100 102
101 @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") 103 @ParameterizedTest(name = title)
102 @MethodSource 104 @MethodSource
103 @Tag("smoke") 105 @Tag("smoke")
104 @Tag("slow") 106 @Tag("slow")
105 void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, 107 void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency,
106 boolean evilHash) { 108 int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) {
107 runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, 109 runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
108 commitFrequency, evilHash); 110 nullDefault, commitFrequency, builder);
109 } 111 }
110 112
111 static Stream<Arguments> parametrizedSlowFuzz() { 113 static Stream<Arguments> parametrizedSlowFuzz() {
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java
index 4b4172d0..299c94b1 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java
@@ -18,61 +18,64 @@ import org.junit.jupiter.params.ParameterizedTest;
18import org.junit.jupiter.params.provider.Arguments; 18import org.junit.jupiter.params.provider.Arguments;
19import org.junit.jupiter.params.provider.MethodSource; 19import org.junit.jupiter.params.provider.MethodSource;
20 20
21import tools.refinery.store.map.ContinousHashProvider; 21import tools.refinery.store.map.ContinuousHashProvider;
22import tools.refinery.store.map.Version;
22import tools.refinery.store.map.VersionedMapStore; 23import tools.refinery.store.map.VersionedMapStore;
23import tools.refinery.store.map.VersionedMapStoreImpl; 24import tools.refinery.store.map.internal.state.VersionedMapStoreStateImpl;
24import tools.refinery.store.map.internal.VersionedMapImpl; 25import tools.refinery.store.map.internal.state.VersionedMapStateImpl;
25import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; 26import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
26import tools.refinery.store.map.tests.utils.MapTestEnvironment; 27import tools.refinery.store.map.tests.utils.MapTestEnvironment;
27 28
29import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*;
30
28class SharedStoreFuzzTest { 31class SharedStoreFuzzTest {
29 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, 32 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue,
30 boolean evilHash) { 33 boolean nullDefault, int commitFrequency, boolean evilHash) {
31 String[] values = MapTestEnvironment.prepareValues(maxValue); 34 String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault);
32 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); 35 ContinuousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash);
33 36
34 List<VersionedMapStore<Integer, String>> stores = VersionedMapStoreImpl.createSharedVersionedMapStores(5, chp, values[0]); 37 List<VersionedMapStore<Integer, String>> stores = VersionedMapStoreStateImpl.createSharedVersionedMapStores(5, chp, values[0]);
35 38
36 iterativeRandomPutsAndCommitsThenRestore(scenario, stores, steps, maxKey, values, seed, commitFrequency); 39 iterativeRandomPutsAndCommitsThenRestore(scenario, stores, steps, maxKey, values, seed, commitFrequency);
37 } 40 }
38 41
39 private void iterativeRandomPutsAndCommitsThenRestore(String scenario, List<VersionedMapStore<Integer, String>> stores, 42 private void iterativeRandomPutsAndCommitsThenRestore(String scenario, List<VersionedMapStore<Integer, String>> stores,
40 int steps, int maxKey, String[] values, int seed, int commitFrequency) { 43 int steps, int maxKey, String[] values, int seed, int commitFrequency) {
41 // 1. maps with versions 44 // 1. maps with versions
42 Random r = new Random(seed); 45 Random r = new Random(seed);
43 List<VersionedMapImpl<Integer, String>> versioneds = new LinkedList<>(); 46 List<VersionedMapStateImpl<Integer, String>> versioneds = new LinkedList<>();
44 for(VersionedMapStore<Integer, String> store : stores) { 47 for (VersionedMapStore<Integer, String> store : stores) {
45 versioneds.add((VersionedMapImpl<Integer, String>) store.createMap()); 48 versioneds.add((VersionedMapStateImpl<Integer, String>) store.createMap());
46 } 49 }
47 50
48 List<Map<Integer, Long>> index2Version = new LinkedList<>(); 51 List<Map<Integer, Version>> index2Version = new LinkedList<>();
49 for(int i = 0; i<stores.size(); i++) { 52 for (int i = 0; i < stores.size(); i++) {
50 index2Version.add(new HashMap<>()); 53 index2Version.add(new HashMap<>());
51 } 54 }
52 55
53 for (int i = 0; i < steps; i++) { 56 for (int i = 0; i < steps; i++) {
54 int stepIndex = i + 1; 57 int stepIndex = i + 1;
55 for (int storeIndex = 0; storeIndex<versioneds.size(); storeIndex++) { 58 for (int storeIndex = 0; storeIndex < versioneds.size(); storeIndex++) {
56 int nextKey = r.nextInt(maxKey); 59 int nextKey = r.nextInt(maxKey);
57 String nextValue = values[r.nextInt(values.length)]; 60 String nextValue = values[r.nextInt(values.length)];
58 versioneds.get(storeIndex).put(nextKey, nextValue); 61 versioneds.get(storeIndex).put(nextKey, nextValue);
59 if (stepIndex % commitFrequency == 0) { 62 if (stepIndex % commitFrequency == 0) {
60 long version = versioneds.get(storeIndex).commit(); 63 Version version = versioneds.get(storeIndex).commit();
61 index2Version.get(storeIndex).put(i, version); 64 index2Version.get(storeIndex).put(i, version);
62 } 65 }
63 MapTestEnvironment.printStatus(scenario, stepIndex, steps, "building"); 66 MapTestEnvironment.printStatus(scenario, stepIndex, steps, "building");
64 } 67 }
65 } 68 }
66 // 2. create a non-versioned and 69 // 2. create a non-versioned and
67 List<VersionedMapImpl<Integer, String>> reference = new LinkedList<>(); 70 List<VersionedMapStateImpl<Integer, String>> reference = new LinkedList<>();
68 for(VersionedMapStore<Integer, String> store : stores) { 71 for (VersionedMapStore<Integer, String> store : stores) {
69 reference.add((VersionedMapImpl<Integer, String>) store.createMap()); 72 reference.add((VersionedMapStateImpl<Integer, String>) store.createMap());
70 } 73 }
71 r = new Random(seed); 74 r = new Random(seed);
72 75
73 for (int i = 0; i < steps; i++) { 76 for (int i = 0; i < steps; i++) {
74 int index = i + 1; 77 int index = i + 1;
75 for (int storeIndex = 0; storeIndex<versioneds.size(); storeIndex++) { 78 for (int storeIndex = 0; storeIndex < versioneds.size(); storeIndex++) {
76 int nextKey = r.nextInt(maxKey); 79 int nextKey = r.nextInt(maxKey);
77 String nextValue = values[r.nextInt(values.length)]; 80 String nextValue = values[r.nextInt(values.length)];
78 reference.get(storeIndex).put(nextKey, nextValue); 81 reference.get(storeIndex).put(nextKey, nextValue);
@@ -81,35 +84,36 @@ class SharedStoreFuzzTest {
81 MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference.get(storeIndex), versioneds.get(storeIndex)); 84 MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference.get(storeIndex), versioneds.get(storeIndex));
82 } 85 }
83 } 86 }
84 MapTestEnvironment.printStatus(scenario, index, steps, "comparison"); 87 MapTestEnvironment.printStatus(scenario, index, steps, "comparison");
85 } 88 }
86 89
87 } 90 }
88 91
89 @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") 92 @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit " +
93 "frequency={4} seed={5} evil-hash={6}")
90 @MethodSource 94 @MethodSource
91 @Timeout(value = 10) 95 @Timeout(value = 10)
92 @Tag("smoke") 96 @Tag("smoke")
93 void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, 97 void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency,
94 boolean evilHash) { 98 int seed, boolean evilHash) {
95 runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, 99 runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
96 commitFrequency, evilHash); 100 nullDefault, commitFrequency, evilHash);
97 } 101 }
98 102
99 static Stream<Arguments> parametrizedFastFuzz() { 103 static Stream<Arguments> parametrizedFastFuzz() {
100 return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, 104 return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions,
101 new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, 105 commitFrequencyOptions, randomSeedOptions, new Object[]{false, true});
102 new Object[] { false, true });
103 } 106 }
104 107
105 @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") 108 @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit " +
109 "frequency={4} seed={5} evil-hash={6}")
106 @MethodSource 110 @MethodSource
107 @Tag("smoke") 111 @Tag("smoke")
108 @Tag("slow") 112 @Tag("slow")
109 void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, 113 void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency,
110 boolean evilHash) { 114 int seed, boolean evilHash) {
111 runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, 115 runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
112 commitFrequency, evilHash); 116 nullDefault, commitFrequency, evilHash);
113 } 117 }
114 118
115 static Stream<Arguments> parametrizedSlowFuzz() { 119 static Stream<Arguments> parametrizedSlowFuzz() {
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java
new file mode 100644
index 00000000..1337cf3a
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java
@@ -0,0 +1,66 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.map.tests.fuzz;
7
8import org.junit.jupiter.api.Tag;
9import org.junit.jupiter.api.Timeout;
10import org.junit.jupiter.params.ParameterizedTest;
11import org.junit.jupiter.params.provider.Arguments;
12import org.junit.jupiter.params.provider.MethodSource;
13import tools.refinery.store.map.VersionedMapStore;
14import tools.refinery.store.map.VersionedMapStoreFactoryBuilder;
15import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
16import tools.refinery.store.map.tests.utils.MapTestEnvironment;
17
18import java.util.stream.Stream;
19
20import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*;
21
22class SingleThreadFuzzTest {
23 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, VersionedMapStoreFactoryBuilder<Integer, String> builder) {
24 String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault);
25
26 VersionedMapStore<Integer, String> store = builder.defaultValue(values[0]).build().createOne();
27
28 // initialize runnables
29 MultiThreadTestRunnable runnable = new MultiThreadTestRunnable(scenario, store, steps, maxKey, values, seed, commitFrequency);
30
31 // start threads;
32 runnable.run();
33 }
34
35 static final String title = "SingleThread {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit " +
36 "frequency={5} seed={6} config={7}";
37
38 @ParameterizedTest(name = title)
39 @MethodSource
40 @Timeout(value = 10)
41 @Tag("fuzz")
42 void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull,
43 int commitFrequency, int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) {
44 runFuzzTest("SingleThreadS" + steps + "K" + noKeys + "V" + noValues + defaultNull + "CF" + commitFrequency +
45 "s" + seed, seed, steps, noKeys, noValues, defaultNull, commitFrequency, builder);
46 }
47
48 static Stream<Arguments> parametrizedFastFuzz() {
49 return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions,
50 new Object[]{10, 100}, randomSeedOptions, storeConfigs);
51 }
52
53 @ParameterizedTest(name = title)
54 @MethodSource
55 @Tag("fuzz")
56 @Tag("slow")
57 void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault,
58 int commitFrequency, int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) {
59 runFuzzTest("SingleThreadS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
60 nullDefault, commitFrequency, builder);
61 }
62
63 static Stream<Arguments> parametrizedSlowFuzz() {
64 return FuzzTestUtils.changeStepCount(RestoreFuzzTest.parametrizedFastFuzz(), 1);
65 }
66}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java
new file mode 100644
index 00000000..ec04904e
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java
@@ -0,0 +1,53 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.map.tests.fuzz.utils;
7
8import tools.refinery.store.map.VersionedMapStore;
9import tools.refinery.store.map.VersionedMapStoreFactoryBuilder;
10import tools.refinery.store.map.tests.utils.MapTestEnvironment;
11
12public final class FuzzTestCollections {
13 public static final Object[] stepCounts = {FuzzTestUtils.FAST_STEP_COUNT};
14 public static final Object[] keyCounts = {1 , 32, 32 * 32};
15 public static final Object[] valueCounts = {2, 3};
16 public static final Object[] nullDefaultOptions = {false, true};
17 public static final Object[] commitFrequencyOptions = {1, 10, 100};
18 public static final Object[] randomSeedOptions = {1};
19 public static final Object[] storeConfigs = {
20 // State based
21 // Default
22 VersionedMapStore.<Integer,String>builder()
23 .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false))
24 .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE),
25 // Evil hash code test
26 VersionedMapStore.<Integer,String>builder()
27 .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(true))
28 .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE),
29 // No weak hashmap test
30 VersionedMapStore.<Integer,String>builder()
31 .versionFreeing(false)
32 .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false))
33 .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE),
34 // Copy when committing, do not hurt the work copy, share between saves.
35 VersionedMapStore.<Integer,String>builder()
36 .stateBasedImmutableWhenCommitting(false)
37 .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false))
38 .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE),
39 // Copy when committing, do not hurt the work copy, do not share between states.
40 VersionedMapStore.<Integer,String>builder()
41 .stateBasedImmutableWhenCommitting(false)
42 .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false))
43 .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.NO_NODE_CACHE),
44
45 // Delta based
46 // Set based transactions
47 VersionedMapStore.<Integer,String>builder()
48 .deltaTransactionStrategy(VersionedMapStoreFactoryBuilder.DeltaTransactionStrategy.SET),
49 // List based transactions
50 VersionedMapStore.<Integer,String>builder()
51 .deltaTransactionStrategy(VersionedMapStoreFactoryBuilder.DeltaTransactionStrategy.LIST)
52 };
53}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java
index a819d348..32675635 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java
@@ -13,7 +13,7 @@ import java.util.stream.Stream;
13import org.junit.jupiter.params.provider.Arguments; 13import org.junit.jupiter.params.provider.Arguments;
14 14
15public final class FuzzTestUtils { 15public final class FuzzTestUtils {
16 public static final int FAST_STEP_COUNT = 500; 16 public static final int FAST_STEP_COUNT = 250;
17 public static final int SLOW_STEP_COUNT = 32 * 32 * 32 * 32; 17 public static final int SLOW_STEP_COUNT = 32 * 32 * 32 * 32;
18 18
19 private FuzzTestUtils() { 19 private FuzzTestUtils() {
@@ -56,14 +56,12 @@ public final class FuzzTestUtils {
56 56
57 public static Stream<Arguments> permutationWithSize(Object[]... valueOption) { 57 public static Stream<Arguments> permutationWithSize(Object[]... valueOption) {
58 int size = 1; 58 int size = 1;
59 for (int i = 0; i < valueOption.length; i++) { 59 for (Object[] objects : valueOption) {
60 size *= valueOption[i].length; 60 size *= objects.length;
61 } 61 }
62 Object[][] newValueOption = new Object[valueOption.length + 1][]; 62 Object[][] newValueOption = new Object[valueOption.length + 1][];
63 newValueOption[0] = new Object[] { size }; 63 newValueOption[0] = new Object[]{size};
64 for (int i = 1; i < newValueOption.length; i++) { 64 System.arraycopy(valueOption, 0, newValueOption, 1, newValueOption.length - 1);
65 newValueOption[i] = valueOption[i - 1];
66 }
67 return permutation(newValueOption); 65 return permutation(newValueOption);
68 } 66 }
69} 67}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java
index dc621574..951d6336 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java
@@ -6,31 +6,36 @@
6package tools.refinery.store.map.tests.fuzz.utils; 6package tools.refinery.store.map.tests.fuzz.utils;
7 7
8import static org.junit.jupiter.api.Assertions.assertEquals; 8import static org.junit.jupiter.api.Assertions.assertEquals;
9import static org.junit.jupiter.api.Assertions.assertTrue;
9 10
10import java.util.List; 11import java.util.List;
12import java.util.Optional;
11 13
12import org.junit.jupiter.api.Test; 14import org.junit.jupiter.api.Test;
15import org.junit.jupiter.params.provider.Arguments;
13 16
14class FuzzTestUtilsTest { 17class FuzzTestUtilsTest {
15 @Test 18 @Test
16 void permutationInternalTest() { 19 void permutationInternalTest() {
17 List<List<Object>> res = FuzzTestUtils.permutationInternal(0, new Object[] { 1, 2, 3 }, 20 List<List<Object>> res = FuzzTestUtils.permutationInternal(0, new Object[]{1, 2, 3},
18 new Object[] { 'a', 'b', 'c' }, new Object[] { "alpha", "beta", "gamma", "delta" }); 21 new Object[]{'a', 'b', 'c'}, new Object[]{"alpha", "beta", "gamma", "delta"});
19 assertEquals(3 * 3 * 4, res.size()); 22 assertEquals(3 * 3 * 4, res.size());
20 } 23 }
21 24
22 @Test 25 @Test
23 void permutationTest1() { 26 void permutationTest1() {
24 var res = FuzzTestUtils.permutation(new Object[] { 1, 2, 3 }, new Object[] { 'a', 'b', 'c' }, 27 var res = FuzzTestUtils.permutation(new Object[]{1, 2, 3}, new Object[]{'a', 'b', 'c'},
25 new Object[] { "alpha", "beta", "gamma", "delta" }); 28 new Object[]{"alpha", "beta", "gamma", "delta"});
26 assertEquals(3 * 3 * 4, res.count()); 29 assertEquals(3 * 3 * 4, res.count());
27 } 30 }
28 31
29 @Test 32 @Test
30 void permutationTest2() { 33 void permutationTest2() {
31 var res = FuzzTestUtils.permutation(new Object[] { 1, 2, 3 }, new Object[] { 'a', 'b', 'c' }, 34 var res = FuzzTestUtils.permutation(new Object[]{1, 2, 3}, new Object[]{'a', 'b', 'c'},
32 new Object[] { "alpha", "beta", "gamma", "delta" }); 35 new Object[]{"alpha", "beta", "gamma", "delta"});
33 var arguments = res.findFirst().get().get(); 36 Optional<Arguments> first = res.findFirst();
37 assertTrue(first.isPresent());
38 var arguments = first.get().get();
34 assertEquals(1, arguments[0]); 39 assertEquals(1, arguments[0]);
35 assertEquals('a', arguments[1]); 40 assertEquals('a', arguments[1]);
36 assertEquals("alpha", arguments[2]); 41 assertEquals("alpha", arguments[2]);
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 f861f496..b84df280 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
@@ -6,7 +6,7 @@
6package tools.refinery.store.map.tests.utils; 6package tools.refinery.store.map.tests.utils;
7 7
8import tools.refinery.store.map.*; 8import tools.refinery.store.map.*;
9import tools.refinery.store.map.internal.VersionedMapImpl; 9import tools.refinery.store.map.internal.state.VersionedMapStateImpl;
10 10
11import java.util.*; 11import java.util.*;
12import java.util.Map.Entry; 12import java.util.Map.Entry;
@@ -14,35 +14,35 @@ import java.util.Map.Entry;
14import static org.junit.jupiter.api.Assertions.*; 14import static org.junit.jupiter.api.Assertions.*;
15 15
16public class MapTestEnvironment<K, V> { 16public class MapTestEnvironment<K, V> {
17 public static String[] prepareValues(int maxValue) { 17 public static String[] prepareValues(int maxValue, boolean nullDefault) {
18 String[] values = new String[maxValue]; 18 String[] values = new String[maxValue];
19 values[0] = "DEFAULT"; 19 if (nullDefault) {
20 values[0] = null;
21 } else {
22 values[0] = "DEFAULT";
23 }
24
20 for (int i = 1; i < values.length; i++) { 25 for (int i = 1; i < values.length; i++) {
21 values[i] = "VAL" + i; 26 values[i] = "VAL" + i;
22 } 27 }
23 return values; 28 return values;
24 } 29 }
25 30
26 public static ContinousHashProvider<Integer> prepareHashProvider(final boolean evil) { 31 public static ContinuousHashProvider<Integer> prepareHashProvider(final boolean evil) {
27 // Use maxPrime = 2147483629 32 // Use maxPrime = 2147483629
28 33
29 ContinousHashProvider<Integer> chp = new ContinousHashProvider<Integer>() { 34 return (key, index) -> {
30 35 if (evil && index < 15 && index < key / 3) {
31 @Override 36 return 7;
32 public int getHash(Integer key, int index) { 37 }
33 if (evil && index < 15 && index < key / 3) { 38 int result = 1;
34 return 7; 39 final int prime = 31;
35 }
36 int result = 1;
37 final int prime = 31;
38 40
39 result = prime * result + key; 41 result = prime * result + key;
40 result = prime * result + index; 42 result = prime * result + index;
41 43
42 return result; 44 return result;
43 }
44 }; 45 };
45 return chp;
46 } 46 }
47 47
48 public static void printStatus(String scenario, int actual, int max, String stepName) { 48 public static void printStatus(String scenario, int actual, int max, String stepName) {
@@ -60,29 +60,17 @@ public class MapTestEnvironment<K, V> {
60 60
61 public static <K, V> void compareTwoMaps(String title, VersionedMap<K, V> map1, 61 public static <K, V> void compareTwoMaps(String title, VersionedMap<K, V> map1,
62 VersionedMap<K, V> map2, List<Throwable> errors) { 62 VersionedMap<K, V> map2, List<Throwable> errors) {
63 assertEqualsList(map1.getSize(), map2.getSize(), title + ": Sizes not equal", errors); 63 map1.checkIntegrity();
64 map2.checkIntegrity();
64 65
65 Cursor<K, V> cursor1 = map1.getAll(); 66 assertContentEqualsList(map1, map2, title + ": map1.contentEquals(map2)", errors);
66 Cursor<K, V> cursor2 = map2.getAll(); 67 assertContentEqualsList(map2, map1, title + ": map2.contentEquals(map1)", errors);
67 while (!cursor1.isTerminated()) { 68 assertEqualsList(map1.getSize(), map2.getSize(), title + ": Sizes not equal", errors);
68 if (cursor2.isTerminated()) {
69 fail("cursor 2 terminated before cursor1");
70 }
71 assertEqualsList(cursor1.getKey(), cursor2.getKey(), title + ": Keys not equal", errors);
72 assertEqualsList(cursor2.getValue(), cursor2.getValue(), title + ": Values not equal", errors);
73 cursor1.move();
74 cursor2.move();
75 }
76 if (!cursor2.isTerminated()) {
77 fail("cursor 1 terminated before cursor 2");
78 }
79 69
80 for (var mode : ContentHashCode.values()) { 70 for (var mode : ContentHashCode.values()) {
81 assertEqualsList(map1.contentHashCode(mode), map2.contentHashCode(mode), 71 assertEqualsList(map1.contentHashCode(mode), map2.contentHashCode(mode),
82 title + ": " + mode + " hashCode check", errors); 72 title + ": " + mode + " hashCode check", errors);
83 } 73 }
84 assertContentEqualsList(map1, map2, title + ": map1.contentEquals(map2)", errors);
85 assertContentEqualsList(map2, map1, title + ": map2.contentEquals(map1)", errors);
86 } 74 }
87 75
88 private static void assertEqualsList(Object o1, Object o2, String message, List<Throwable> errors) { 76 private static void assertEqualsList(Object o1, Object o2, String message, List<Throwable> errors) {
@@ -112,29 +100,35 @@ public class MapTestEnvironment<K, V> {
112 } 100 }
113 } 101 }
114 102
115 public VersionedMapImpl<K, V> sut; 103 final private VersionedMap<K, V> sut;
116 Map<K, V> oracle = new HashMap<K, V>(); 104 final private V defaultValue;
105 Map<K, V> oracle = new HashMap<>();
117 106
118 public MapTestEnvironment(VersionedMapImpl<K, V> sut) { 107 public MapTestEnvironment(VersionedMap<K, V> sut) {
119 this.sut = sut; 108 this.sut = sut;
109 this.defaultValue = sut.getDefaultValue();
120 } 110 }
121 111
122 public void put(K key, V value) { 112 public void put(K key, V value) {
123 V oldSutValue = sut.put(key, value); 113 V oldSutValue = sut.put(key, value);
124 V oldOracleValue; 114 V oldOracleValue;
125 if (value != sut.getDefaultValue()) { 115 if (value != defaultValue) {
126 oldOracleValue = oracle.put(key, value); 116 oldOracleValue = oracle.put(key, value);
127 } else { 117 } else {
128 oldOracleValue = oracle.remove(key); 118 oldOracleValue = oracle.remove(key);
129 } 119 }
130 if (oldSutValue == sut.getDefaultValue() && oldOracleValue != null) { 120 if (oldSutValue == defaultValue && oldOracleValue != null) {
131 fail("After put, SUT old nodeId was default, but oracle old value was " + oldOracleValue); 121 fail("After put, SUT old nodeId was default, but oracle old value was " + oldOracleValue);
132 } 122 }
133 if (oldSutValue != sut.getDefaultValue()) { 123 if (oldSutValue != defaultValue) {
134 assertEquals(oldOracleValue, oldSutValue); 124 assertEquals(oldOracleValue, oldSutValue);
135 } 125 }
136 } 126 }
137 127
128 public Version commit(){
129 return sut.commit();
130 }
131
138 public void checkEquivalence(String title) { 132 public void checkEquivalence(String title) {
139 // 0. Checking integrity 133 // 0. Checking integrity
140 try { 134 try {
@@ -181,7 +175,7 @@ public class MapTestEnvironment<K, V> {
181 long sutSize = sut.getSize(); 175 long sutSize = sut.getSize();
182 if (oracleSize != sutSize || oracleSize != elementsInSutEntrySet) { 176 if (oracleSize != sutSize || oracleSize != elementsInSutEntrySet) {
183 printComparison(); 177 printComparison();
184 fail(title + ": Non-equivalent size() result: SUT.getSize()=" + sutSize + ", SUT.entryset.size=" 178 fail(title + ": Non-equivalent size() result: SUT.getSize()=" + sutSize + ", SUT.entrySet.size="
185 + elementsInSutEntrySet + ", Oracle=" + oracleSize + "!"); 179 + elementsInSutEntrySet + ", Oracle=" + oracleSize + "!");
186 } 180 }
187 } 181 }
@@ -190,15 +184,15 @@ public class MapTestEnvironment<K, V> {
190 K previous = null; 184 K previous = null;
191 Cursor<K, V> cursor = versionedMap.getAll(); 185 Cursor<K, V> cursor = versionedMap.getAll();
192 while (cursor.move()) { 186 while (cursor.move()) {
193 System.out.println(cursor.getKey() + " " + ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().getHash(cursor.getKey(), 0)); 187 //System.out.println(cursor.getKey() + " " + ((VersionedMapImpl<K, V>) versionedMap).getHashProvider()
188 // .getHash(cursor.getKey(), 0));
194 if (previous != null) { 189 if (previous != null) {
195 int comparisonResult = ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().compare(previous, 190 int comparisonResult = ((VersionedMapStateImpl<K, V>) versionedMap).getHashProvider().compare(previous,
196 cursor.getKey()); 191 cursor.getKey());
197 assertTrue(comparisonResult < 0, scenario + " Cursor order is not incremental!"); 192 assertTrue(comparisonResult < 0, scenario + " Cursor order is not incremental!");
198 } 193 }
199 previous = cursor.getKey(); 194 previous = cursor.getKey();
200 } 195 }
201 System.out.println();
202 } 196 }
203 197
204 public void printComparison() { 198 public void printComparison() {
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java b/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java
index 4d4f5e26..5b595da7 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.store.model.hashtests; 6package tools.refinery.store.model.hashTests;
7 7
8import static org.junit.jupiter.api.Assertions.assertEquals; 8import static org.junit.jupiter.api.Assertions.assertEquals;
9 9
@@ -14,10 +14,9 @@ import java.util.Random;
14 14
15import org.junit.jupiter.api.Test; 15import org.junit.jupiter.api.Test;
16 16
17import tools.refinery.store.map.ContinousHashProvider; 17import tools.refinery.store.map.ContinuousHashProvider;
18import tools.refinery.store.tuple.Tuple; 18import tools.refinery.store.tuple.Tuple;
19import tools.refinery.store.model.TupleHashProvider; 19import tools.refinery.store.model.TupleHashProvider;
20import tools.refinery.store.model.TupleHashProviderBitMagic;
21 20
22class HashEfficiencyTest { 21class HashEfficiencyTest {
23 22
@@ -95,7 +94,7 @@ class HashEfficiencyTest {
95 List<Tuple> p = nRandoms(2, amount, 1);; 94 List<Tuple> p = nRandoms(2, amount, 1);;
96 assertEquals(amount,p.size()); 95 assertEquals(amount,p.size());
97 } 96 }
98 private static double calculateHashClashes(List<Tuple> tuples, ContinousHashProvider<Tuple> chp) { 97 private static double calculateHashClashes(List<Tuple> tuples, ContinuousHashProvider<Tuple> chp) {
99 int sumClashes = 0; 98 int sumClashes = 0;
100 99
101 for(int i = 0; i<tuples.size(); i++) { 100 for(int i = 0; i<tuples.size(); i++) {
@@ -108,7 +107,7 @@ class HashEfficiencyTest {
108 } 107 }
109 return (sumClashes+0.0) / tuples.size(); 108 return (sumClashes+0.0) / tuples.size();
110 } 109 }
111 private static int calculateHashClash(ContinousHashProvider<Tuple> chp, Tuple a, Tuple b) { 110 private static int calculateHashClash(ContinuousHashProvider<Tuple> chp, Tuple a, Tuple b) {
112 if(a.equals(b)) return 0; 111 if(a.equals(b)) return 0;
113 final int bits = 5; 112 final int bits = 5;
114 final int segments = Integer.SIZE/bits; 113 final int segments = Integer.SIZE/bits;
@@ -131,11 +130,9 @@ class HashEfficiencyTest {
131 } 130 }
132 public static void main(String[] args) { 131 public static void main(String[] args) {
133 List<String> hashNames = new LinkedList<>(); 132 List<String> hashNames = new LinkedList<>();
134 List<ContinousHashProvider<Tuple>> hashes = new LinkedList<>(); 133 List<ContinuousHashProvider<Tuple>> hashes = new LinkedList<>();
135 hashNames.add("PrimeGroup"); 134 hashNames.add("PrimeGroup");
136 hashes.add(new TupleHashProvider()); 135 hashes.add(new TupleHashProvider());
137 hashNames.add("BitMagic");
138 hashes.add(new TupleHashProviderBitMagic());
139 136
140 int[] arities = new int[] {2,3,4,5}; 137 int[] arities = new int[] {2,3,4,5};
141 int[] sizes = new int[] {32*32,32*32*8}; 138 int[] sizes = new int[] {32*32,32*32*8};
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java b/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
index 56b75804..dc7b776e 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
@@ -6,6 +6,7 @@
6package tools.refinery.store.model.tests; 6package tools.refinery.store.model.tests;
7 7
8import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
9import tools.refinery.store.map.Version;
9import tools.refinery.store.model.Model; 10import tools.refinery.store.model.Model;
10import tools.refinery.store.model.ModelStore; 11import tools.refinery.store.model.ModelStore;
11import tools.refinery.store.representation.Symbol; 12import tools.refinery.store.representation.Symbol;
@@ -120,7 +121,7 @@ class ModelTest {
120 assertTrue(model.hasUncommittedChanges()); 121 assertTrue(model.hasUncommittedChanges());
121 assertEquals(Model.NO_STATE_ID, model.getState()); 122 assertEquals(Model.NO_STATE_ID, model.getState());
122 123
123 long state1 = model.commit(); 124 Version state1 = model.commit();
124 125
125 assertFalse(model.hasUncommittedChanges()); 126 assertFalse(model.hasUncommittedChanges());
126 assertEquals(state1, model.getState()); 127 assertEquals(state1, model.getState());
@@ -134,7 +135,7 @@ class ModelTest {
134 assertTrue(model.hasUncommittedChanges()); 135 assertTrue(model.hasUncommittedChanges());
135 assertEquals(state1, model.getState()); 136 assertEquals(state1, model.getState());
136 137
137 long state2 = model.commit(); 138 Version state2 = model.commit();
138 139
139 assertFalse(model.hasUncommittedChanges()); 140 assertFalse(model.hasUncommittedChanges());
140 assertEquals(state2, model.getState()); 141 assertEquals(state2, model.getState());
diff --git a/subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java b/subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java
new file mode 100644
index 00000000..3c35849e
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java
@@ -0,0 +1,217 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.statecoding;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.map.Version;
10import tools.refinery.store.model.Model;
11import tools.refinery.store.model.ModelStore;
12import tools.refinery.store.representation.Symbol;
13import tools.refinery.store.statecoding.neighbourhood.ObjectCodeImpl;
14import tools.refinery.store.tuple.Tuple;
15
16import static org.junit.jupiter.api.Assertions.assertEquals;
17
18class EquivalenceTest {
19 Symbol<Boolean> person = new Symbol<>("Person", 1, Boolean.class, false);
20 Symbol<Integer> age = new Symbol<>("age", 1, Integer.class, null);
21 Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false);
22 Symbol<Boolean> parents = new Symbol<>("parents", 3, Boolean.class, false);
23 Symbol<Integer> population = new Symbol<>("population", 0, Integer.class, 0);
24
25 private ModelStore createStore() {
26 return ModelStore.builder()
27 .symbols(person, age, friend, parents, population)
28 .with(StateCoderAdapter.builder())
29 .build();
30 }
31
32 @Test
33 void emptyModelCode0() {
34 ModelStore store = createStore();
35 var stateCoder = store.getAdapter(StateCoderStoreAdapter.class);
36 Model model = createStore().createEmptyModel();
37 Version v1 = model.commit();
38 Version v2 = model.commit();
39
40 assertEquals(StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC, stateCoder.checkEquivalence(v1, v2));
41
42 var personI = model.getInterpretation(person);
43 var friendI = model.getInterpretation(friend);
44
45 personI.put(Tuple.of(1), true);
46 personI.put(Tuple.of(2), true);
47 friendI.put(Tuple.of(1, 2), true);
48
49 Version v3 = model.commit();
50
51 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v3));
52 }
53
54 @Test
55 void nullRelationTest() {
56 ModelStore store = createStore();
57 var stateCoder = store.getAdapter(StateCoderStoreAdapter.class);
58 Model model = createStore().createEmptyModel();
59
60 var populationI = model.getInterpretation(population);
61
62 Version v1 = model.commit();
63
64 populationI.put(Tuple.of(), 1);
65 Version v2 = model.commit();
66
67 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v2));
68
69 populationI.put(Tuple.of(), 2);
70 Version v3 = model.commit();
71
72 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v2, v3));
73 }
74
75 @Test
76 void unaryBooleanTest() {
77 ModelStore store = createStore();
78 var stateCoder = store.getAdapter(StateCoderStoreAdapter.class);
79 Model model = createStore().createEmptyModel();
80
81 var personI = model.getInterpretation(person);
82
83 Version v1 = model.commit();
84
85 personI.put(Tuple.of(1), true);
86 Version v2 = model.commit();
87
88 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v2));
89
90 personI.put(Tuple.of(2), true);
91 Version v3 = model.commit();
92
93 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v2, v3));
94
95 personI.put(Tuple.of(1), false);
96 Version v4 = model.commit();
97
98 assertEquals(StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC, stateCoder.checkEquivalence(v2, v4));
99 }
100
101 @Test
102 void unaryIntTest() {
103 ModelStore store = createStore();
104 var stateCoder = store.getAdapter(StateCoderStoreAdapter.class);
105 Model model = createStore().createEmptyModel();
106
107 var ageI = model.getInterpretation(age);
108
109 ageI.put(Tuple.of(1), 3);
110 Version v1 = model.commit();
111
112 ageI.put(Tuple.of(1), 4);
113 Version v2 = model.commit();
114
115 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v2));
116
117 ageI.put(Tuple.of(2), 4);
118 Version v3 = model.commit();
119
120 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v2, v3));
121
122 ageI.put(Tuple.of(1), null);
123 Version v4 = model.commit();
124
125 assertEquals(StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC, stateCoder.checkEquivalence(v2, v4));
126 }
127
128 @Test
129 void binaryTest() {
130 ModelStore store = createStore();
131 var stateCoder = store.getAdapter(StateCoderStoreAdapter.class);
132 Model model = createStore().createEmptyModel();
133
134 var friendI = model.getInterpretation(friend);
135
136 Version v1 = model.commit();
137
138 friendI.put(Tuple.of(1, 2), true);
139 Version v2 = model.commit();
140
141 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v2));
142
143 friendI.put(Tuple.of(2, 1), true);
144 Version v3 = model.commit();
145
146 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v2, v3));
147
148 friendI.put(Tuple.of(1, 2), false);
149 Version v4 = model.commit();
150
151 assertEquals(StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC, stateCoder.checkEquivalence(v2, v4));
152 }
153
154 @Test
155 void NaryTest() {
156 ModelStore store = createStore();
157 var stateCoder = store.getAdapter(StateCoderStoreAdapter.class);
158 Model model = createStore().createEmptyModel();
159
160 var parentsI = model.getInterpretation(parents);
161
162 Version v1 = model.commit();
163
164 parentsI.put(Tuple.of(3, 1, 2), true);
165 Version v2 = model.commit();
166
167 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v2));
168
169 parentsI.put(Tuple.of(4, 1, 2), true);
170 Version v3 = model.commit();
171
172 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v2, v3));
173
174 parentsI.put(Tuple.of(3, 1, 2), false);
175 Version v4 = model.commit();
176
177 assertEquals(StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC, stateCoder.checkEquivalence(v2, v4));
178 }
179
180 @Test
181 void largeUnknownTest() {
182 final int limit = 100;
183
184 StateCodeCalculator calculator = () -> {
185 var code = new ObjectCodeImpl();
186 for (int i = 0; i < limit; i++) {
187 code.set(i, 1);
188 }
189 return new StateCoderResult(1, code);
190 };
191
192 ModelStore store = ModelStore.builder()
193 .symbols(person, age, friend, parents, population)
194 .with(StateCoderAdapter.builder()
195 .stateCodeCalculatorFactory((p1, p2) -> calculator))
196 .build();
197
198 var stateCoder = store.getAdapter(StateCoderStoreAdapter.class);
199 Model model = createStore().createEmptyModel();
200
201 var personI = model.getInterpretation(person);
202 var friendI = model.getInterpretation(friend);
203
204 for (int i = 0; i < limit; i++) {
205 personI.put(Tuple.of(i), true);
206 }
207
208 friendI.put(Tuple.of(11,12),true);
209 var v1 = model.commit();
210
211 friendI.put(Tuple.of(11,12),false);
212 friendI.put(Tuple.of(21,22),false);
213 var v2 = model.commit();
214
215 assertEquals(StateEquivalenceChecker.EquivalenceResult.UNKNOWN, stateCoder.checkEquivalence(v1,v2));
216 }
217}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/statecoding/ExperimentalSetupTest.java b/subprojects/store/src/test/java/tools/refinery/store/statecoding/ExperimentalSetupTest.java
new file mode 100644
index 00000000..f5ffc18d
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/statecoding/ExperimentalSetupTest.java
@@ -0,0 +1,199 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.statecoding;
7
8import org.eclipse.collections.api.factory.primitive.IntObjectMaps;
9import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
10import org.junit.jupiter.api.Tag;
11import org.junit.jupiter.api.Test;
12import org.junit.jupiter.params.ParameterizedTest;
13import org.junit.jupiter.params.provider.ValueSource;
14import tools.refinery.store.map.Version;
15import tools.refinery.store.model.Model;
16import tools.refinery.store.model.ModelStore;
17import tools.refinery.store.representation.Symbol;
18import tools.refinery.store.tuple.Tuple;
19
20import java.util.ArrayList;
21import java.util.HashSet;
22import java.util.List;
23import java.util.Set;
24
25import static org.junit.jupiter.api.Assertions.assertEquals;
26import static org.junit.jupiter.api.Assertions.assertTrue;
27
28class ExperimentalSetupTest {
29 static class ExperimentalSetupResult {
30 int versions = 0;
31 int different = 0;
32 int isomorphic = 0;
33 int unknown = 0;
34
35 double failureRatio() {
36 return (different + 0.0) / versions;
37 }
38
39 @Override
40 public String toString() {
41 return "ExperimentalSetupResult{" +
42 "versions=" + versions +
43 ", different=" + different +
44 ", isomorphic=" + isomorphic +
45 ", unknown=" + unknown +
46 ", ratio= " + failureRatio() +
47 '}';
48 }
49 }
50
51 static int MAX = 100000;
52
53 public static ExperimentalSetupResult generate(int size, boolean permuteTypes) {
54 Symbol<Boolean> person = new Symbol<>("Person", 1, Boolean.class, false);
55 Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false);
56
57 var store = ModelStore.builder()
58 .symbols(person, friend)
59 .with(StateCoderAdapter
60 .builder())
61 .build();
62
63 Set<Version> versions = new HashSet<>();
64 MutableIntObjectMap<List<Version>> codes = IntObjectMaps.mutable.empty();
65
66 var empty = store.createEmptyModel();
67 if (!permuteTypes) {
68 for (int i = 0; i < size; i++) {
69 empty.getInterpretation(person).put(Tuple.of(i), true);
70 }
71 }
72
73 var emptyVersion = empty.commit();
74 versions.add(emptyVersion);
75 var emptyCode = empty.getAdapter(StateCoderAdapter.class).calculateModelCode();
76 List<Version> emptyList = new ArrayList<>();
77 emptyList.add(emptyVersion);
78 codes.put(emptyCode, emptyList);
79
80 var storeAdapter = store.getAdapter(StateCoderStoreAdapter.class);
81 var result = new ExperimentalSetupResult();
82
83 int steps = 0;
84
85 if (permuteTypes) {
86 for (int i = 0; i < size; i++) {
87 var previousVersions = new HashSet<>(versions);
88 for (var version : previousVersions) {
89 var model = store.createModelForState(version);
90 model.getInterpretation(person).put(Tuple.of(i), true);
91
92 saveAsNewVersion(versions, codes, storeAdapter, result, model);
93
94 logProgress(steps++);
95 if (steps > MAX) {
96 result.versions = versions.size();
97 return result;
98 }
99 }
100 }
101 }
102
103 for (int i = 0; i < size; i++) {
104 for (int j = 0; j < size; j++) {
105 var previousVersions = new HashSet<>(versions);
106 for (var version : previousVersions) {
107
108 var model = store.createModelForState(version);
109 model.getInterpretation(friend).put(Tuple.of(i, j), true);
110
111 saveAsNewVersion(versions, codes, storeAdapter, result, model);
112
113 logProgress(steps++);
114 if (steps > MAX) {
115 result.versions = versions.size();
116 return result;
117 }
118 }
119 }
120 }
121
122 result.versions = versions.size();
123 return result;
124 }
125
126 private static void saveAsNewVersion(Set<Version> versions, MutableIntObjectMap<List<Version>> codes,
127 StateCoderStoreAdapter storeAdapter, ExperimentalSetupResult result,
128 Model model) {
129 Version version1 = model.commit();
130
131 var stateCode = model.getAdapter(StateCoderAdapter.class).calculateStateCode();
132 int code = stateCode.modelCode();
133 if (codes.containsKey(code)) {
134 Version similar = codes.get(code).get(0);
135
136 var outcome = storeAdapter.checkEquivalence(version1, similar);
137 if (outcome == StateEquivalenceChecker.EquivalenceResult.DIFFERENT) {
138 result.different++;
139 } else if (outcome == StateEquivalenceChecker.EquivalenceResult.UNKNOWN) {
140 result.unknown++;
141 } else {
142 result.isomorphic++;
143 }
144 } else {
145 versions.add(version1);
146
147 List<Version> newList = new ArrayList<>();
148 newList.add(version1);
149 codes.put(code, newList);
150 }
151 }
152
153 private static void logProgress(int steps) {
154 if (steps % 10000 == 0) {
155 System.out.println("Steps: " + steps + " / " + MAX);
156 }
157 }
158
159 static final double limit = 0.01;
160
161 @Test
162 void test0() {
163 assertEquals(1, generate(0, true).versions);
164 }
165
166 @ParameterizedTest
167 @ValueSource(ints = {1, 2, 3, 4})
168 void testForSmallUntypedModels(int size) {
169 var res = generate(size, false);
170 System.out.println(res);
171 assertTrue(res.failureRatio() < limit);
172 }
173
174 @ParameterizedTest
175 @ValueSource(ints = {1, 2, 3})
176 void testForSmallTypedModels(int size) {
177 var res = generate(size, true);
178 System.out.println(res);
179 assertTrue(res.failureRatio() < limit);
180 }
181
182 @Test
183 @Tag("fuzz")
184 @Tag("slow")
185 void testForLargeTypedModels() {
186 var res = generate(10, true);
187 System.out.println(res);
188 assertTrue(res.failureRatio() < limit);
189 }
190
191 @Test
192 @Tag("fuzz")
193 @Tag("slow")
194 void testForLargeUntypedModels() {
195 var res = generate(10, false);
196 System.out.println(res);
197 assertTrue(res.failureRatio() < limit);
198 }
199}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java b/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java
new file mode 100644
index 00000000..0b738005
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java
@@ -0,0 +1,171 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.statecoding;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.model.Interpretation;
10import tools.refinery.store.model.ModelStore;
11import tools.refinery.store.representation.Symbol;
12import tools.refinery.store.tuple.Tuple;
13
14import static org.junit.jupiter.api.Assertions.*;
15
16class StateCoderBuildTest {
17 Symbol<Boolean> person = new Symbol<>("Person", 1, Boolean.class, false);
18 Symbol<Integer> age = new Symbol<>("age", 1, Integer.class, null);
19 Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false);
20
21 @Test
22 void simpleStateCoderBuildTest() {
23 var store = ModelStore.builder()
24 .symbols(person, age, friend)
25 .with(StateCoderAdapter.builder())
26 .build();
27
28 var model = store.createEmptyModel();
29 var stateCoder = model.getAdapter(StateCoderAdapter.class);
30 assertNotNull(stateCoder);
31
32 var personI = model.getInterpretation(person);
33 var friendI = model.getInterpretation(friend);
34 var ageI = model.getInterpretation(age);
35
36 fill(personI, friendI, ageI);
37
38 stateCoder.calculateStateCode();
39 }
40
41 @Test
42 void excludeTest() {
43 var store = ModelStore.builder()
44 .symbols(person, age, friend)
45 .with(StateCoderAdapter.builder()
46 .exclude(person)
47 .exclude(age))
48 .build();
49
50 var model = store.createEmptyModel();
51 var stateCoder = model.getAdapter(StateCoderAdapter.class);
52 assertNotNull(stateCoder);
53
54 var personI = model.getInterpretation(person);
55 var friendI = model.getInterpretation(friend);
56 var ageI = model.getInterpretation(age);
57 fill(personI, friendI, ageI);
58
59 int code = stateCoder.calculateStateCode().modelCode();
60
61 ageI.put(Tuple.of(1), 3);
62 assertEquals(code, stateCoder.calculateStateCode().modelCode());
63
64 ageI.put(Tuple.of(1), null);
65 assertEquals(code, stateCoder.calculateStateCode().modelCode());
66
67 personI.put(Tuple.of(2), false);
68 assertEquals(code, stateCoder.calculateStateCode().modelCode());
69 }
70
71 @Test
72 void notIndividualTest() {
73 var store = ModelStore.builder()
74 .symbols(friend)
75 .with(StateCoderAdapter.builder())
76 .build();
77
78 var model = store.createEmptyModel();
79 var stateCoder = model.getAdapter(StateCoderAdapter.class);
80
81 var friendI = model.getInterpretation(friend);
82
83 friendI.put(Tuple.of(1, 2), true);
84 int code1 = stateCoder.calculateModelCode();
85
86 friendI.put(Tuple.of(1, 2), false);
87 friendI.put(Tuple.of(2, 1), true);
88 int code2 = stateCoder.calculateModelCode();
89
90 assertEquals(code1, code2);
91 }
92
93 @Test
94 void individualTest() {
95 var store = ModelStore.builder()
96 .symbols(friend)
97 .with(StateCoderAdapter.builder()
98 .individual(Tuple.of(1)))
99 .build();
100
101 var model = store.createEmptyModel();
102 var stateCoder = model.getAdapter(StateCoderAdapter.class);
103
104 var friendI = model.getInterpretation(friend);
105
106 friendI.put(Tuple.of(1, 2), true);
107 int code1 = stateCoder.calculateModelCode();
108
109 friendI.put(Tuple.of(1, 2), false);
110 friendI.put(Tuple.of(2, 1), true);
111 int code2 = stateCoder.calculateModelCode();
112
113 assertNotEquals(code1, code2);
114 }
115
116 @Test
117 void customStateCoderTest() {
118 final boolean[] called = new boolean[]{false};
119 StateCodeCalculator mock = () -> {
120 called[0] = true;
121 return null;
122 };
123
124 var store = ModelStore.builder()
125 .symbols(friend)
126 .with(StateCoderAdapter.builder()
127 .stateCodeCalculatorFactory((interpretations, individuals) -> mock))
128 .build();
129
130 var model = store.createEmptyModel();
131 var stateCoder = model.getAdapter(StateCoderAdapter.class);
132
133 stateCoder.calculateStateCode();
134
135 assertTrue(called[0]);
136 }
137
138 @Test
139 void customEquivalenceCheckerTest() {
140 final boolean[] called = new boolean[]{false};
141 StateEquivalenceChecker mock = (p1, p2, p3, p4, p5) -> {
142 called[0] = true;
143 return StateEquivalenceChecker.EquivalenceResult.UNKNOWN;
144 };
145
146 var store = ModelStore.builder()
147 .symbols(friend)
148 .with(StateCoderAdapter.builder()
149 .stateEquivalenceChecker(mock))
150 .build();
151
152 var model = store.createEmptyModel();
153 var v1 = model.commit();
154 var v2 = model.commit();
155
156 store.getAdapter(StateCoderStoreAdapter.class).checkEquivalence(v1, v2);
157
158 assertTrue(called[0]);
159 }
160
161
162 private static void fill(Interpretation<Boolean> personI, Interpretation<Boolean> friendI, Interpretation<Integer> ageI) {
163 personI.put(Tuple.of(1), true);
164 personI.put(Tuple.of(2), true);
165
166 ageI.put(Tuple.of(1), 5);
167 ageI.put(Tuple.of(2), 4);
168
169 friendI.put(Tuple.of(1, 2), true);
170 }
171}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderUnitTest.java b/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderUnitTest.java
new file mode 100644
index 00000000..d94df841
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderUnitTest.java
@@ -0,0 +1,195 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.statecoding;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.model.Model;
10import tools.refinery.store.model.ModelStore;
11import tools.refinery.store.representation.Symbol;
12import tools.refinery.store.tuple.Tuple;
13
14import java.util.Objects;
15
16import static org.junit.jupiter.api.Assertions.*;
17
18class StateCoderUnitTest {
19 Symbol<Boolean> person = new Symbol<>("Person", 1, Boolean.class, false);
20 Symbol<Integer> age = new Symbol<>("age", 1, Integer.class, null);
21 Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false);
22 Symbol<Boolean> parents = new Symbol<>("parents", 3, Boolean.class, false);
23 Symbol<Integer> population = new Symbol<>("population", 0, Integer.class, 0);
24
25 private Model createEmptyModel() {
26 var store = ModelStore.builder()
27 .symbols(person, age, friend, parents, population)
28 .with(StateCoderAdapter.builder())
29 .build();
30
31 return store.createEmptyModel();
32 }
33
34 @Test
35 void emptyModelCode0() {
36 Model model = createEmptyModel();
37 var stateCoder = model.getAdapter(StateCoderAdapter.class);
38
39 assertEquals(0, stateCoder.calculateModelCode());
40
41 var personI = model.getInterpretation(person);
42 var friendI = model.getInterpretation(friend);
43
44 personI.put(Tuple.of(1), true);
45 personI.put(Tuple.of(2), true);
46 friendI.put(Tuple.of(1, 2), true);
47
48 assertNotEquals(0, stateCoder.calculateModelCode());
49 }
50
51 @Test
52 void emptyObjectCode0() {
53 Model model = createEmptyModel();
54 var stateCoder = model.getAdapter(StateCoderAdapter.class);
55
56 var personI = model.getInterpretation(person);
57 var friendI = model.getInterpretation(friend);
58
59 assertEquals(0, stateCoder.calculateObjectCode().get(1));
60 assertEquals(0, stateCoder.calculateObjectCode().get(17));
61
62 personI.put(Tuple.of(1), true);
63 personI.put(Tuple.of(2), true);
64 friendI.put(Tuple.of(1, 2), true);
65
66 assertNotEquals(0, stateCoder.calculateObjectCode().get(1));
67 assertEquals(0, stateCoder.calculateObjectCode().get(17));
68 }
69
70 @Test
71 void nullRelationTest() {
72 Model model = createEmptyModel();
73 var stateCoder = model.getAdapter(StateCoderAdapter.class);
74
75 var populationI = model.getInterpretation(population);
76
77 final int hashOf0 = Objects.hashCode(0);
78
79 assertEquals(hashOf0, stateCoder.calculateModelCode());
80
81 populationI.put(Tuple.of(), 1);
82 int code1 = stateCoder.calculateModelCode();
83
84 assertNotEquals(hashOf0, stateCoder.calculateModelCode());
85
86 populationI.put(Tuple.of(), 2);
87 int code2 = stateCoder.calculateModelCode();
88
89 assertNotEquals(code1, code2);
90
91 populationI.put(Tuple.of(), 1);
92 assertEquals(code1, stateCoder.calculateModelCode());
93 }
94
95 @Test
96 void unaryBooleanTest() {
97 Model model = createEmptyModel();
98 var stateCoder = model.getAdapter(StateCoderAdapter.class);
99
100 var personI = model.getInterpretation(person);
101
102 assertEquals(0, stateCoder.calculateModelCode());
103
104 personI.put(Tuple.of(1), true);
105 int code1 = stateCoder.calculateModelCode();
106
107 assertNotEquals(0, stateCoder.calculateModelCode());
108
109 personI.put(Tuple.of(2), true);
110 int code2 = stateCoder.calculateModelCode();
111
112 assertNotEquals(code1, code2);
113
114 personI.put(Tuple.of(1), false);
115 assertEquals(code1, stateCoder.calculateModelCode());
116 }
117
118 @Test
119 void unaryIntTest() {
120 Model model = createEmptyModel();
121 var stateCoder = model.getAdapter(StateCoderAdapter.class);
122
123 var ageI = model.getInterpretation(age);
124
125 assertEquals(0, stateCoder.calculateModelCode());
126
127 ageI.put(Tuple.of(1), 4);
128 int code0 = stateCoder.calculateModelCode();
129
130 assertNotEquals(0, code0);
131
132 ageI.put(Tuple.of(1), 5);
133 int code1 = stateCoder.calculateModelCode();
134
135 assertNotEquals(code0, code1);
136
137 ageI.put(Tuple.of(2), 5);
138 int code2 = stateCoder.calculateModelCode();
139
140 assertNotEquals(code1, code2);
141
142 ageI.put(Tuple.of(1), null);
143 assertEquals(code1, stateCoder.calculateModelCode());
144 }
145
146 @Test
147 void binaryTest() {
148 Model model = createEmptyModel();
149 var stateCoder = model.getAdapter(StateCoderAdapter.class);
150
151 var friendI = model.getInterpretation(friend);
152
153 assertEquals(0, stateCoder.calculateModelCode());
154
155 friendI.put(Tuple.of(1, 2), true);
156 int code1 = stateCoder.calculateModelCode();
157
158 assertNotEquals(0, code1);
159
160 friendI.put(Tuple.of(2, 1), true);
161 int code2 = stateCoder.calculateModelCode();
162
163 assertNotEquals(code1, code2);
164
165 friendI.put(Tuple.of(1, 2), false);
166 int code3 = stateCoder.calculateModelCode();
167
168 assertEquals(code1, code3);
169 }
170
171 @Test
172 void NaryTest() {
173 Model model = createEmptyModel();
174 var stateCoder = model.getAdapter(StateCoderAdapter.class);
175
176 var parentsI = model.getInterpretation(parents);
177
178 assertEquals(0, stateCoder.calculateModelCode());
179
180 parentsI.put(Tuple.of(3, 1, 2), true);
181 int code1 = stateCoder.calculateModelCode();
182
183 assertNotEquals(0, code1);
184
185 parentsI.put(Tuple.of(4, 1, 2), true);
186 int code2 = stateCoder.calculateModelCode();
187
188 assertNotEquals(code1, code2);
189
190 parentsI.put(Tuple.of(3, 1, 2), false);
191 int code3 = stateCoder.calculateModelCode();
192
193 assertEquals(code1, code3);
194 }
195}