diff options
Diffstat (limited to 'store/src/test/java/org/eclipse/viatra')
16 files changed, 1732 insertions, 0 deletions
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/CommitFuzzTest.java b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/CommitFuzzTest.java new file mode 100644 index 00000000..e160df2b --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/CommitFuzzTest.java | |||
@@ -0,0 +1,95 @@ | |||
1 | package org.eclipse.viatra.solver.data.map.tests.fuzz; | ||
2 | |||
3 | import static org.junit.jupiter.api.Assertions.fail; | ||
4 | |||
5 | import java.util.Random; | ||
6 | import java.util.stream.Stream; | ||
7 | |||
8 | import org.eclipse.viatra.solver.data.map.ContinousHashProvider; | ||
9 | import org.eclipse.viatra.solver.data.map.VersionedMapStore; | ||
10 | import org.eclipse.viatra.solver.data.map.VersionedMapStoreImpl; | ||
11 | import org.eclipse.viatra.solver.data.map.internal.VersionedMapImpl; | ||
12 | import org.eclipse.viatra.solver.data.map.tests.fuzz.utils.FuzzTestUtils; | ||
13 | import org.eclipse.viatra.solver.data.map.tests.utils.MapTestEnvironment; | ||
14 | import org.junit.jupiter.api.Tag; | ||
15 | import org.junit.jupiter.api.Timeout; | ||
16 | import org.junit.jupiter.params.ParameterizedTest; | ||
17 | import org.junit.jupiter.params.provider.Arguments; | ||
18 | import org.junit.jupiter.params.provider.MethodSource; | ||
19 | |||
20 | class CommitFuzzTest { | ||
21 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | ||
22 | boolean evilHash) { | ||
23 | String[] values = MapTestEnvironment.prepareValues(maxValue); | ||
24 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | ||
25 | |||
26 | VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | ||
27 | VersionedMapImpl<Integer, String> sut = (VersionedMapImpl<Integer, String>) store.createMap(); | ||
28 | MapTestEnvironment<Integer, String> e = new MapTestEnvironment<Integer, String>(sut); | ||
29 | |||
30 | Random r = new Random(seed); | ||
31 | |||
32 | iterativeRandomPutsAndCommits(scenario, steps, maxKey, values, e, r, commitFrequency); | ||
33 | } | ||
34 | |||
35 | private void iterativeRandomPutsAndCommits(String scenario, int steps, int maxKey, String[] values, | ||
36 | MapTestEnvironment<Integer, String> e, Random r, int commitFrequency) { | ||
37 | int stopAt = -1; | ||
38 | for (int i = 0; i < steps; i++) { | ||
39 | int index = i + 1; | ||
40 | int nextKey = r.nextInt(maxKey); | ||
41 | String nextValue = values[r.nextInt(values.length)]; | ||
42 | if (index == stopAt) { | ||
43 | System.out.println("issue!"); | ||
44 | System.out.println("State before:"); | ||
45 | e.printComparison(); | ||
46 | e.sut.prettyPrint(); | ||
47 | System.out.println("Next: put(" + nextKey + "," + nextValue + ")"); | ||
48 | } | ||
49 | try { | ||
50 | e.put(nextKey, nextValue); | ||
51 | if (index == stopAt) { | ||
52 | e.sut.prettyPrint(); | ||
53 | } | ||
54 | e.checkEquivalence(scenario + ":" + index); | ||
55 | } catch (Exception exception) { | ||
56 | exception.printStackTrace(); | ||
57 | fail(scenario + ":" + index + ": exception happened: " + exception); | ||
58 | } | ||
59 | MapTestEnvironment.printStatus(scenario, index, steps, null); | ||
60 | if (index % commitFrequency == 0) { | ||
61 | e.sut.commit(); | ||
62 | } | ||
63 | } | ||
64 | } | ||
65 | |||
66 | @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
67 | @MethodSource | ||
68 | @Timeout(value = 10) | ||
69 | @Tag("fuzz") | ||
70 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
71 | boolean evilHash) { | ||
72 | runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | ||
73 | commitFrequency, evilHash); | ||
74 | } | ||
75 | |||
76 | static Stream<Arguments> parametrizedFastFuzz() { | ||
77 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | ||
78 | new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, | ||
79 | new Object[] { false, true }); | ||
80 | } | ||
81 | |||
82 | @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
83 | @MethodSource | ||
84 | @Tag("fuzz") | ||
85 | @Tag("slow") | ||
86 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
87 | boolean evilHash) { | ||
88 | runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | ||
89 | commitFrequency, evilHash); | ||
90 | } | ||
91 | |||
92 | static Stream<Arguments> parametrizedSlowFuzz() { | ||
93 | return FuzzTestUtils.changeStepCount(parametrizedFastFuzz(), 1); | ||
94 | } | ||
95 | } | ||
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/ContentEqualsFuzzTest.java b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/ContentEqualsFuzzTest.java new file mode 100644 index 00000000..5004c152 --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/ContentEqualsFuzzTest.java | |||
@@ -0,0 +1,142 @@ | |||
1 | package org.eclipse.viatra.solver.data.map.tests.fuzz; | ||
2 | |||
3 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
4 | import static org.junit.jupiter.api.Assertions.fail; | ||
5 | |||
6 | import java.util.AbstractMap.SimpleEntry; | ||
7 | import java.util.Collections; | ||
8 | import java.util.LinkedList; | ||
9 | import java.util.List; | ||
10 | import java.util.Random; | ||
11 | import java.util.stream.Stream; | ||
12 | |||
13 | import org.eclipse.viatra.solver.data.map.ContinousHashProvider; | ||
14 | import org.eclipse.viatra.solver.data.map.Cursor; | ||
15 | import org.eclipse.viatra.solver.data.map.VersionedMap; | ||
16 | import org.eclipse.viatra.solver.data.map.VersionedMapStore; | ||
17 | import org.eclipse.viatra.solver.data.map.VersionedMapStoreImpl; | ||
18 | import org.eclipse.viatra.solver.data.map.internal.VersionedMapImpl; | ||
19 | import org.eclipse.viatra.solver.data.map.tests.fuzz.utils.FuzzTestUtils; | ||
20 | import org.eclipse.viatra.solver.data.map.tests.utils.MapTestEnvironment; | ||
21 | import org.junit.jupiter.api.Tag; | ||
22 | import org.junit.jupiter.api.Timeout; | ||
23 | import org.junit.jupiter.params.ParameterizedTest; | ||
24 | import org.junit.jupiter.params.provider.Arguments; | ||
25 | import org.junit.jupiter.params.provider.MethodSource; | ||
26 | |||
27 | class ContentEqualsFuzzTest { | ||
28 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | ||
29 | boolean evilHash) { | ||
30 | String[] values = MapTestEnvironment.prepareValues(maxValue); | ||
31 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | ||
32 | |||
33 | Random r = new Random(seed); | ||
34 | |||
35 | iterativeRandomPutsAndCommitsThenCompare(scenario, chp, steps, maxKey, values, r, commitFrequency); | ||
36 | } | ||
37 | |||
38 | private void iterativeRandomPutsAndCommitsThenCompare(String scenario, ContinousHashProvider<Integer> chp, int steps, int maxKey, String[] values, Random r, int commitFrequency) { | ||
39 | |||
40 | VersionedMapStore<Integer, String> store1 = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | ||
41 | VersionedMap<Integer, String> sut1 = store1.createMap(); | ||
42 | |||
43 | // Fill one map | ||
44 | for (int i = 0; i < steps; i++) { | ||
45 | int index1 = i + 1; | ||
46 | int nextKey = r.nextInt(maxKey); | ||
47 | String nextValue = values[r.nextInt(values.length)]; | ||
48 | try { | ||
49 | sut1.put(nextKey, nextValue); | ||
50 | } catch (Exception exception) { | ||
51 | exception.printStackTrace(); | ||
52 | fail(scenario + ":" + index1 + ": exception happened: " + exception); | ||
53 | } | ||
54 | MapTestEnvironment.printStatus(scenario, index1, steps, "Fill"); | ||
55 | if (index1 % commitFrequency == 0) { | ||
56 | sut1.commit(); | ||
57 | } | ||
58 | } | ||
59 | |||
60 | // Get the content of the first map | ||
61 | List<SimpleEntry<Integer, String>> content = new LinkedList<>(); | ||
62 | Cursor<Integer, String> cursor = sut1.getAll(); | ||
63 | while (cursor.move()) { | ||
64 | content.add(new SimpleEntry<>(cursor.getKey(), cursor.getValue())); | ||
65 | } | ||
66 | |||
67 | // Randomize the order of the content | ||
68 | Collections.shuffle(content, r); | ||
69 | |||
70 | VersionedMapStore<Integer, String> store2 = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | ||
71 | VersionedMap<Integer, String> sut2 = store2.createMap(); | ||
72 | int index2 = 1; | ||
73 | for (SimpleEntry<Integer, String> entry : content) { | ||
74 | sut2.put(entry.getKey(), entry.getValue()); | ||
75 | if(index2++%commitFrequency == 0) | ||
76 | sut2.commit(); | ||
77 | } | ||
78 | |||
79 | // Check the integrity of the maps | ||
80 | ((VersionedMapImpl<Integer,String>) sut1).checkIntegrity(); | ||
81 | ((VersionedMapImpl<Integer,String>) sut2).checkIntegrity(); | ||
82 | |||
83 | // // Compare the two maps | ||
84 | // By size | ||
85 | assertEquals(sut1.getSize(), content.size()); | ||
86 | assertEquals(sut2.getSize(), content.size()); | ||
87 | |||
88 | |||
89 | |||
90 | // By cursors | ||
91 | Cursor<Integer, String> cursor1 = sut1.getAll(); | ||
92 | Cursor<Integer, String> cursor2 = sut2.getAll(); | ||
93 | int index3 = 1; | ||
94 | boolean canMove = true; | ||
95 | do{ | ||
96 | boolean canMove1 = cursor1.move(); | ||
97 | boolean canMove2 = cursor2.move(); | ||
98 | assertEquals(canMove1, canMove2, scenario + ":" + index3 +" Cursors stopped at different times!"); | ||
99 | assertEquals(cursor1.getKey(), cursor2.getKey(), scenario + ":" + index3 +" Cursors have different keys!"); | ||
100 | assertEquals(cursor1.getValue(), cursor2.getValue(), scenario + ":" + index3 +" Cursors have different values!"); | ||
101 | |||
102 | canMove = canMove1; | ||
103 | MapTestEnvironment.printStatus(scenario, index3++, content.size(), "Compare"); | ||
104 | } while (canMove); | ||
105 | |||
106 | // By hashcode | ||
107 | assertEquals(sut1.hashCode(), sut2.hashCode(), "Hash codes are not equal!"); | ||
108 | |||
109 | // By equals | ||
110 | assertEquals(sut1, sut2, "Maps are not equals"); | ||
111 | } | ||
112 | |||
113 | @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
114 | @MethodSource | ||
115 | @Timeout(value = 10) | ||
116 | @Tag("fuzz") | ||
117 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
118 | boolean evilHash) { | ||
119 | runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | ||
120 | commitFrequency, evilHash); | ||
121 | } | ||
122 | |||
123 | static Stream<Arguments> parametrizedFastFuzz() { | ||
124 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | ||
125 | new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, | ||
126 | new Object[] { false, true }); | ||
127 | } | ||
128 | |||
129 | @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
130 | @MethodSource | ||
131 | @Tag("fuzz") | ||
132 | @Tag("slow") | ||
133 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
134 | boolean evilHash) { | ||
135 | runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | ||
136 | commitFrequency, evilHash); | ||
137 | } | ||
138 | |||
139 | static Stream<Arguments> parametrizedSlowFuzz() { | ||
140 | return FuzzTestUtils.changeStepCount(parametrizedFastFuzz(), 1); | ||
141 | } | ||
142 | } | ||
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/DiffCursorFuzzTest.java b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/DiffCursorFuzzTest.java new file mode 100644 index 00000000..4b79a98a --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/DiffCursorFuzzTest.java | |||
@@ -0,0 +1,116 @@ | |||
1 | package org.eclipse.viatra.solver.data.map.tests.fuzz; | ||
2 | |||
3 | import static org.junit.jupiter.api.Assertions.fail; | ||
4 | |||
5 | import java.util.Random; | ||
6 | import java.util.stream.Stream; | ||
7 | |||
8 | import org.eclipse.viatra.solver.data.map.ContinousHashProvider; | ||
9 | import org.eclipse.viatra.solver.data.map.DiffCursor; | ||
10 | import org.eclipse.viatra.solver.data.map.VersionedMapStore; | ||
11 | import org.eclipse.viatra.solver.data.map.VersionedMapStoreImpl; | ||
12 | import org.eclipse.viatra.solver.data.map.internal.VersionedMapImpl; | ||
13 | import org.eclipse.viatra.solver.data.map.tests.fuzz.utils.FuzzTestUtils; | ||
14 | import org.eclipse.viatra.solver.data.map.tests.utils.MapTestEnvironment; | ||
15 | import org.junit.jupiter.api.Tag; | ||
16 | import org.junit.jupiter.api.Timeout; | ||
17 | import org.junit.jupiter.params.ParameterizedTest; | ||
18 | import org.junit.jupiter.params.provider.Arguments; | ||
19 | import org.junit.jupiter.params.provider.MethodSource; | ||
20 | |||
21 | class DiffCursorFuzzTest { | ||
22 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | ||
23 | boolean evilHash) { | ||
24 | String[] values = MapTestEnvironment.prepareValues(maxValue); | ||
25 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | ||
26 | |||
27 | VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | ||
28 | iterativeRandomPutsAndCommitsThenDiffcursor(scenario, store, steps, maxKey, values, seed, commitFrequency); | ||
29 | } | ||
30 | |||
31 | private void iterativeRandomPutsAndCommitsThenDiffcursor(String scenario, VersionedMapStore<Integer, String> store, | ||
32 | int steps, int maxKey, String[] values, int seed, int commitFrequency) { | ||
33 | // 1. build a map with versions | ||
34 | Random r = new Random(seed); | ||
35 | VersionedMapImpl<Integer, String> versioned = (VersionedMapImpl<Integer, String>) store.createMap(); | ||
36 | int largestCommit = -1; | ||
37 | |||
38 | for (int i = 0; i < steps; i++) { | ||
39 | int index = i + 1; | ||
40 | int nextKey = r.nextInt(maxKey); | ||
41 | String nextValue = values[r.nextInt(values.length)]; | ||
42 | try { | ||
43 | versioned.put(nextKey, nextValue); | ||
44 | } catch (Exception exception) { | ||
45 | exception.printStackTrace(); | ||
46 | fail(scenario + ":" + index + ": exception happened: " + exception); | ||
47 | } | ||
48 | if (index % commitFrequency == 0) { | ||
49 | long version = versioned.commit(); | ||
50 | largestCommit = (int) version; | ||
51 | } | ||
52 | if (index % 10000 == 0) | ||
53 | System.out.println(scenario + ":" + index + "/" + steps + " building finished"); | ||
54 | } | ||
55 | // 2. create a non-versioned map, | ||
56 | VersionedMapImpl<Integer, String> moving = (VersionedMapImpl<Integer, String>) store.createMap(); | ||
57 | Random r2 = new Random(seed + 1); | ||
58 | |||
59 | final int diffTravelFrequency = commitFrequency * 2; | ||
60 | for (int i = 0; i < steps; i++) { | ||
61 | int index = i + 1; | ||
62 | if (index % diffTravelFrequency == 0) { | ||
63 | // difftravel | ||
64 | long travelToVersion = r2.nextInt(largestCommit + 1); | ||
65 | DiffCursor<Integer, String> diffCursor = moving.getDiffCursor(travelToVersion); | ||
66 | moving.putAll(diffCursor); | ||
67 | |||
68 | } else { | ||
69 | // random puts | ||
70 | int nextKey = r2.nextInt(maxKey); | ||
71 | String nextValue = values[r2.nextInt(values.length)]; | ||
72 | try { | ||
73 | moving.put(nextKey, nextValue); | ||
74 | } catch (Exception exception) { | ||
75 | exception.printStackTrace(); | ||
76 | fail(scenario + ":" + index + ": exception happened: " + exception); | ||
77 | } | ||
78 | if (index % commitFrequency == 0) { | ||
79 | versioned.commit(); | ||
80 | } | ||
81 | if (index % 10000 == 0) | ||
82 | System.out.println(scenario + ":" + index + "/" + steps + " building finished"); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | } | ||
87 | |||
88 | @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
89 | @MethodSource | ||
90 | @Timeout(value = 10) | ||
91 | @Tag("fuzz") | ||
92 | void parametrizedFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
93 | boolean evilHash) { | ||
94 | runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, | ||
95 | noKeys, noValues, commitFrequency, evilHash); | ||
96 | } | ||
97 | |||
98 | static Stream<Arguments> parametrizedFuzz() { | ||
99 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | ||
100 | new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, | ||
101 | new Object[] { false, true }); | ||
102 | } | ||
103 | @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
104 | @MethodSource | ||
105 | @Tag("fuzz") | ||
106 | @Tag("slow") | ||
107 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
108 | boolean evilHash) { | ||
109 | runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | ||
110 | commitFrequency, evilHash); | ||
111 | } | ||
112 | |||
113 | static Stream<Arguments> parametrizedSlowFuzz() { | ||
114 | return FuzzTestUtils.changeStepCount(parametrizedFuzz(), 1); | ||
115 | } | ||
116 | } | ||
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MultiThreadFuzzTest.java b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MultiThreadFuzzTest.java new file mode 100644 index 00000000..c3a3e8ea --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MultiThreadFuzzTest.java | |||
@@ -0,0 +1,96 @@ | |||
1 | package org.eclipse.viatra.solver.data.map.tests.fuzz; | ||
2 | |||
3 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
4 | import static org.junit.jupiter.api.Assertions.fail; | ||
5 | |||
6 | import java.util.Collections; | ||
7 | import java.util.LinkedList; | ||
8 | import java.util.List; | ||
9 | import java.util.stream.Stream; | ||
10 | |||
11 | import org.eclipse.viatra.solver.data.map.ContinousHashProvider; | ||
12 | import org.eclipse.viatra.solver.data.map.VersionedMapStore; | ||
13 | import org.eclipse.viatra.solver.data.map.VersionedMapStoreImpl; | ||
14 | import org.eclipse.viatra.solver.data.map.tests.fuzz.utils.FuzzTestUtils; | ||
15 | import org.eclipse.viatra.solver.data.map.tests.utils.MapTestEnvironment; | ||
16 | import org.junit.jupiter.api.Tag; | ||
17 | import org.junit.jupiter.api.Timeout; | ||
18 | import org.junit.jupiter.params.ParameterizedTest; | ||
19 | import org.junit.jupiter.params.provider.Arguments; | ||
20 | import org.junit.jupiter.params.provider.MethodSource; | ||
21 | |||
22 | class MultiThreadFuzzTest { | ||
23 | public static final int noThreads = 32; | ||
24 | |||
25 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | ||
26 | boolean evilHash) { | ||
27 | String[] values = MapTestEnvironment.prepareValues(maxValue); | ||
28 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | ||
29 | |||
30 | VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | ||
31 | |||
32 | // initialize runnables | ||
33 | MultiThreadTestRunnable[] runnables = new MultiThreadTestRunnable[noThreads]; | ||
34 | for(int i = 0; i<noThreads; i++) { | ||
35 | runnables[i] = new MultiThreadTestRunnable(scenario+"-T"+(i+1), store, steps, maxKey, values, seed, commitFrequency); | ||
36 | } | ||
37 | |||
38 | // initialize threads | ||
39 | Thread[] threads = new Thread[noThreads]; | ||
40 | for(int i = 0; i<noThreads; i++) { | ||
41 | threads[i] = new Thread(runnables[i]); | ||
42 | } | ||
43 | |||
44 | // start threads; | ||
45 | for(int i = 0; i<noThreads; i++) { | ||
46 | threads[i].start(); | ||
47 | } | ||
48 | |||
49 | // wait all the threads; | ||
50 | for(int i = 0; i<noThreads; i++) { | ||
51 | try { | ||
52 | threads[i].join(); | ||
53 | } catch (InterruptedException e) { | ||
54 | fail("Thread "+i+" interrupted."); | ||
55 | } | ||
56 | } | ||
57 | |||
58 | // collect errors | ||
59 | List<Throwable> errors = new LinkedList<>(); | ||
60 | for(int i = 0; i<noThreads; i++) { | ||
61 | errors.addAll(runnables[i].getErrors()); | ||
62 | } | ||
63 | |||
64 | assertEquals(Collections.EMPTY_LIST, errors); | ||
65 | } | ||
66 | |||
67 | @ParameterizedTest(name = "Multithread {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
68 | @MethodSource | ||
69 | @Timeout(value = 10) | ||
70 | @Tag("fuzz") | ||
71 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
72 | boolean evilHash) { | ||
73 | runFuzzTest("MultithreadS" + steps + "K" + noKeys + "V" + noValues + "CF" + commitFrequency + "s" + seed, seed, steps, noKeys, noValues, | ||
74 | commitFrequency, evilHash); | ||
75 | } | ||
76 | |||
77 | static Stream<Arguments> parametrizedFastFuzz() { | ||
78 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | ||
79 | new Object[] { 2, 3 }, new Object[] { 10, 100 }, new Object[] { 1, 2, 3 }, | ||
80 | new Object[] { false, true }); | ||
81 | } | ||
82 | |||
83 | @ParameterizedTest(name = "Multithread {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
84 | @MethodSource | ||
85 | @Tag("fuzz") | ||
86 | @Tag("slow") | ||
87 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
88 | boolean evilHash) { | ||
89 | runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | ||
90 | commitFrequency, evilHash); | ||
91 | } | ||
92 | |||
93 | static Stream<Arguments> parametrizedSlowFuzz() { | ||
94 | return FuzzTestUtils.changeStepCount(RestoreFuzzTest.parametrizedFastFuzz(), 1); | ||
95 | } | ||
96 | } | ||
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MultiThreadTestRunnable.java b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MultiThreadTestRunnable.java new file mode 100644 index 00000000..a18298a2 --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MultiThreadTestRunnable.java | |||
@@ -0,0 +1,101 @@ | |||
1 | package org.eclipse.viatra.solver.data.map.tests.fuzz; | ||
2 | |||
3 | import java.util.ArrayList; | ||
4 | import java.util.Collections; | ||
5 | import java.util.HashMap; | ||
6 | import java.util.LinkedList; | ||
7 | import java.util.List; | ||
8 | import java.util.Map; | ||
9 | import java.util.Random; | ||
10 | |||
11 | import org.eclipse.viatra.solver.data.map.VersionedMapStore; | ||
12 | import org.eclipse.viatra.solver.data.map.internal.VersionedMapImpl; | ||
13 | import org.eclipse.viatra.solver.data.map.tests.utils.MapTestEnvironment; | ||
14 | |||
15 | public class MultiThreadTestRunnable implements Runnable { | ||
16 | String scenario; | ||
17 | VersionedMapStore<Integer, String> store; | ||
18 | int steps; | ||
19 | int maxKey; | ||
20 | String[] values; | ||
21 | int seed; | ||
22 | int commitFrequency; | ||
23 | List<Throwable> errors = new LinkedList<>(); | ||
24 | |||
25 | public MultiThreadTestRunnable(String scenario, VersionedMapStore<Integer, String> store, int steps, | ||
26 | int maxKey, String[] values, int seed, int commitFrequency) { | ||
27 | super(); | ||
28 | this.scenario = scenario; | ||
29 | this.store = store; | ||
30 | this.steps = steps; | ||
31 | this.maxKey = maxKey; | ||
32 | this.values = values; | ||
33 | this.seed = seed; | ||
34 | this.commitFrequency = commitFrequency; | ||
35 | } | ||
36 | |||
37 | private void logAndThrowError(String message) { | ||
38 | AssertionError error = new AssertionError(message); | ||
39 | errors.add(error); | ||
40 | } | ||
41 | |||
42 | public List<Throwable> getErrors() { | ||
43 | return errors; | ||
44 | } | ||
45 | |||
46 | @Override | ||
47 | public void run() { | ||
48 | // 1. build a map with versions | ||
49 | Random r = new Random(seed); | ||
50 | VersionedMapImpl<Integer, String> versioned = (VersionedMapImpl<Integer, String>) store.createMap(); | ||
51 | Map<Integer, Long> index2Version = new HashMap<>(); | ||
52 | |||
53 | for (int i = 0; i < steps; i++) { | ||
54 | int index = i + 1; | ||
55 | int nextKey = r.nextInt(maxKey); | ||
56 | String nextValue = values[r.nextInt(values.length)]; | ||
57 | try { | ||
58 | versioned.put(nextKey, nextValue); | ||
59 | } catch (Exception exception) { | ||
60 | exception.printStackTrace(); | ||
61 | logAndThrowError(scenario + ":" + index + ": exception happened: " + exception); | ||
62 | } | ||
63 | if (index % commitFrequency == 0) { | ||
64 | long version = versioned.commit(); | ||
65 | index2Version.put(i, version); | ||
66 | } | ||
67 | MapTestEnvironment.printStatus(scenario, index, steps, "building"); | ||
68 | } | ||
69 | // 2. create a non-versioned | ||
70 | VersionedMapImpl<Integer, String> reference = (VersionedMapImpl<Integer, String>) store.createMap(); | ||
71 | r = new Random(seed); | ||
72 | Random r2 = new Random(seed+1); | ||
73 | |||
74 | for (int i = 0; i < steps; i++) { | ||
75 | int index = i + 1; | ||
76 | int nextKey = r.nextInt(maxKey); | ||
77 | String nextValue = values[r.nextInt(values.length)]; | ||
78 | try { | ||
79 | reference.put(nextKey, nextValue); | ||
80 | } catch (Exception exception) { | ||
81 | exception.printStackTrace(); | ||
82 | logAndThrowError(scenario + ":" + index + ": exception happened: " + exception); | ||
83 | } | ||
84 | // go back to an existing state and compare to the reference | ||
85 | if (index % (commitFrequency) == 0) { | ||
86 | versioned.restore(index2Version.get(i)); | ||
87 | MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference, versioned,errors); | ||
88 | |||
89 | // go back to a random state (probably created by another thread) | ||
90 | List<Long> states = new ArrayList<>(store.getStates()); | ||
91 | Collections.shuffle(states, r2); | ||
92 | for(Long state : states.subList(0, Math.min(states.size(), 100))) { | ||
93 | versioned.restore(state); | ||
94 | } | ||
95 | versioned.restore(index2Version.get(i)); | ||
96 | } | ||
97 | |||
98 | MapTestEnvironment.printStatus(scenario, index, steps, "comparison"); | ||
99 | } | ||
100 | } | ||
101 | } | ||
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MutableFuzzTest.java b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MutableFuzzTest.java new file mode 100644 index 00000000..2d589dc9 --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MutableFuzzTest.java | |||
@@ -0,0 +1,91 @@ | |||
1 | package org.eclipse.viatra.solver.data.map.tests.fuzz; | ||
2 | |||
3 | import static org.junit.jupiter.api.Assertions.fail; | ||
4 | |||
5 | import java.util.Random; | ||
6 | import java.util.stream.Stream; | ||
7 | |||
8 | import org.eclipse.viatra.solver.data.map.ContinousHashProvider; | ||
9 | import org.eclipse.viatra.solver.data.map.VersionedMapStore; | ||
10 | import org.eclipse.viatra.solver.data.map.VersionedMapStoreImpl; | ||
11 | import org.eclipse.viatra.solver.data.map.internal.VersionedMapImpl; | ||
12 | import org.eclipse.viatra.solver.data.map.tests.fuzz.utils.FuzzTestUtils; | ||
13 | import org.eclipse.viatra.solver.data.map.tests.utils.MapTestEnvironment; | ||
14 | import org.junit.jupiter.api.Tag; | ||
15 | import org.junit.jupiter.api.Timeout; | ||
16 | import org.junit.jupiter.params.ParameterizedTest; | ||
17 | import org.junit.jupiter.params.provider.Arguments; | ||
18 | import org.junit.jupiter.params.provider.MethodSource; | ||
19 | |||
20 | class MutableFuzzTest { | ||
21 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean evilHash) { | ||
22 | String[] values = MapTestEnvironment.prepareValues(maxValue); | ||
23 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | ||
24 | |||
25 | VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | ||
26 | VersionedMapImpl<Integer, String> sut = (VersionedMapImpl<Integer, String>) store.createMap(); | ||
27 | MapTestEnvironment<Integer, String> e = new MapTestEnvironment<Integer, String>(sut); | ||
28 | |||
29 | Random r = new Random(seed); | ||
30 | |||
31 | iterativeRandomPuts(scenario, steps, maxKey, values, e, r); | ||
32 | } | ||
33 | |||
34 | private void iterativeRandomPuts(String scenario, int steps, int maxKey, String[] values, | ||
35 | MapTestEnvironment<Integer, String> e, Random r) { | ||
36 | int stopAt = -1; | ||
37 | for (int i = 0; i < steps; i++) { | ||
38 | int index = i + 1; | ||
39 | int nextKey = r.nextInt(maxKey); | ||
40 | String nextValue = values[r.nextInt(values.length)]; | ||
41 | if (index == stopAt) { | ||
42 | System.out.println("issue!"); | ||
43 | System.out.println("State before:"); | ||
44 | e.printComparison(); | ||
45 | e.sut.prettyPrint(); | ||
46 | System.out.println("Next: put(" + nextKey + "," + nextValue + ")"); | ||
47 | } | ||
48 | try { | ||
49 | e.put(nextKey, nextValue); | ||
50 | if (index == stopAt) { | ||
51 | e.sut.prettyPrint(); | ||
52 | } | ||
53 | e.checkEquivalence(scenario + ":" + index); | ||
54 | } catch (Exception exception) { | ||
55 | exception.printStackTrace(); | ||
56 | fail(scenario + ":" + index + ": exception happened: " + exception); | ||
57 | } | ||
58 | MapTestEnvironment.printStatus(scenario, index, steps, null); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} seed={4} evil-hash={5}") | ||
63 | @MethodSource | ||
64 | @Timeout(value = 10) | ||
65 | @Tag("fuzz") | ||
66 | void parametrizedFuzz(int test, int steps, int noKeys, int noValues, int seed, boolean evilHash) { | ||
67 | runFuzzTest( | ||
68 | "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed + "H" + (evilHash ? "Evil" : "Normal"), | ||
69 | seed, steps, noKeys, noValues, evilHash); | ||
70 | } | ||
71 | |||
72 | static Stream<Arguments> parametrizedFuzz() { | ||
73 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, | ||
74 | new Object[] { 3, 32, 32 * 32, 32 * 32 * 32 * 32 }, new Object[] { 2, 3 }, new Object[] { 1, 2, 3 }, | ||
75 | new Object[] { false, true }); | ||
76 | } | ||
77 | |||
78 | @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} seed={4} evil-hash={5}") | ||
79 | @MethodSource | ||
80 | @Tag("fuzz") | ||
81 | @Tag("slow") | ||
82 | void parametrizedSlowFuzz(int test, int steps, int noKeys, int noValues, int seed, boolean evilHash) { | ||
83 | runFuzzTest( | ||
84 | "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed + "H" + (evilHash ? "Evil" : "Normal"), | ||
85 | seed, steps, noKeys, noValues, evilHash); | ||
86 | } | ||
87 | |||
88 | static Stream<Arguments> parametrizedSlowFuzz() { | ||
89 | return FuzzTestUtils.changeStepCount(parametrizedFuzz(), 1); | ||
90 | } | ||
91 | } | ||
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MutableImmutableCompareFuzzTest.java b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MutableImmutableCompareFuzzTest.java new file mode 100644 index 00000000..cc2abfe4 --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MutableImmutableCompareFuzzTest.java | |||
@@ -0,0 +1,88 @@ | |||
1 | package org.eclipse.viatra.solver.data.map.tests.fuzz; | ||
2 | |||
3 | import static org.junit.jupiter.api.Assertions.fail; | ||
4 | |||
5 | import java.util.Random; | ||
6 | import java.util.stream.Stream; | ||
7 | |||
8 | import org.eclipse.viatra.solver.data.map.ContinousHashProvider; | ||
9 | import org.eclipse.viatra.solver.data.map.VersionedMapStore; | ||
10 | import org.eclipse.viatra.solver.data.map.VersionedMapStoreImpl; | ||
11 | import org.eclipse.viatra.solver.data.map.internal.VersionedMapImpl; | ||
12 | import org.eclipse.viatra.solver.data.map.tests.fuzz.utils.FuzzTestUtils; | ||
13 | import org.eclipse.viatra.solver.data.map.tests.utils.MapTestEnvironment; | ||
14 | import org.junit.jupiter.api.Tag; | ||
15 | import org.junit.jupiter.api.Timeout; | ||
16 | import org.junit.jupiter.params.ParameterizedTest; | ||
17 | import org.junit.jupiter.params.provider.Arguments; | ||
18 | import org.junit.jupiter.params.provider.MethodSource; | ||
19 | |||
20 | class MutableImmutableCompareFuzzTest { | ||
21 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | ||
22 | boolean evilHash) { | ||
23 | String[] values = MapTestEnvironment.prepareValues(maxValue); | ||
24 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | ||
25 | |||
26 | VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | ||
27 | VersionedMapImpl<Integer, String> immutable = (VersionedMapImpl<Integer, String>) store.createMap(); | ||
28 | VersionedMapImpl<Integer, String> mutable = (VersionedMapImpl<Integer, String>) store.createMap(); | ||
29 | |||
30 | Random r = new Random(seed); | ||
31 | |||
32 | iterativeRandomPutsAndCommitsAndCompare(scenario, immutable, mutable, steps, maxKey, values, r, | ||
33 | commitFrequency); | ||
34 | } | ||
35 | |||
36 | private void iterativeRandomPutsAndCommitsAndCompare(String scenario, VersionedMapImpl<Integer, String> immutable, | ||
37 | VersionedMapImpl<Integer, String> mutable, int steps, int maxKey, String[] values, Random r, | ||
38 | int commitFrequency) { | ||
39 | for (int i = 0; i < steps; i++) { | ||
40 | int index = i + 1; | ||
41 | int nextKey = r.nextInt(maxKey); | ||
42 | String nextValue = values[r.nextInt(values.length)]; | ||
43 | try { | ||
44 | immutable.put(nextKey, nextValue); | ||
45 | mutable.put(nextKey, nextValue); | ||
46 | } catch (Exception exception) { | ||
47 | exception.printStackTrace(); | ||
48 | fail(scenario + ":" + index + ": exception happened: " + exception); | ||
49 | } | ||
50 | if (index % commitFrequency == 0) { | ||
51 | immutable.commit(); | ||
52 | } | ||
53 | MapTestEnvironment.compareTwoMaps(scenario + ":" + index, immutable, mutable); | ||
54 | |||
55 | MapTestEnvironment.printStatus(scenario, index, steps, null); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
60 | @MethodSource | ||
61 | @Timeout(value = 10) | ||
62 | @Tag("fuzz") | ||
63 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
64 | boolean evilHash) { | ||
65 | runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, | ||
66 | noKeys, noValues, commitFrequency, evilHash); | ||
67 | } | ||
68 | |||
69 | static Stream<Arguments> parametrizedFastFuzz() { | ||
70 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | ||
71 | new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, | ||
72 | new Object[] { false, true }); | ||
73 | } | ||
74 | |||
75 | @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
76 | @MethodSource | ||
77 | @Tag("fuzz") | ||
78 | @Tag("slow") | ||
79 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
80 | boolean evilHash) { | ||
81 | runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, | ||
82 | noKeys, noValues, commitFrequency, evilHash); | ||
83 | } | ||
84 | |||
85 | static Stream<Arguments> parametrizedSlowFuzz() { | ||
86 | return FuzzTestUtils.changeStepCount(MutableImmutableCompareFuzzTest.parametrizedFastFuzz(), 1); | ||
87 | } | ||
88 | } | ||
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/RestoreFuzzTest.java b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/RestoreFuzzTest.java new file mode 100644 index 00000000..7d9f5372 --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/RestoreFuzzTest.java | |||
@@ -0,0 +1,108 @@ | |||
1 | package org.eclipse.viatra.solver.data.map.tests.fuzz; | ||
2 | |||
3 | import static org.junit.jupiter.api.Assertions.fail; | ||
4 | |||
5 | import java.util.HashMap; | ||
6 | import java.util.Map; | ||
7 | import java.util.Random; | ||
8 | import java.util.stream.Stream; | ||
9 | |||
10 | import org.eclipse.viatra.solver.data.map.ContinousHashProvider; | ||
11 | import org.eclipse.viatra.solver.data.map.VersionedMapStore; | ||
12 | import org.eclipse.viatra.solver.data.map.VersionedMapStoreImpl; | ||
13 | import org.eclipse.viatra.solver.data.map.internal.VersionedMapImpl; | ||
14 | import org.eclipse.viatra.solver.data.map.tests.fuzz.utils.FuzzTestUtils; | ||
15 | import org.eclipse.viatra.solver.data.map.tests.utils.MapTestEnvironment; | ||
16 | import org.junit.jupiter.api.Tag; | ||
17 | import org.junit.jupiter.api.Timeout; | ||
18 | import org.junit.jupiter.params.ParameterizedTest; | ||
19 | import org.junit.jupiter.params.provider.Arguments; | ||
20 | import org.junit.jupiter.params.provider.MethodSource; | ||
21 | |||
22 | class RestoreFuzzTest { | ||
23 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | ||
24 | boolean evilHash) { | ||
25 | String[] values = MapTestEnvironment.prepareValues(maxValue); | ||
26 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | ||
27 | |||
28 | VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | ||
29 | |||
30 | iterativeRandomPutsAndCommitsThenRestore(scenario, store, steps, maxKey, values, seed, commitFrequency); | ||
31 | } | ||
32 | |||
33 | private void iterativeRandomPutsAndCommitsThenRestore(String scenario, VersionedMapStore<Integer, String> store, | ||
34 | int steps, int maxKey, String[] values, int seed, int commitFrequency) { | ||
35 | // 1. build a map with versions | ||
36 | Random r = new Random(seed); | ||
37 | VersionedMapImpl<Integer, String> versioned = (VersionedMapImpl<Integer, String>) store.createMap(); | ||
38 | Map<Integer, Long> index2Version = new HashMap<>(); | ||
39 | |||
40 | for (int i = 0; i < steps; i++) { | ||
41 | int index = i + 1; | ||
42 | int nextKey = r.nextInt(maxKey); | ||
43 | String nextValue = values[r.nextInt(values.length)]; | ||
44 | try { | ||
45 | versioned.put(nextKey, nextValue); | ||
46 | } catch (Exception exception) { | ||
47 | exception.printStackTrace(); | ||
48 | fail(scenario + ":" + index + ": exception happened: " + exception); | ||
49 | } | ||
50 | if (index % commitFrequency == 0) { | ||
51 | long version = versioned.commit(); | ||
52 | index2Version.put(i, version); | ||
53 | } | ||
54 | MapTestEnvironment.printStatus(scenario, index, steps, "building"); | ||
55 | } | ||
56 | // 2. create a non-versioned and | ||
57 | VersionedMapImpl<Integer, String> reference = (VersionedMapImpl<Integer, String>) store.createMap(); | ||
58 | r = new Random(seed); | ||
59 | |||
60 | for (int i = 0; i < steps; i++) { | ||
61 | int index = i + 1; | ||
62 | int nextKey = r.nextInt(maxKey); | ||
63 | String nextValue = values[r.nextInt(values.length)]; | ||
64 | try { | ||
65 | reference.put(nextKey, nextValue); | ||
66 | } catch (Exception exception) { | ||
67 | exception.printStackTrace(); | ||
68 | fail(scenario + ":" + index + ": exception happened: " + exception); | ||
69 | } | ||
70 | if (index % commitFrequency == 0) { | ||
71 | versioned.restore(index2Version.get(i)); | ||
72 | MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference, versioned); | ||
73 | } | ||
74 | MapTestEnvironment.printStatus(scenario, index, steps, "comparison"); | ||
75 | } | ||
76 | |||
77 | } | ||
78 | |||
79 | @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
80 | @MethodSource | ||
81 | @Timeout(value = 10) | ||
82 | @Tag("smoke") | ||
83 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
84 | boolean evilHash) { | ||
85 | runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | ||
86 | commitFrequency, evilHash); | ||
87 | } | ||
88 | |||
89 | static Stream<Arguments> parametrizedFastFuzz() { | ||
90 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | ||
91 | new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, | ||
92 | new Object[] { false, true }); | ||
93 | } | ||
94 | |||
95 | @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
96 | @MethodSource | ||
97 | @Tag("smoke") | ||
98 | @Tag("slow") | ||
99 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
100 | boolean evilHash) { | ||
101 | runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | ||
102 | commitFrequency, evilHash); | ||
103 | } | ||
104 | |||
105 | static Stream<Arguments> parametrizedSlowFuzz() { | ||
106 | return FuzzTestUtils.changeStepCount(RestoreFuzzTest.parametrizedFastFuzz(), 1); | ||
107 | } | ||
108 | } | ||
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/SharedStoreFuzzTest.java b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/SharedStoreFuzzTest.java new file mode 100644 index 00000000..800308b4 --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/SharedStoreFuzzTest.java | |||
@@ -0,0 +1,112 @@ | |||
1 | package org.eclipse.viatra.solver.data.map.tests.fuzz; | ||
2 | |||
3 | import java.util.HashMap; | ||
4 | import java.util.LinkedList; | ||
5 | import java.util.List; | ||
6 | import java.util.Map; | ||
7 | import java.util.Random; | ||
8 | import java.util.stream.Stream; | ||
9 | |||
10 | import org.eclipse.viatra.solver.data.map.ContinousHashProvider; | ||
11 | import org.eclipse.viatra.solver.data.map.VersionedMapStore; | ||
12 | import org.eclipse.viatra.solver.data.map.VersionedMapStoreImpl; | ||
13 | import org.eclipse.viatra.solver.data.map.internal.VersionedMapImpl; | ||
14 | import org.eclipse.viatra.solver.data.map.tests.fuzz.utils.FuzzTestUtils; | ||
15 | import org.eclipse.viatra.solver.data.map.tests.utils.MapTestEnvironment; | ||
16 | import org.junit.jupiter.api.Tag; | ||
17 | import org.junit.jupiter.api.Timeout; | ||
18 | import org.junit.jupiter.params.ParameterizedTest; | ||
19 | import org.junit.jupiter.params.provider.Arguments; | ||
20 | import org.junit.jupiter.params.provider.MethodSource; | ||
21 | |||
22 | class SharedStoreFuzzTest { | ||
23 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | ||
24 | boolean evilHash) { | ||
25 | String[] values = MapTestEnvironment.prepareValues(maxValue); | ||
26 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | ||
27 | |||
28 | List<VersionedMapStore<Integer, String>> stores = VersionedMapStoreImpl.createSharedVersionedMapStores(5, chp, values[0]); | ||
29 | |||
30 | iterativeRandomPutsAndCommitsThenRestore(scenario, stores, steps, maxKey, values, seed, commitFrequency); | ||
31 | } | ||
32 | |||
33 | private void iterativeRandomPutsAndCommitsThenRestore(String scenario, List<VersionedMapStore<Integer, String>> stores, | ||
34 | int steps, int maxKey, String[] values, int seed, int commitFrequency) { | ||
35 | // 1. maps with versions | ||
36 | Random r = new Random(seed); | ||
37 | List<VersionedMapImpl<Integer, String>> versioneds = new LinkedList<>(); | ||
38 | for(VersionedMapStore<Integer, String> store : stores) { | ||
39 | versioneds.add((VersionedMapImpl<Integer, String>) store.createMap()); | ||
40 | } | ||
41 | |||
42 | List<Map<Integer, Long>> index2Version = new LinkedList<>(); | ||
43 | for(int i = 0; i<stores.size(); i++) { | ||
44 | index2Version.add(new HashMap<>()); | ||
45 | } | ||
46 | |||
47 | for (int i = 0; i < steps; i++) { | ||
48 | int stepIndex = i + 1; | ||
49 | for (int storeIndex = 0; storeIndex<versioneds.size(); storeIndex++) { | ||
50 | int nextKey = r.nextInt(maxKey); | ||
51 | String nextValue = values[r.nextInt(values.length)]; | ||
52 | versioneds.get(storeIndex).put(nextKey, nextValue); | ||
53 | if (stepIndex % commitFrequency == 0) { | ||
54 | long version = versioneds.get(storeIndex).commit(); | ||
55 | index2Version.get(storeIndex).put(i, version); | ||
56 | } | ||
57 | MapTestEnvironment.printStatus(scenario, stepIndex, steps, "building"); | ||
58 | } | ||
59 | } | ||
60 | // 2. create a non-versioned and | ||
61 | List<VersionedMapImpl<Integer, String>> reference = new LinkedList<>(); | ||
62 | for(VersionedMapStore<Integer, String> store : stores) { | ||
63 | reference.add((VersionedMapImpl<Integer, String>) store.createMap()); | ||
64 | } | ||
65 | r = new Random(seed); | ||
66 | |||
67 | for (int i = 0; i < steps; i++) { | ||
68 | int index = i + 1; | ||
69 | for (int storeIndex = 0; storeIndex<versioneds.size(); storeIndex++) { | ||
70 | int nextKey = r.nextInt(maxKey); | ||
71 | String nextValue = values[r.nextInt(values.length)]; | ||
72 | reference.get(storeIndex).put(nextKey, nextValue); | ||
73 | if (index % commitFrequency == 0) { | ||
74 | versioneds.get(storeIndex).restore(index2Version.get(storeIndex).get(i)); | ||
75 | MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference.get(storeIndex), versioneds.get(storeIndex)); | ||
76 | } | ||
77 | } | ||
78 | MapTestEnvironment.printStatus(scenario, index, steps, "comparison"); | ||
79 | } | ||
80 | |||
81 | } | ||
82 | |||
83 | @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
84 | @MethodSource | ||
85 | @Timeout(value = 10) | ||
86 | @Tag("smoke") | ||
87 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
88 | boolean evilHash) { | ||
89 | runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | ||
90 | commitFrequency, evilHash); | ||
91 | } | ||
92 | |||
93 | static Stream<Arguments> parametrizedFastFuzz() { | ||
94 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | ||
95 | new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, | ||
96 | new Object[] { false, true }); | ||
97 | } | ||
98 | |||
99 | @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
100 | @MethodSource | ||
101 | @Tag("smoke") | ||
102 | @Tag("slow") | ||
103 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
104 | boolean evilHash) { | ||
105 | runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | ||
106 | commitFrequency, evilHash); | ||
107 | } | ||
108 | |||
109 | static Stream<Arguments> parametrizedSlowFuzz() { | ||
110 | return FuzzTestUtils.changeStepCount(RestoreFuzzTest.parametrizedFastFuzz(), 1); | ||
111 | } | ||
112 | } | ||
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/utils/FuzzTestUtils.java b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/utils/FuzzTestUtils.java new file mode 100644 index 00000000..ec21bb7b --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/utils/FuzzTestUtils.java | |||
@@ -0,0 +1,64 @@ | |||
1 | package org.eclipse.viatra.solver.data.map.tests.fuzz.utils; | ||
2 | |||
3 | import java.util.Arrays; | ||
4 | import java.util.LinkedList; | ||
5 | import java.util.List; | ||
6 | import java.util.stream.Stream; | ||
7 | |||
8 | import org.junit.jupiter.params.provider.Arguments; | ||
9 | |||
10 | public final class FuzzTestUtils { | ||
11 | public static final int FAST_STEP_COUNT = 500; | ||
12 | public static final int SLOW_STEP_COUNT = 32 * 32 * 32 * 32; | ||
13 | |||
14 | private FuzzTestUtils() { | ||
15 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); | ||
16 | } | ||
17 | |||
18 | public static Stream<Arguments> changeStepCount(Stream<Arguments> arguments, int parameterIndex) { | ||
19 | return arguments.map(x -> Arguments.of(updatedStepCount(x.get(), parameterIndex))); | ||
20 | } | ||
21 | |||
22 | public static Object[] updatedStepCount(Object[] arguments, int parameterIndex) { | ||
23 | Object[] copy = Arrays.copyOf(arguments, arguments.length); | ||
24 | copy[parameterIndex] = SLOW_STEP_COUNT; | ||
25 | return copy; | ||
26 | } | ||
27 | |||
28 | static List<List<Object>> permutationInternal(int from, Object[]... valueOption) { | ||
29 | if (valueOption.length == from) { | ||
30 | return List.of(List.of()); | ||
31 | } else { | ||
32 | Object[] permuteThis = valueOption[from]; | ||
33 | List<List<Object>> otherCombination = permutationInternal(from + 1, valueOption); | ||
34 | List<List<Object>> result = new LinkedList<>(); | ||
35 | for (Object permuteThisElement : permuteThis) { | ||
36 | for (List<Object> otherCombinationList : otherCombination) { | ||
37 | List<Object> newResult = new LinkedList<>(); | ||
38 | newResult.add(permuteThisElement); | ||
39 | newResult.addAll(otherCombinationList); | ||
40 | result.add(newResult); | ||
41 | } | ||
42 | } | ||
43 | return result; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | public static Stream<Arguments> permutation(Object[]... valueOption) { | ||
48 | List<List<Object>> permutations = permutationInternal(0, valueOption); | ||
49 | return permutations.stream().map(x -> Arguments.of(x.toArray())); | ||
50 | } | ||
51 | |||
52 | public static Stream<Arguments> permutationWithSize(Object[]... valueOption) { | ||
53 | int size = 1; | ||
54 | for (int i = 0; i < valueOption.length; i++) { | ||
55 | size *= valueOption[i].length; | ||
56 | } | ||
57 | Object[][] newValueOption = new Object[valueOption.length + 1][]; | ||
58 | newValueOption[0] = new Object[] { size }; | ||
59 | for (int i = 1; i < newValueOption.length; i++) { | ||
60 | newValueOption[i] = valueOption[i - 1]; | ||
61 | } | ||
62 | return permutation(newValueOption); | ||
63 | } | ||
64 | } | ||
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/utils/FuzzTestUtilsTest.java b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/utils/FuzzTestUtilsTest.java new file mode 100644 index 00000000..3f4214bc --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/utils/FuzzTestUtilsTest.java | |||
@@ -0,0 +1,33 @@ | |||
1 | package org.eclipse.viatra.solver.data.map.tests.fuzz.utils; | ||
2 | |||
3 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
4 | |||
5 | import java.util.List; | ||
6 | |||
7 | import org.junit.jupiter.api.Test; | ||
8 | |||
9 | class FuzzTestUtilsTest { | ||
10 | @Test | ||
11 | void permutationInternalTest() { | ||
12 | List<List<Object>> res = FuzzTestUtils.permutationInternal(0, new Object[] { 1, 2, 3 }, | ||
13 | new Object[] { 'a', 'b', 'c' }, new Object[] { "alpha", "beta", "gamma", "delta" }); | ||
14 | assertEquals(3 * 3 * 4, res.size()); | ||
15 | } | ||
16 | |||
17 | @Test | ||
18 | void permutationTest1() { | ||
19 | var res = FuzzTestUtils.permutation(new Object[] { 1, 2, 3 }, new Object[] { 'a', 'b', 'c' }, | ||
20 | new Object[] { "alpha", "beta", "gamma", "delta" }); | ||
21 | assertEquals(3 * 3 * 4, res.count()); | ||
22 | } | ||
23 | |||
24 | @Test | ||
25 | void permutationTest2() { | ||
26 | var res = FuzzTestUtils.permutation(new Object[] { 1, 2, 3 }, new Object[] { 'a', 'b', 'c' }, | ||
27 | new Object[] { "alpha", "beta", "gamma", "delta" }); | ||
28 | var arguments = res.findFirst().get().get(); | ||
29 | assertEquals(1, arguments[0]); | ||
30 | assertEquals('a', arguments[1]); | ||
31 | assertEquals("alpha", arguments[2]); | ||
32 | } | ||
33 | } | ||
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/utils/MapTestEnvironment.java b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/utils/MapTestEnvironment.java new file mode 100644 index 00000000..4c043350 --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/map/tests/utils/MapTestEnvironment.java | |||
@@ -0,0 +1,213 @@ | |||
1 | package org.eclipse.viatra.solver.data.map.tests.utils; | ||
2 | |||
3 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
4 | import static org.junit.jupiter.api.Assertions.assertTrue; | ||
5 | import static org.junit.jupiter.api.Assertions.fail; | ||
6 | |||
7 | import java.util.HashMap; | ||
8 | import java.util.Iterator; | ||
9 | import java.util.List; | ||
10 | import java.util.Map; | ||
11 | import java.util.Map.Entry; | ||
12 | import java.util.TreeMap; | ||
13 | |||
14 | import org.eclipse.viatra.solver.data.map.ContinousHashProvider; | ||
15 | import org.eclipse.viatra.solver.data.map.Cursor; | ||
16 | import org.eclipse.viatra.solver.data.map.VersionedMap; | ||
17 | import org.eclipse.viatra.solver.data.map.internal.VersionedMapImpl; | ||
18 | |||
19 | public class MapTestEnvironment<K, V> { | ||
20 | public static String[] prepareValues(int maxValue) { | ||
21 | String[] values = new String[maxValue]; | ||
22 | values[0] = "DEFAULT"; | ||
23 | for (int i = 1; i < values.length; i++) { | ||
24 | values[i] = "VAL" + i; | ||
25 | } | ||
26 | return values; | ||
27 | } | ||
28 | |||
29 | public static ContinousHashProvider<Integer> prepareHashProvider(final boolean evil) { | ||
30 | // Use maxPrime = 2147483629 | ||
31 | |||
32 | ContinousHashProvider<Integer> chp = new ContinousHashProvider<Integer>() { | ||
33 | |||
34 | @Override | ||
35 | public int getHash(Integer key, int index) { | ||
36 | if (evil && index < 15 && index < key / 3) { | ||
37 | return 7; | ||
38 | } | ||
39 | int result = 1; | ||
40 | final int prime = 31; | ||
41 | |||
42 | result = prime * result + key; | ||
43 | result = prime * result + index; | ||
44 | |||
45 | return result; | ||
46 | } | ||
47 | }; | ||
48 | return chp; | ||
49 | } | ||
50 | |||
51 | public static void printStatus(String scenario, int actual, int max, String stepName) { | ||
52 | if (actual % 10000 == 0) { | ||
53 | String printStepName = stepName == null ? "" : stepName; | ||
54 | System.out.format(scenario + ":%d/%d (%d%%) " + printStepName + "%n", actual, max, actual * 100 / max); | ||
55 | } | ||
56 | |||
57 | } | ||
58 | |||
59 | public static <K, V> void compareTwoMaps(String title, VersionedMapImpl<K, V> map1, | ||
60 | VersionedMapImpl<K, V> map2) { | ||
61 | compareTwoMaps(title, map1, map2, null); | ||
62 | } | ||
63 | public static <K, V> void compareTwoMaps(String title, VersionedMapImpl<K, V> map1, | ||
64 | VersionedMapImpl<K, V> map2, List<Throwable> errors) { | ||
65 | // 1. Comparing cursors. | ||
66 | Cursor<K, V> cursor1 = map1.getAll(); | ||
67 | Cursor<K, V> cursor2 = map2.getAll(); | ||
68 | while (!cursor1.isTerminated()) { | ||
69 | if (cursor2.isTerminated()) { | ||
70 | fail("cursor 2 terminated before cursor1"); | ||
71 | } | ||
72 | assertEqualsList(cursor1.getKey(), cursor2.getKey(),"Keys not equal", errors); | ||
73 | assertEqualsList(cursor2.getValue(), cursor2.getValue(), "Values not equal", errors); | ||
74 | cursor1.move(); | ||
75 | cursor2.move(); | ||
76 | } | ||
77 | if (!cursor2.isTerminated()) | ||
78 | fail("cursor 1 terminated before cursor 2"); | ||
79 | |||
80 | // 2.1. comparing hash codes | ||
81 | assertEqualsList(map1.hashCode(), map2.hashCode(), title + ": hash code check",errors); | ||
82 | assertEqualsList(map1, map2, title + ": 1.equals(2)",errors); | ||
83 | assertEqualsList(map2, map1, title + ": 2.equals(1)",errors); | ||
84 | } | ||
85 | private static void assertEqualsList(Object o1, Object o2, String message, List<Throwable> errors) { | ||
86 | if(errors == null) { | ||
87 | assertEquals(o1, o2, message); | ||
88 | } else { | ||
89 | if(o1 != null) { | ||
90 | if(!(o1.equals(o2))) { | ||
91 | AssertionError error = new AssertionError((message != null ? message+" " : "") + "expected: " + o1 + " but was : " + o2); | ||
92 | errors.add(error); | ||
93 | } | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | |||
98 | public VersionedMapImpl<K, V> sut; | ||
99 | Map<K, V> oracle = new HashMap<K, V>(); | ||
100 | |||
101 | public MapTestEnvironment(VersionedMapImpl<K, V> sut) { | ||
102 | this.sut = sut; | ||
103 | } | ||
104 | |||
105 | public void put(K key, V value) { | ||
106 | V oldSutValue = sut.put(key, value); | ||
107 | V oldOracleValue; | ||
108 | if (value != sut.getDefaultValue()) { | ||
109 | oldOracleValue = oracle.put(key, value); | ||
110 | } else { | ||
111 | oldOracleValue = oracle.remove(key); | ||
112 | } | ||
113 | if(oldSutValue == sut.getDefaultValue() && oldOracleValue != null) { | ||
114 | fail("After put, SUT old value was default, but oracle old walue was " + oldOracleValue); | ||
115 | } | ||
116 | if(oldSutValue != sut.getDefaultValue()) { | ||
117 | assertEquals(oldOracleValue, oldSutValue); | ||
118 | } | ||
119 | } | ||
120 | |||
121 | public void checkEquivalence(String title) { | ||
122 | // 0. Checking integrity | ||
123 | try { | ||
124 | sut.checkIntegrity(); | ||
125 | } catch (IllegalStateException e) { | ||
126 | fail(title + ": " + e.getMessage()); | ||
127 | } | ||
128 | |||
129 | // 1. Checking: if Reference contains <key,value> pair, then SUT contains | ||
130 | // <key,value> pair. | ||
131 | // Tests get functions | ||
132 | for (Entry<K, V> entry : oracle.entrySet()) { | ||
133 | V sutValue = sut.get(entry.getKey()); | ||
134 | V oracleValue = entry.getValue(); | ||
135 | if (sutValue != oracleValue) { | ||
136 | printComparison(); | ||
137 | fail(title + ": Non-equivalent get(" + entry.getKey() + ") results: SUT=" + sutValue + ", Oracle=" | ||
138 | + oracleValue + "!"); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | // 2. Checking: if SUT contains <key,value> pair, then Reference contains | ||
143 | // <key,value> pair. | ||
144 | // Tests iterators | ||
145 | int elementsInSutEntrySet = 0; | ||
146 | Cursor<K, V> cursor = sut.getAll(); | ||
147 | while (cursor.move()) { | ||
148 | elementsInSutEntrySet++; | ||
149 | K key = cursor.getKey(); | ||
150 | V sutValue = cursor.getValue(); | ||
151 | // System.out.println(key + " -> " + sutValue); | ||
152 | V oracleValue = oracle.get(key); | ||
153 | if (sutValue != oracleValue) { | ||
154 | printComparison(); | ||
155 | fail(title + ": Non-equivalent entry in iterator: SUT=<" + key + "," + sutValue + ">, Oracle=<" + key | ||
156 | + "," + oracleValue + ">!"); | ||
157 | } | ||
158 | |||
159 | } | ||
160 | |||
161 | // 3. Checking sizes | ||
162 | // Counting of non-default value pairs. | ||
163 | int oracleSize = oracle.entrySet().size(); | ||
164 | long sutSize = sut.getSize(); | ||
165 | if (oracleSize != sutSize || oracleSize != elementsInSutEntrySet) { | ||
166 | printComparison(); | ||
167 | fail(title + ": Non-eqivalent size() result: SUT.getSize()=" + sutSize + ", SUT.entryset.size=" | ||
168 | + elementsInSutEntrySet + ", Oracle=" + oracleSize + "!"); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | public static <K,V> void checkOrder(String scenario, VersionedMap<K,V> versionedMap) { | ||
173 | K previous = null; | ||
174 | Cursor<K, V> cursor = versionedMap.getAll(); | ||
175 | while(cursor.move()) { | ||
176 | System.out.println(cursor.getKey() + " " + ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().getHash(cursor.getKey(), 0)); | ||
177 | if(previous != null) { | ||
178 | int comparisonResult = ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().compare(previous, cursor.getKey()); | ||
179 | assertTrue(comparisonResult<0,scenario+" Cursor order is not incremental!"); | ||
180 | } | ||
181 | previous = cursor.getKey(); | ||
182 | } | ||
183 | System.out.println(); | ||
184 | } | ||
185 | |||
186 | public void printComparison() { | ||
187 | System.out.println("SUT:"); | ||
188 | printEntrySet(sut.getAll()); | ||
189 | System.out.println("Oracle:"); | ||
190 | printEntrySet(oracle.entrySet().iterator()); | ||
191 | } | ||
192 | |||
193 | private void printEntrySet(Iterator<Entry<K, V>> iterator) { | ||
194 | TreeMap<K, V> treemap = new TreeMap<>(); | ||
195 | while (iterator.hasNext()) { | ||
196 | Entry<K, V> entry = iterator.next(); | ||
197 | treemap.put(entry.getKey(), entry.getValue()); | ||
198 | } | ||
199 | for (Entry<K, V> e : treemap.entrySet()) { | ||
200 | System.out.println("\t" + e.getKey() + " -> " + e.getValue()); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | private void printEntrySet(Cursor<K, V> cursor) { | ||
205 | TreeMap<K, V> treemap = new TreeMap<>(); | ||
206 | while (cursor.move()) { | ||
207 | treemap.put(cursor.getKey(), cursor.getValue()); | ||
208 | } | ||
209 | for (Entry<K, V> e : treemap.entrySet()) { | ||
210 | System.out.println("\t" + e.getKey() + " -> " + e.getValue()); | ||
211 | } | ||
212 | } | ||
213 | } | ||
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/model/hashTests/HashEfficiencyTest.java b/store/src/test/java/org/eclipse/viatra/solver/data/model/hashTests/HashEfficiencyTest.java new file mode 100644 index 00000000..c4d98a43 --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/model/hashTests/HashEfficiencyTest.java | |||
@@ -0,0 +1,160 @@ | |||
1 | package org.eclipse.viatra.solver.data.model.hashTests; | ||
2 | |||
3 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
4 | |||
5 | import java.util.ArrayList; | ||
6 | import java.util.LinkedList; | ||
7 | import java.util.List; | ||
8 | import java.util.Random; | ||
9 | |||
10 | import org.eclipse.viatra.solver.data.map.ContinousHashProvider; | ||
11 | import org.eclipse.viatra.solver.data.model.Tuple; | ||
12 | import org.eclipse.viatra.solver.data.model.TupleHashProvider; | ||
13 | import org.eclipse.viatra.solver.data.model.TupleHashProviderBitMagic; | ||
14 | import org.junit.jupiter.api.Test; | ||
15 | |||
16 | class HashEfficiencyTest { | ||
17 | |||
18 | private static List<Tuple> permutations(int range, int arity) { | ||
19 | if(arity == 1) { | ||
20 | List<Tuple> result = new ArrayList<>(range); | ||
21 | for(int i=0; i<range; i++) { | ||
22 | result.add(Tuple.of(i)); | ||
23 | } | ||
24 | return result; | ||
25 | } else if(arity > 1) { | ||
26 | List<Tuple> smallers = permutations(range, arity-1); | ||
27 | List<Tuple> result = new ArrayList<>(range*smallers.size()); | ||
28 | for(Tuple smaller : smallers) { | ||
29 | for(int i=0; i<range; i++) { | ||
30 | int[] larger = new int[arity]; | ||
31 | for(int x = 0; x<smaller.getSize(); x++) { | ||
32 | larger[x] = smaller.get(x); | ||
33 | } | ||
34 | larger[arity-1] = i; | ||
35 | result.add(Tuple.of(larger)); | ||
36 | } | ||
37 | } | ||
38 | return result; | ||
39 | } else throw new IllegalArgumentException(); | ||
40 | } | ||
41 | |||
42 | private static int amountToRange(int arity, int n) { | ||
43 | int range = 1; | ||
44 | while(Math.pow(range,arity)<n+0.1) { | ||
45 | range++; | ||
46 | } | ||
47 | return 1024; | ||
48 | } | ||
49 | |||
50 | public static List<Tuple> nPermutations(int arity, int n) { | ||
51 | int range = amountToRange(arity, n); | ||
52 | List<Tuple> permutations = permutations(range, arity); | ||
53 | return permutations.subList(0, n); | ||
54 | } | ||
55 | |||
56 | public static List<Tuple> nRandoms(int arity, int n, int seed) { | ||
57 | int range = amountToRange(arity, n); | ||
58 | List<Tuple> permutations = new ArrayList<>(n); | ||
59 | Random r = new Random(seed); | ||
60 | for(int i = 0; i<n; i++) { | ||
61 | int[] tuple = new int[arity]; | ||
62 | for(int j=0; j<arity; j++) { | ||
63 | tuple[j] = r.nextInt(range); | ||
64 | } | ||
65 | permutations.add(Tuple.of(tuple)); | ||
66 | } | ||
67 | return permutations; | ||
68 | } | ||
69 | |||
70 | @Test | ||
71 | void permutationTest() { | ||
72 | List<Tuple> p = permutations(10, 2); | ||
73 | assertEquals(p.size(),10*10); | ||
74 | } | ||
75 | // private void printTuples(List<Tuple> p) { | ||
76 | // for(Tuple element : p) { | ||
77 | // System.out.println(element); | ||
78 | // } | ||
79 | // } | ||
80 | @Test | ||
81 | void nPermutationTest() { | ||
82 | final int amount = 500; | ||
83 | List<Tuple> p = nPermutations(2, amount); | ||
84 | assertEquals(amount,p.size()); | ||
85 | } | ||
86 | @Test | ||
87 | void nRandomTest() { | ||
88 | final int amount = 500; | ||
89 | List<Tuple> p = nRandoms(2, amount, 1);; | ||
90 | assertEquals(amount,p.size()); | ||
91 | } | ||
92 | private static double calculateHashClashes(List<Tuple> tuples, ContinousHashProvider<Tuple> chp) { | ||
93 | int sumClashes = 0; | ||
94 | |||
95 | for(int i = 0; i<tuples.size(); i++) { | ||
96 | int height = 0; | ||
97 | for(int j=0; j<tuples.size(); j++) { | ||
98 | int clashes = calculateHashClash(chp, tuples.get(i), tuples.get(j)); | ||
99 | height = Math.max(height, clashes); | ||
100 | } | ||
101 | sumClashes += height; | ||
102 | } | ||
103 | return (sumClashes+0.0) / tuples.size(); | ||
104 | } | ||
105 | private static int calculateHashClash(ContinousHashProvider<Tuple> chp, Tuple a, Tuple b) { | ||
106 | if(a.equals(b)) return 0; | ||
107 | final int bits = 5; | ||
108 | final int segments = Integer.SIZE/bits; | ||
109 | final int mask = (1<<bits)-1; | ||
110 | for(int i = 0;;i++) { | ||
111 | int index = i/segments; | ||
112 | int depth = i%segments; | ||
113 | int aHash = (chp.getHash(a, index)>>(depth*5))&mask; | ||
114 | int bHash = (chp.getHash(b, index)>>(depth*5))&mask; | ||
115 | if(aHash != bHash) { | ||
116 | return i+1; | ||
117 | } | ||
118 | if(i>400) { | ||
119 | throw new IllegalStateException(a+" vs "+b); | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | private static double caclulateOptimalHashClash(int size) { | ||
124 | return (Math.log(size)/Math.log(32)); | ||
125 | } | ||
126 | public static void main(String[] args) { | ||
127 | List<String> hashNames = new LinkedList<>(); | ||
128 | List<ContinousHashProvider<Tuple>> hashes = new LinkedList<>(); | ||
129 | hashNames.add("PrimeGroup"); | ||
130 | hashes.add(new TupleHashProvider()); | ||
131 | hashNames.add("BitMagic"); | ||
132 | hashes.add(new TupleHashProviderBitMagic()); | ||
133 | |||
134 | int[] arities = new int[] {2,3,4,5}; | ||
135 | int[] sizes = new int[] {32*32,32*32*8}; | ||
136 | |||
137 | System.out.println("Size,Arity,DataSource,Hash,Chashes,Optimal,Badness"); | ||
138 | for(int size : sizes) { | ||
139 | double optimalClashes = caclulateOptimalHashClash(size); | ||
140 | for(int arity : arities) { | ||
141 | List<String> dataSourceNames = new LinkedList<>(); | ||
142 | List<List<Tuple>> dataSources = new LinkedList<>(); | ||
143 | |||
144 | // dataSourceNames.add("Permutation"); | ||
145 | // dataSources.add(nPermutations(arity, size)); | ||
146 | dataSourceNames.add("Random"); | ||
147 | dataSources.add(nRandoms(arity, size, 0)); | ||
148 | |||
149 | for(int dataSourceIndex = 0; dataSourceIndex<dataSourceNames.size(); dataSourceIndex++) { | ||
150 | for(int hashIndex = 0; hashIndex<hashNames.size(); hashIndex++) { | ||
151 | double clashes = calculateHashClashes(dataSources.get(dataSourceIndex),hashes.get(hashIndex)); | ||
152 | System.out.println( | ||
153 | size+","+arity+","+dataSourceNames.get(dataSourceIndex)+","+hashNames.get(hashIndex)+","+ | ||
154 | clashes+","+optimalClashes+","+(clashes+0.0)/optimalClashes); | ||
155 | } | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | } | ||
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/model/tests/ModelTest.java b/store/src/test/java/org/eclipse/viatra/solver/data/model/tests/ModelTest.java new file mode 100644 index 00000000..c9bf3da9 --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/model/tests/ModelTest.java | |||
@@ -0,0 +1,147 @@ | |||
1 | package org.eclipse.viatra.solver.data.model.tests; | ||
2 | |||
3 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
4 | import static org.junit.jupiter.api.Assertions.assertFalse; | ||
5 | import static org.junit.jupiter.api.Assertions.assertTrue; | ||
6 | |||
7 | import java.util.Set; | ||
8 | |||
9 | import org.eclipse.viatra.solver.data.model.Model; | ||
10 | import org.eclipse.viatra.solver.data.model.ModelStore; | ||
11 | import org.eclipse.viatra.solver.data.model.ModelStoreImpl; | ||
12 | import org.eclipse.viatra.solver.data.model.Tuple; | ||
13 | import org.eclipse.viatra.solver.data.model.representation.Relation; | ||
14 | import org.junit.jupiter.api.Assertions; | ||
15 | import org.junit.jupiter.api.Test; | ||
16 | |||
17 | class ModelTest { | ||
18 | |||
19 | @Test | ||
20 | void modelConstructionTest() { | ||
21 | Relation<Boolean> person = new Relation<>("Person", 1, false); | ||
22 | Relation<Boolean> friend = new Relation<>("friend", 2, false); | ||
23 | |||
24 | ModelStore store = new ModelStoreImpl(Set.of(person, friend)); | ||
25 | Model model = store.createModel(); | ||
26 | |||
27 | assertTrue(store.getDataRepresentations().contains(person)); | ||
28 | assertTrue(store.getDataRepresentations().contains(friend)); | ||
29 | assertTrue(model.getDataRepresentations().contains(person)); | ||
30 | assertTrue(model.getDataRepresentations().contains(friend)); | ||
31 | |||
32 | Relation<Integer> other = new Relation<Integer>("other", 2, null); | ||
33 | assertFalse(model.getDataRepresentations().contains(other)); | ||
34 | } | ||
35 | |||
36 | @Test | ||
37 | void modelBuildingTest() { | ||
38 | Relation<Boolean> person = new Relation<>("Person", 1, false); | ||
39 | Relation<Integer> age = new Relation<Integer>("age", 1, null); | ||
40 | Relation<Boolean> friend = new Relation<>("friend", 2, false); | ||
41 | |||
42 | ModelStore store = new ModelStoreImpl(Set.of(person, age, friend)); | ||
43 | Model model = store.createModel(); | ||
44 | |||
45 | model.put(person, Tuple.of(0), true); | ||
46 | model.put(person, Tuple.of(1), true); | ||
47 | model.put(age, Tuple.of(0), 3); | ||
48 | model.put(age, Tuple.of(1), 1); | ||
49 | model.put(friend, Tuple.of(0, 1), true); | ||
50 | model.put(friend, Tuple.of(1, 0), true); | ||
51 | |||
52 | assertTrue(model.get(person, Tuple.of(0))); | ||
53 | assertTrue(model.get(person, Tuple.of(1))); | ||
54 | assertFalse(model.get(person, Tuple.of(2))); | ||
55 | |||
56 | assertEquals(3, model.get(age, Tuple.of(0))); | ||
57 | assertEquals(1, model.get(age, Tuple.of(1))); | ||
58 | assertEquals(null, model.get(age, Tuple.of(2))); | ||
59 | |||
60 | assertTrue(model.get(friend, Tuple.of(0, 1))); | ||
61 | assertFalse(model.get(friend, Tuple.of(0, 5))); | ||
62 | } | ||
63 | |||
64 | @Test | ||
65 | void modelBuildingArityFailTest() { | ||
66 | Relation<Boolean> person = new Relation<>("Person", 1, false); | ||
67 | ModelStore store = new ModelStoreImpl(Set.of(person)); | ||
68 | Model model = store.createModel(); | ||
69 | |||
70 | final Tuple tuple3 = Tuple.of(1, 1, 1); | ||
71 | Assertions.assertThrows(IllegalArgumentException.class, () -> model.put(person, tuple3, true)); | ||
72 | Assertions.assertThrows(IllegalArgumentException.class, () -> model.get(person, tuple3)); | ||
73 | } | ||
74 | |||
75 | @Test | ||
76 | void modelBuildingNullFailTest() { | ||
77 | Relation<Integer> age = new Relation<Integer>("age", 1, null); | ||
78 | ModelStore store = new ModelStoreImpl(Set.of(age)); | ||
79 | Model model = store.createModel(); | ||
80 | |||
81 | model.put(age, Tuple.of(1), null); // valid | ||
82 | Assertions.assertThrows(IllegalArgumentException.class, () -> model.put(age, null, 1)); | ||
83 | Assertions.assertThrows(IllegalArgumentException.class, () -> model.get(age, null)); | ||
84 | |||
85 | } | ||
86 | |||
87 | @Test | ||
88 | void modelUpdateTest() { | ||
89 | Relation<Boolean> person = new Relation<>("Person", 1, false); | ||
90 | Relation<Integer> age = new Relation<Integer>("age", 1, null); | ||
91 | Relation<Boolean> friend = new Relation<>("friend", 2, false); | ||
92 | |||
93 | ModelStore store = new ModelStoreImpl(Set.of(person, age, friend)); | ||
94 | Model model = store.createModel(); | ||
95 | |||
96 | model.put(person, Tuple.of(0), true); | ||
97 | model.put(person, Tuple.of(1), true); | ||
98 | model.put(age, Tuple.of(0), 3); | ||
99 | model.put(age, Tuple.of(1), 1); | ||
100 | model.put(friend, Tuple.of(0, 1), true); | ||
101 | model.put(friend, Tuple.of(1, 0), true); | ||
102 | |||
103 | assertEquals(3, model.get(age, Tuple.of(0))); | ||
104 | assertTrue(model.get(friend, Tuple.of(0, 1))); | ||
105 | |||
106 | model.put(age, Tuple.of(0), 4); | ||
107 | model.put(friend, Tuple.of(0, 1), false); | ||
108 | |||
109 | assertEquals(4, model.get(age, Tuple.of(0))); | ||
110 | assertFalse(model.get(friend, Tuple.of(0, 1))); | ||
111 | } | ||
112 | |||
113 | @Test | ||
114 | void restoreTest() { | ||
115 | Relation<Boolean> person = new Relation<Boolean>("Person", 1, false); | ||
116 | Relation<Boolean> friend = new Relation<Boolean>("friend", 2, false); | ||
117 | |||
118 | ModelStore store = new ModelStoreImpl(Set.of(person, friend)); | ||
119 | Model model = store.createModel(); | ||
120 | |||
121 | model.put(person, Tuple.of(0), true); | ||
122 | model.put(person, Tuple.of(1), true); | ||
123 | model.put(friend, Tuple.of(0, 1), true); | ||
124 | model.put(friend, Tuple.of(1, 0), true); | ||
125 | long state1 = model.commit(); | ||
126 | |||
127 | assertFalse(model.get(person, Tuple.of(2))); | ||
128 | assertFalse(model.get(friend, Tuple.of(0, 2))); | ||
129 | |||
130 | model.put(person, Tuple.of(2), true); | ||
131 | model.put(friend, Tuple.of(0, 2), true); | ||
132 | long state2 = model.commit(); | ||
133 | |||
134 | assertTrue(model.get(person, Tuple.of(2))); | ||
135 | assertTrue(model.get(friend, Tuple.of(0, 2))); | ||
136 | |||
137 | model.restore(state1); | ||
138 | |||
139 | assertFalse(model.get(person, Tuple.of(2))); | ||
140 | assertFalse(model.get(friend, Tuple.of(0, 2))); | ||
141 | |||
142 | model.restore(state2); | ||
143 | |||
144 | assertTrue(model.get(person, Tuple.of(2))); | ||
145 | assertTrue(model.get(friend, Tuple.of(0, 2))); | ||
146 | } | ||
147 | } | ||
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/query/test/QueryTest.java b/store/src/test/java/org/eclipse/viatra/solver/data/query/test/QueryTest.java new file mode 100644 index 00000000..182f6c94 --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/query/test/QueryTest.java | |||
@@ -0,0 +1,89 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.test; | ||
2 | |||
3 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
4 | import static org.junit.jupiter.api.Assertions.assertFalse; | ||
5 | import static org.junit.jupiter.api.Assertions.assertTrue; | ||
6 | |||
7 | import java.util.Collection; | ||
8 | import java.util.Set; | ||
9 | |||
10 | import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine; | ||
11 | import org.eclipse.viatra.query.runtime.api.GenericPatternMatch; | ||
12 | import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher; | ||
13 | import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; | ||
14 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; | ||
15 | import org.eclipse.viatra.solver.data.model.Model; | ||
16 | import org.eclipse.viatra.solver.data.model.ModelStore; | ||
17 | import org.eclipse.viatra.solver.data.model.ModelStoreImpl; | ||
18 | import org.eclipse.viatra.solver.data.model.Tuple; | ||
19 | import org.eclipse.viatra.solver.data.model.representation.Relation; | ||
20 | import org.eclipse.viatra.solver.data.model.representation.TruthValue; | ||
21 | import org.eclipse.viatra.solver.data.query.RelationalScope; | ||
22 | import org.eclipse.viatra.solver.data.query.internal.PredicateTranslator; | ||
23 | import org.eclipse.viatra.solver.data.query.view.FilteredRelationView; | ||
24 | import org.eclipse.viatra.solver.data.query.view.FunctionalRelationView; | ||
25 | import org.eclipse.viatra.solver.data.query.view.RelationView; | ||
26 | import org.eclipse.viatra.solver.data.query.view.KeyOnlyRelationView; | ||
27 | import org.junit.jupiter.api.Test; | ||
28 | |||
29 | class QueryTest { | ||
30 | @Test | ||
31 | void minimalTest() { | ||
32 | Relation<Boolean> person = new Relation<>("Person", 1, false); | ||
33 | |||
34 | RelationView<Boolean> persionView = new KeyOnlyRelationView(person); | ||
35 | GenericQuerySpecification<GenericPatternMatcher> personQuery = (new PredicateTranslator("PersonQuery")) | ||
36 | .addParameter("p", persionView).addConstraint(persionView, "p").build(); | ||
37 | |||
38 | ModelStore store = new ModelStoreImpl(Set.of(person)); | ||
39 | Model model = store.createModel(); | ||
40 | |||
41 | model.put(person, Tuple.of(0), true); | ||
42 | model.put(person, Tuple.of(1), true); | ||
43 | |||
44 | RelationalScope scope = new RelationalScope(model, Set.of(persionView)); | ||
45 | |||
46 | ViatraQueryEngine engine = AdvancedViatraQueryEngine.on(scope); | ||
47 | GenericPatternMatcher personMatcher = engine.getMatcher(personQuery); | ||
48 | |||
49 | assertEquals(2, personMatcher.countMatches()); | ||
50 | } | ||
51 | |||
52 | void modelBuildingTest() { | ||
53 | Relation<Boolean> person = new Relation<>("Person", 1, false); | ||
54 | Relation<Integer> age = new Relation<Integer>("age", 1, null); | ||
55 | Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.False); | ||
56 | |||
57 | ModelStore store = new ModelStoreImpl(Set.of(person, age, friend)); | ||
58 | Model model = store.createModel(); | ||
59 | |||
60 | model.put(person, Tuple.of(0), true); | ||
61 | model.put(person, Tuple.of(1), true); | ||
62 | model.put(age, Tuple.of(0), 3); | ||
63 | model.put(age, Tuple.of(1), 1); | ||
64 | model.put(friend, Tuple.of(0, 1), TruthValue.True); | ||
65 | model.put(friend, Tuple.of(1, 0), TruthValue.Unknown); | ||
66 | |||
67 | // Sanity check | ||
68 | assertTrue(model.get(person, Tuple.of(0))); | ||
69 | assertTrue(model.get(person, Tuple.of(1))); | ||
70 | assertFalse(model.get(person, Tuple.of(2))); | ||
71 | |||
72 | RelationView<Boolean> persionView = new KeyOnlyRelationView(person); | ||
73 | RelationView<Integer> ageView = new FunctionalRelationView<>(age); | ||
74 | RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must()); | ||
75 | RelationView<TruthValue> friendMayView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.may()); | ||
76 | |||
77 | RelationalScope scope = new RelationalScope(model, Set.of(persionView, ageView, friendMustView, friendMayView)); | ||
78 | |||
79 | GenericQuerySpecification<GenericPatternMatcher> personQuery = (new PredicateTranslator("PersonQuery")) | ||
80 | .addParameter("p", persionView).addConstraint(persionView, "p").build(); | ||
81 | |||
82 | ViatraQueryEngine engine = AdvancedViatraQueryEngine.on(scope); | ||
83 | GenericPatternMatcher personMatcher = engine.getMatcher(personQuery); | ||
84 | Collection<GenericPatternMatch> personMatches = personMatcher.getAllMatches(); | ||
85 | for (GenericPatternMatch personMatch : personMatches) { | ||
86 | System.out.println(personMatch); | ||
87 | } | ||
88 | } | ||
89 | } \ No newline at end of file | ||
diff --git a/store/src/test/java/org/eclipse/viatra/solver/data/util/CollectionsUtilTests.java b/store/src/test/java/org/eclipse/viatra/solver/data/util/CollectionsUtilTests.java new file mode 100644 index 00000000..16368912 --- /dev/null +++ b/store/src/test/java/org/eclipse/viatra/solver/data/util/CollectionsUtilTests.java | |||
@@ -0,0 +1,77 @@ | |||
1 | package org.eclipse.viatra.solver.data.util; | ||
2 | |||
3 | import java.util.ArrayList; | ||
4 | import java.util.Iterator; | ||
5 | import java.util.List; | ||
6 | import java.util.NoSuchElementException; | ||
7 | |||
8 | import org.junit.jupiter.api.Assertions; | ||
9 | import org.junit.jupiter.api.Test; | ||
10 | |||
11 | import static org.eclipse.viatra.solver.data.util.CollectionsUtil.*; | ||
12 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
13 | |||
14 | class CollectionsUtilTests { | ||
15 | List<Integer> list10 = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); | ||
16 | List<String> listTen = List.of("1", "2", "3", "4", "5", "6", "7", "8", "9", "10"); | ||
17 | |||
18 | private static <T> void compare(Iterable<T> a, Iterable<T> b) { | ||
19 | List<T> listA = toList(a); | ||
20 | List<T> listB = toList(b); | ||
21 | assertEquals(listA, listB); | ||
22 | } | ||
23 | |||
24 | private static <T> List<T> toList(Iterable<T> a) { | ||
25 | List<T> result = new ArrayList<T>(); | ||
26 | Iterator<T> iterator = a.iterator(); | ||
27 | while (iterator.hasNext()) { | ||
28 | result.add(iterator.next()); | ||
29 | } | ||
30 | return result; | ||
31 | } | ||
32 | |||
33 | @Test | ||
34 | void testFilterEven() { | ||
35 | compare(List.of(2, 4, 6, 8, 10), filter(list10, (x -> x % 2 == 0))); | ||
36 | } | ||
37 | |||
38 | @Test | ||
39 | void testFilterOdd() { | ||
40 | compare(List.of(1, 3, 5, 7, 9), filter(list10, (x -> x % 2 == 1))); | ||
41 | } | ||
42 | |||
43 | @Test | ||
44 | void testFilterFalse() { | ||
45 | compare(List.of(), filter(list10, (x -> false))); | ||
46 | } | ||
47 | |||
48 | @Test | ||
49 | void testFilterTrue() { | ||
50 | compare(list10, filter(list10, (x -> true))); | ||
51 | } | ||
52 | |||
53 | @Test | ||
54 | void testFilterEmpty() { | ||
55 | compare(List.of(), filter(List.of(), (x -> true))); | ||
56 | } | ||
57 | |||
58 | @Test() | ||
59 | void testNoSuchElement() { | ||
60 | Iterable<Integer> iterable = filter(list10, (x -> x % 2 == 0)); | ||
61 | Iterator<Integer> iterator = iterable.iterator(); | ||
62 | while (iterator.hasNext()) { | ||
63 | iterator.next(); | ||
64 | } | ||
65 | Assertions.assertThrows(NoSuchElementException.class, () -> iterator.next()); | ||
66 | } | ||
67 | |||
68 | @Test() | ||
69 | void mapTest() { | ||
70 | compare(listTen, map(list10, x -> x.toString())); | ||
71 | } | ||
72 | |||
73 | @Test() | ||
74 | void mapEmtyTest() { | ||
75 | compare(List.of(), map(List.of(), x -> x.toString())); | ||
76 | } | ||
77 | } | ||