diff options
author | nagilooh <ficsorattila96@gmail.com> | 2023-08-02 14:07:35 +0200 |
---|---|---|
committer | nagilooh <ficsorattila96@gmail.com> | 2023-08-02 14:07:35 +0200 |
commit | c93d455d2459c2fbe0cfce7693d592986f65d44c (patch) | |
tree | cd29acd462c7934ed26ba1a7370b721033841e63 /subprojects/store-dse/src/test/java | |
parent | Merge remote-tracking branch 'origin/main' into design-space-exploration (diff) | |
download | refinery-c93d455d2459c2fbe0cfce7693d592986f65d44c.tar.gz refinery-c93d455d2459c2fbe0cfce7693d592986f65d44c.tar.zst refinery-c93d455d2459c2fbe0cfce7693d592986f65d44c.zip |
Move DSE to new subproject
Diffstat (limited to 'subprojects/store-dse/src/test/java')
5 files changed, 1338 insertions, 0 deletions
diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/CRAExamplesTest.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/CRAExamplesTest.java new file mode 100644 index 00000000..e7cc60d6 --- /dev/null +++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/CRAExamplesTest.java | |||
@@ -0,0 +1,274 @@ | |||
1 | package tools.refinery.store.dse; | ||
2 | |||
3 | import org.junit.jupiter.api.Test; | ||
4 | import tools.refinery.store.model.ModelStore; | ||
5 | import tools.refinery.store.query.ModelQueryAdapter; | ||
6 | import tools.refinery.store.query.dnf.Query; | ||
7 | import tools.refinery.store.query.dnf.RelationalQuery; | ||
8 | import tools.refinery.store.dse.internal.TransformationRule; | ||
9 | import tools.refinery.store.dse.strategy.BestFirstStrategy; | ||
10 | import tools.refinery.store.dse.strategy.DepthFirstStrategy; | ||
11 | import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; | ||
12 | import tools.refinery.store.query.view.AnySymbolView; | ||
13 | import tools.refinery.store.query.view.KeyOnlyView; | ||
14 | import tools.refinery.store.representation.Symbol; | ||
15 | import tools.refinery.store.tuple.Tuple; | ||
16 | import tools.refinery.visualization.ModelVisualizerAdapter; | ||
17 | import tools.refinery.visualization.internal.FileFormat; | ||
18 | |||
19 | import java.util.List; | ||
20 | |||
21 | import static tools.refinery.store.query.literal.Literals.not; | ||
22 | |||
23 | public class CRAExamplesTest { | ||
24 | private static final Symbol<String> name = Symbol.of("Name", 1, String.class); | ||
25 | |||
26 | // private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1); | ||
27 | private static final Symbol<Boolean> classElement = Symbol.of("ClassElement", 1); | ||
28 | // private static final Symbol<Boolean> feature = Symbol.of("Feature", 1); | ||
29 | private static final Symbol<Boolean> attribute = Symbol.of("Attribute", 1); | ||
30 | private static final Symbol<Boolean> method = Symbol.of("Method", 1); | ||
31 | |||
32 | // private static final Symbol<Boolean> isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); | ||
33 | private static final Symbol<Boolean> encapsulates = Symbol.of("Encapsulates", 2); | ||
34 | private static final Symbol<Boolean> dataDependency = Symbol.of("DataDependency", 2); | ||
35 | private static final Symbol<Boolean> functionalDependency = Symbol.of("FunctionalDependency", 2); | ||
36 | |||
37 | private static final Symbol<Boolean> features = Symbol.of("Features", 2); | ||
38 | private static final Symbol<Boolean> classes = Symbol.of("Classes", 2); | ||
39 | |||
40 | // private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); | ||
41 | private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); | ||
42 | // private static final AnySymbolView featureView = new KeyOnlyView<>(feature); | ||
43 | private static final AnySymbolView attributeView = new KeyOnlyView<>(attribute); | ||
44 | private static final AnySymbolView methodView = new KeyOnlyView<>(method); | ||
45 | // private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); | ||
46 | private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); | ||
47 | private static final AnySymbolView dataDependencyView = new KeyOnlyView<>(dataDependency); | ||
48 | private static final AnySymbolView functionalDependencyView = new KeyOnlyView<>(functionalDependency); | ||
49 | private static final AnySymbolView featuresView = new KeyOnlyView<>(features); | ||
50 | private static final AnySymbolView classesView = new KeyOnlyView<>(classes); | ||
51 | |||
52 | /*Example Transformation rules*/ | ||
53 | private static final RelationalQuery feature = Query.of("Feature", | ||
54 | (builder, f) -> builder.clause( | ||
55 | attributeView.call(f)) | ||
56 | .clause( | ||
57 | methodView.call(f)) | ||
58 | ); | ||
59 | |||
60 | private static final RelationalQuery assignFeaturePreconditionHelper = Query.of("AssignFeaturePreconditionHelper", | ||
61 | (builder, c, f) -> builder.clause( | ||
62 | classElementView.call(c), | ||
63 | // classesView.call(model, c), | ||
64 | encapsulatesView.call(c, f) | ||
65 | )); | ||
66 | |||
67 | private static final RelationalQuery assignFeaturePrecondition = Query.of("AssignFeaturePrecondition", | ||
68 | (builder, f, c1) -> builder.clause((c2) -> List.of( | ||
69 | // classModelView.call(model), | ||
70 | feature.call(f), | ||
71 | classElementView.call(c1), | ||
72 | // featuresView.call(model, f), | ||
73 | not(assignFeaturePreconditionHelper.call(c2, f)), | ||
74 | not(encapsulatesView.call(c1, f)) | ||
75 | ))); | ||
76 | |||
77 | private static final RelationalQuery deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", | ||
78 | (builder, c) -> builder.clause((f) -> List.of( | ||
79 | // classModelView.call(model), | ||
80 | classElementView.call(c), | ||
81 | // featuresView.call(model, f), | ||
82 | not(encapsulatesView.call(c, f)) | ||
83 | ))); | ||
84 | |||
85 | private static final RelationalQuery createClassPreconditionHelper = Query.of("CreateClassPreconditionHelper", | ||
86 | (builder, f, c) -> builder.clause( | ||
87 | classElementView.call(c), | ||
88 | // classesView.call(model, c), | ||
89 | encapsulatesView.call(c, f) | ||
90 | )); | ||
91 | |||
92 | private static final RelationalQuery createClassPrecondition = Query.of("CreateClassPrecondition", | ||
93 | (builder, f) -> builder.clause((c) -> List.of( | ||
94 | // classModelView.call(model), | ||
95 | feature.call(f), | ||
96 | not(createClassPreconditionHelper.call(f, c)) | ||
97 | ))); | ||
98 | |||
99 | private static final RelationalQuery moveFeaturePrecondition = Query.of("MoveFeature", | ||
100 | (builder, c1, c2, f) -> builder.clause( | ||
101 | // classModelView.call(model), | ||
102 | classElementView.call(c1), | ||
103 | classElementView.call(c2), | ||
104 | c1.notEquivalent(c2), | ||
105 | feature.call(f), | ||
106 | // classesView.call(model, c1), | ||
107 | // classesView.call(model, c2), | ||
108 | // featuresView.call(model, f), | ||
109 | encapsulatesView.call(c1, f) | ||
110 | )); | ||
111 | |||
112 | private static final TransformationRule assignFeatureRule = new TransformationRule("AssignFeature", | ||
113 | assignFeaturePrecondition, | ||
114 | (model) -> { | ||
115 | // var isEncapsulatedByInterpretation = model.getInterpretation(isEncapsulatedBy); | ||
116 | var encapsulatesInterpretation = model.getInterpretation(encapsulates); | ||
117 | return ((Tuple activation) -> { | ||
118 | var feature = activation.get(0); | ||
119 | var classElement = activation.get(1); | ||
120 | |||
121 | // isEncapsulatedByInterpretation.put(Tuple.of(feature, classElement), true); | ||
122 | encapsulatesInterpretation.put(Tuple.of(classElement, feature), true); | ||
123 | }); | ||
124 | }); | ||
125 | |||
126 | private static final TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass", | ||
127 | deleteEmptyClassPrecondition, | ||
128 | (model) -> { | ||
129 | // var classesInterpretation = model.getInterpretation(classes); | ||
130 | var classElementInterpretation = model.getInterpretation(classElement); | ||
131 | return ((Tuple activation) -> { | ||
132 | // TODO: can we move dseAdapter outside? | ||
133 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
134 | // var modelElement = activation.get(0); | ||
135 | var classElement = activation.get(0); | ||
136 | |||
137 | // classesInterpretation.put(Tuple.of(modelElement, classElement), false); | ||
138 | classElementInterpretation.put(Tuple.of(classElement), false); | ||
139 | dseAdapter.deleteObject(Tuple.of(classElement)); | ||
140 | }); | ||
141 | }); | ||
142 | |||
143 | private static final TransformationRule createClassRule = new TransformationRule("CreateClass", | ||
144 | createClassPrecondition, | ||
145 | (model) -> { | ||
146 | var classElementInterpretation = model.getInterpretation(classElement); | ||
147 | // var classesInterpretation = model.getInterpretation(classes); | ||
148 | var encapsulatesInterpretation = model.getInterpretation(encapsulates); | ||
149 | return ((Tuple activation) -> { | ||
150 | // TODO: can we move dseAdapter outside? | ||
151 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
152 | // var modelElement = activation.get(0); | ||
153 | var feature = activation.get(0); | ||
154 | |||
155 | var newClassElement = dseAdapter.createObject(); | ||
156 | var newClassElementId = newClassElement.get(0); | ||
157 | classElementInterpretation.put(newClassElement, true); | ||
158 | // classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); | ||
159 | encapsulatesInterpretation.put(Tuple.of(newClassElementId, feature), true); | ||
160 | }); | ||
161 | }); | ||
162 | |||
163 | private static final TransformationRule moveFeatureRule = new TransformationRule("MoveFeature", | ||
164 | moveFeaturePrecondition, | ||
165 | (model) -> { | ||
166 | var encapsulatesInterpretation = model.getInterpretation(encapsulates); | ||
167 | return ((Tuple activation) -> { | ||
168 | var classElement1 = activation.get(0); | ||
169 | var classElement2 = activation.get(1); | ||
170 | var feature = activation.get(2); | ||
171 | |||
172 | encapsulatesInterpretation.put(Tuple.of(classElement1, feature), false); | ||
173 | encapsulatesInterpretation.put(Tuple.of(classElement2, feature), true); | ||
174 | }); | ||
175 | }); | ||
176 | |||
177 | @Test | ||
178 | void craTest() { | ||
179 | var store = ModelStore.builder() | ||
180 | .symbols(classElement, encapsulates, classes, features, attribute, method, dataDependency, | ||
181 | functionalDependency, name) | ||
182 | .with(ViatraModelQueryAdapter.builder() | ||
183 | .queries(feature, assignFeaturePreconditionHelper, assignFeaturePrecondition, | ||
184 | deleteEmptyClassPrecondition, createClassPreconditionHelper, createClassPrecondition, | ||
185 | moveFeaturePrecondition)) | ||
186 | .with(ModelVisualizerAdapter.builder()) | ||
187 | .with(DesignSpaceExplorationAdapter.builder() | ||
188 | .transformations(assignFeatureRule, deleteEmptyClassRule, createClassRule, moveFeatureRule) | ||
189 | // .strategy(new DepthFirstStrategy(3).continueIfHardObjectivesFulfilled() | ||
190 | .strategy(new BestFirstStrategy(6).continueIfHardObjectivesFulfilled() | ||
191 | // .goOnOnlyIfFitnessIsBetter() | ||
192 | )) | ||
193 | .build(); | ||
194 | |||
195 | var model = store.createEmptyModel(); | ||
196 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
197 | // dseAdapter.setRandom(1); | ||
198 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
199 | |||
200 | // var modelInterpretation = model.getInterpretation(classModel); | ||
201 | var nameInterpretation = model.getInterpretation(name); | ||
202 | var methodInterpretation = model.getInterpretation(method); | ||
203 | var attributeInterpretation = model.getInterpretation(attribute); | ||
204 | var dataDependencyInterpretation = model.getInterpretation(dataDependency); | ||
205 | var functionalDependencyInterpretation = model.getInterpretation(functionalDependency); | ||
206 | |||
207 | // var modelElement = dseAdapter.createObject(); | ||
208 | var method1 = dseAdapter.createObject(); | ||
209 | var method1Id = method1.get(0); | ||
210 | var method2 = dseAdapter.createObject(); | ||
211 | var method2Id = method2.get(0); | ||
212 | var method3 = dseAdapter.createObject(); | ||
213 | var method3Id = method3.get(0); | ||
214 | var method4 = dseAdapter.createObject(); | ||
215 | var method4Id = method4.get(0); | ||
216 | var attribute1 = dseAdapter.createObject(); | ||
217 | var attribute1Id = attribute1.get(0); | ||
218 | var attribute2 = dseAdapter.createObject(); | ||
219 | var attribute2Id = attribute2.get(0); | ||
220 | var attribute3 = dseAdapter.createObject(); | ||
221 | var attribute3Id = attribute3.get(0); | ||
222 | var attribute4 = dseAdapter.createObject(); | ||
223 | var attribute4Id = attribute4.get(0); | ||
224 | var attribute5 = dseAdapter.createObject(); | ||
225 | var attribute5Id = attribute5.get(0); | ||
226 | |||
227 | nameInterpretation.put(method1, "M1"); | ||
228 | nameInterpretation.put(method2, "M2"); | ||
229 | nameInterpretation.put(method3, "M3"); | ||
230 | nameInterpretation.put(method4, "M4"); | ||
231 | nameInterpretation.put(attribute1, "A1"); | ||
232 | nameInterpretation.put(attribute2, "A2"); | ||
233 | nameInterpretation.put(attribute3, "A3"); | ||
234 | nameInterpretation.put(attribute4, "A4"); | ||
235 | nameInterpretation.put(attribute5, "A5"); | ||
236 | |||
237 | |||
238 | |||
239 | // modelInterpretation.put(modelElement, true); | ||
240 | methodInterpretation.put(method1, true); | ||
241 | methodInterpretation.put(method2, true); | ||
242 | methodInterpretation.put(method3, true); | ||
243 | methodInterpretation.put(method4, true); | ||
244 | attributeInterpretation.put(attribute1, true); | ||
245 | attributeInterpretation.put(attribute2, true); | ||
246 | attributeInterpretation.put(attribute3, true); | ||
247 | attributeInterpretation.put(attribute4, true); | ||
248 | attributeInterpretation.put(attribute5, true); | ||
249 | |||
250 | dataDependencyInterpretation.put(Tuple.of(method1Id, attribute1Id), true); | ||
251 | dataDependencyInterpretation.put(Tuple.of(method1Id, attribute3Id), true); | ||
252 | dataDependencyInterpretation.put(Tuple.of(method2Id, attribute2Id), true); | ||
253 | dataDependencyInterpretation.put(Tuple.of(method3Id, attribute3Id), true); | ||
254 | dataDependencyInterpretation.put(Tuple.of(method3Id, attribute4Id), true); | ||
255 | dataDependencyInterpretation.put(Tuple.of(method4Id, attribute3Id), true); | ||
256 | dataDependencyInterpretation.put(Tuple.of(method4Id, attribute5Id), true); | ||
257 | |||
258 | functionalDependencyInterpretation.put(Tuple.of(method1Id, attribute3Id), true); | ||
259 | functionalDependencyInterpretation.put(Tuple.of(method1Id, attribute4Id), true); | ||
260 | functionalDependencyInterpretation.put(Tuple.of(method2Id, attribute1Id), true); | ||
261 | functionalDependencyInterpretation.put(Tuple.of(method3Id, attribute1Id), true); | ||
262 | functionalDependencyInterpretation.put(Tuple.of(method3Id, attribute4Id), true); | ||
263 | functionalDependencyInterpretation.put(Tuple.of(method4Id, attribute2Id), true); | ||
264 | |||
265 | queryEngine.flushChanges(); | ||
266 | |||
267 | var states = dseAdapter.explore(); | ||
268 | System.out.println("states size: " + states.size()); | ||
269 | System.out.println("states: " + states); | ||
270 | var visualizer = model.getAdapter(ModelVisualizerAdapter.class); | ||
271 | visualizer.renderDesignSpace("test_output", FileFormat.SVG); | ||
272 | } | ||
273 | |||
274 | } | ||
diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DebugTest.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DebugTest.java new file mode 100644 index 00000000..911c0661 --- /dev/null +++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DebugTest.java | |||
@@ -0,0 +1,117 @@ | |||
1 | package tools.refinery.store.dse; | ||
2 | |||
3 | import org.junit.jupiter.api.Test; | ||
4 | import tools.refinery.store.model.ModelStore; | ||
5 | import tools.refinery.store.query.ModelQueryAdapter; | ||
6 | import tools.refinery.store.query.dnf.Query; | ||
7 | import tools.refinery.store.dse.internal.TransformationRule; | ||
8 | import tools.refinery.store.dse.strategy.BestFirstStrategy; | ||
9 | import tools.refinery.store.dse.strategy.DepthFirstStrategy; | ||
10 | import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; | ||
11 | import tools.refinery.store.query.view.AnySymbolView; | ||
12 | import tools.refinery.store.query.view.KeyOnlyView; | ||
13 | import tools.refinery.store.representation.Symbol; | ||
14 | import tools.refinery.store.tuple.Tuple; | ||
15 | import tools.refinery.visualization.ModelVisualizerAdapter; | ||
16 | import tools.refinery.visualization.internal.FileFormat; | ||
17 | |||
18 | public class DebugTest { | ||
19 | private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1); | ||
20 | private static final Symbol<Boolean> classElement = Symbol.of("ClassElement", 1); | ||
21 | private static final Symbol<Boolean> feature = Symbol.of("Feature", 1); | ||
22 | |||
23 | private static final Symbol<Boolean> isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); | ||
24 | private static final Symbol<Boolean> encapsulates = Symbol.of("Encapsulates", 2); | ||
25 | |||
26 | private static final Symbol<Boolean> features = Symbol.of("Features", 2); | ||
27 | private static final Symbol<Boolean> classes = Symbol.of("Classes", 2); | ||
28 | |||
29 | private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); | ||
30 | private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); | ||
31 | private static final AnySymbolView featureView = new KeyOnlyView<>(feature); | ||
32 | private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); | ||
33 | private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); | ||
34 | private static final AnySymbolView featuresView = new KeyOnlyView<>(features); | ||
35 | private static final AnySymbolView classesView = new KeyOnlyView<>(classes); | ||
36 | |||
37 | |||
38 | @Test | ||
39 | void BFSTest() { | ||
40 | var createClassPrecondition = Query.of("CreateClassPrecondition", | ||
41 | (builder, model) -> builder.clause( | ||
42 | classModelView.call(model) | ||
43 | )); | ||
44 | |||
45 | var createClassRule = new TransformationRule("CreateClass", | ||
46 | createClassPrecondition, | ||
47 | (model) -> { | ||
48 | var classesInterpretation = model.getInterpretation(classes); | ||
49 | var classElementInterpretation = model.getInterpretation(classElement); | ||
50 | return ((Tuple activation) -> { | ||
51 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
52 | var modelElement = activation.get(0); | ||
53 | |||
54 | var newClassElement = dseAdapter.createObject(); | ||
55 | var newClassElementId = newClassElement.get(0); | ||
56 | |||
57 | classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); | ||
58 | classElementInterpretation.put(Tuple.of(newClassElementId), true); | ||
59 | }); | ||
60 | }); | ||
61 | |||
62 | var createFeaturePrecondition = Query.of("CreateFeaturePrecondition", | ||
63 | (builder, model) -> builder.clause( | ||
64 | classModelView.call(model) | ||
65 | )); | ||
66 | |||
67 | var createFeatureRule = new TransformationRule("CreateFeature", | ||
68 | createFeaturePrecondition, | ||
69 | (model) -> { | ||
70 | var featuresInterpretation = model.getInterpretation(features); | ||
71 | var featureInterpretation = model.getInterpretation(feature); | ||
72 | return ((Tuple activation) -> { | ||
73 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
74 | var modelElement = activation.get(0); | ||
75 | |||
76 | var newClassElement = dseAdapter.createObject(); | ||
77 | var newClassElementId = newClassElement.get(0); | ||
78 | |||
79 | featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true); | ||
80 | featureInterpretation.put(Tuple.of(newClassElementId), true); | ||
81 | }); | ||
82 | }); | ||
83 | |||
84 | var store = ModelStore.builder() | ||
85 | .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) | ||
86 | .with(ViatraModelQueryAdapter.builder() | ||
87 | .queries(createClassPrecondition, createFeaturePrecondition)) | ||
88 | .with(ModelVisualizerAdapter.builder()) | ||
89 | .with(DesignSpaceExplorationAdapter.builder() | ||
90 | .transformations(createClassRule, createFeatureRule) | ||
91 | .strategy(new DepthFirstStrategy(4).continueIfHardObjectivesFulfilled() | ||
92 | // .strategy(new BestFirstStrategy(4).continueIfHardObjectivesFulfilled() | ||
93 | // .goOnOnlyIfFitnessIsBetter() | ||
94 | )) | ||
95 | .build(); | ||
96 | |||
97 | var model = store.createEmptyModel(); | ||
98 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
99 | // dseAdapter.setRandom(1); | ||
100 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
101 | |||
102 | var modelElementInterpretation = model.getInterpretation(classModel); | ||
103 | var classElementInterpretation = model.getInterpretation(classElement); | ||
104 | var modelElement = dseAdapter.createObject(); | ||
105 | modelElementInterpretation.put(modelElement, true); | ||
106 | classElementInterpretation.put(modelElement, true); | ||
107 | queryEngine.flushChanges(); | ||
108 | |||
109 | |||
110 | var states = dseAdapter.explore(); | ||
111 | var visualizer = model.getAdapter(ModelVisualizerAdapter.class); | ||
112 | visualizer.renderDesignSpace("test_output", FileFormat.SVG); | ||
113 | System.out.println("states size: " + states.size()); | ||
114 | System.out.println("states: " + states); | ||
115 | |||
116 | } | ||
117 | } | ||
diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DesignSpaceExplorationTest.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DesignSpaceExplorationTest.java new file mode 100644 index 00000000..c454f4ec --- /dev/null +++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DesignSpaceExplorationTest.java | |||
@@ -0,0 +1,487 @@ | |||
1 | package tools.refinery.store.dse; | ||
2 | |||
3 | import org.junit.jupiter.api.Test; | ||
4 | import tools.refinery.store.model.ModelStore; | ||
5 | import tools.refinery.store.query.ModelQueryAdapter; | ||
6 | import tools.refinery.store.query.dnf.Query; | ||
7 | import tools.refinery.store.dse.internal.TransformationRule; | ||
8 | import tools.refinery.store.dse.strategy.BestFirstStrategy; | ||
9 | import tools.refinery.store.dse.strategy.DepthFirstStrategy; | ||
10 | import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; | ||
11 | import tools.refinery.store.query.view.AnySymbolView; | ||
12 | import tools.refinery.store.query.view.KeyOnlyView; | ||
13 | import tools.refinery.store.representation.Symbol; | ||
14 | import tools.refinery.store.tuple.Tuple; | ||
15 | import tools.refinery.visualization.ModelVisualizerAdapter; | ||
16 | |||
17 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
18 | |||
19 | public class DesignSpaceExplorationTest { | ||
20 | // private static final Symbol<Boolean> namedElement = Symbol.of("NamedElement", 1); | ||
21 | // private static final Symbol<Boolean> attribute = Symbol.of("Attribute", 1); | ||
22 | // private static final Symbol<Boolean> method = Symbol.of("Method", 1); | ||
23 | // private static final Symbol<Boolean> dataDependency = Symbol.of("DataDependency", 2); | ||
24 | // private static final Symbol<Boolean> functionalDependency = Symbol.of("FunctionalDependency", 2); | ||
25 | |||
26 | private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1); | ||
27 | private static final Symbol<Boolean> classElement = Symbol.of("ClassElement", 1); | ||
28 | private static final Symbol<Boolean> feature = Symbol.of("Feature", 1); | ||
29 | |||
30 | private static final Symbol<Boolean> isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); | ||
31 | private static final Symbol<Boolean> encapsulates = Symbol.of("Encapsulates", 2); | ||
32 | |||
33 | private static final Symbol<Boolean> features = Symbol.of("Features", 2); | ||
34 | private static final Symbol<Boolean> classes = Symbol.of("Classes", 2); | ||
35 | |||
36 | private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); | ||
37 | private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); | ||
38 | private static final AnySymbolView featureView = new KeyOnlyView<>(feature); | ||
39 | private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); | ||
40 | private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); | ||
41 | private static final AnySymbolView featuresView = new KeyOnlyView<>(features); | ||
42 | private static final AnySymbolView classesView = new KeyOnlyView<>(classes); | ||
43 | |||
44 | @Test | ||
45 | void createObjectTest() { | ||
46 | var store = ModelStore.builder() | ||
47 | .with(ViatraModelQueryAdapter.builder()) | ||
48 | .with(DesignSpaceExplorationAdapter.builder()) | ||
49 | .build(); | ||
50 | |||
51 | var model = store.createEmptyModel(); | ||
52 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
53 | |||
54 | assertEquals(0, dseAdapter.getModelSize()); | ||
55 | |||
56 | var newModel = dseAdapter.createObject(); | ||
57 | var newModelId = newModel.get(0); | ||
58 | var newClass1 = dseAdapter.createObject(); | ||
59 | var newClass1Id = newClass1.get(0); | ||
60 | var newClass2 = dseAdapter.createObject(); | ||
61 | var newClass2Id = newClass2.get(0); | ||
62 | var newField = dseAdapter.createObject(); | ||
63 | var newFieldId = newField.get(0); | ||
64 | |||
65 | assertEquals(0, newModelId); | ||
66 | assertEquals(1, newClass1Id); | ||
67 | assertEquals(2, newClass2Id); | ||
68 | assertEquals(3, newFieldId); | ||
69 | assertEquals(4, dseAdapter.getModelSize()); | ||
70 | } | ||
71 | |||
72 | @Test | ||
73 | void deleteMiddleObjectTest() { | ||
74 | var store = ModelStore.builder() | ||
75 | .with(ViatraModelQueryAdapter.builder()) | ||
76 | .with(DesignSpaceExplorationAdapter.builder()) | ||
77 | .build(); | ||
78 | |||
79 | var model = store.createEmptyModel(); | ||
80 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
81 | |||
82 | assertEquals(0, dseAdapter.getModelSize()); | ||
83 | |||
84 | var newObject0 = dseAdapter.createObject(); | ||
85 | var newObject0Id = newObject0.get(0); | ||
86 | var newObject1 = dseAdapter.createObject(); | ||
87 | var newObject1Id = newObject1.get(0); | ||
88 | var newObject2 = dseAdapter.createObject(); | ||
89 | var newObject2Id = newObject2.get(0); | ||
90 | var newObject3 = dseAdapter.createObject(); | ||
91 | var newObject3Id = newObject3.get(0); | ||
92 | |||
93 | assertEquals(0, newObject0Id); | ||
94 | assertEquals(1, newObject1Id); | ||
95 | assertEquals(2, newObject2Id); | ||
96 | assertEquals(3, newObject3Id); | ||
97 | assertEquals(4, dseAdapter.getModelSize()); | ||
98 | |||
99 | dseAdapter.deleteObject(newObject1); | ||
100 | assertEquals(4, dseAdapter.getModelSize()); | ||
101 | |||
102 | var newObject4 = dseAdapter.createObject(); | ||
103 | var newObject4Id = newObject4.get(0); | ||
104 | assertEquals(4, newObject4Id); | ||
105 | assertEquals(5, dseAdapter.getModelSize()); | ||
106 | |||
107 | dseAdapter.deleteObject(newObject4); | ||
108 | assertEquals(5, dseAdapter.getModelSize()); | ||
109 | } | ||
110 | |||
111 | @Test | ||
112 | void DFSTrivialTest() { | ||
113 | var store = ModelStore.builder() | ||
114 | .symbols(classModel) | ||
115 | .with(ViatraModelQueryAdapter.builder()) | ||
116 | .with(ModelVisualizerAdapter.builder()) | ||
117 | .with(DesignSpaceExplorationAdapter.builder() | ||
118 | .strategy(new DepthFirstStrategy(0))) | ||
119 | .build(); | ||
120 | |||
121 | var model = store.createEmptyModel(); | ||
122 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
123 | |||
124 | var states = dseAdapter.explore(); | ||
125 | assertEquals(1, states.size()); | ||
126 | assertEquals(0, states.iterator().next()); | ||
127 | } | ||
128 | |||
129 | @Test | ||
130 | void DFSOneRuleTest() { | ||
131 | var createClassPrecondition = Query.of("CreateClassPrecondition", | ||
132 | (builder, model) -> builder.clause( | ||
133 | classModelView.call(model) | ||
134 | )); | ||
135 | |||
136 | var createClassRule = new TransformationRule("CreateClass", | ||
137 | createClassPrecondition, | ||
138 | (model) -> { | ||
139 | var classesInterpretation = model.getInterpretation(classes); | ||
140 | var classElementInterpretation = model.getInterpretation(classElement); | ||
141 | return ((Tuple activation) -> { | ||
142 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
143 | var modelElement = activation.get(0); | ||
144 | |||
145 | var newClassElement = dseAdapter.createObject(); | ||
146 | var newClassElementId = newClassElement.get(0); | ||
147 | |||
148 | classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); | ||
149 | classElementInterpretation.put(Tuple.of(newClassElementId), true); | ||
150 | }); | ||
151 | }); | ||
152 | |||
153 | var store = ModelStore.builder() | ||
154 | .symbols(classModel, classElement, classes) | ||
155 | .with(ViatraModelQueryAdapter.builder() | ||
156 | .queries(createClassPrecondition)) | ||
157 | .with(ModelVisualizerAdapter.builder()) | ||
158 | .with(DesignSpaceExplorationAdapter.builder() | ||
159 | .transformations(createClassRule) | ||
160 | .strategy(new DepthFirstStrategy(4) | ||
161 | )) | ||
162 | .build(); | ||
163 | |||
164 | var model = store.createEmptyModel(); | ||
165 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
166 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
167 | |||
168 | var modelElementInterpretation = model.getInterpretation(classModel); | ||
169 | modelElementInterpretation.put(dseAdapter.createObject(), true); | ||
170 | queryEngine.flushChanges(); | ||
171 | |||
172 | var states = dseAdapter.explore(); | ||
173 | assertEquals(1, states.size()); | ||
174 | assertEquals(0, states.iterator().next()); | ||
175 | } | ||
176 | |||
177 | @Test | ||
178 | void DFSContinueTest() { | ||
179 | var createClassPrecondition = Query.of("CreateClassPrecondition", | ||
180 | (builder, model) -> builder.clause( | ||
181 | classModelView.call(model) | ||
182 | )); | ||
183 | |||
184 | var createClassRule = new TransformationRule("CreateClass", | ||
185 | createClassPrecondition, | ||
186 | (model) -> { | ||
187 | var classesInterpretation = model.getInterpretation(classes); | ||
188 | var classElementInterpretation = model.getInterpretation(classElement); | ||
189 | return ((Tuple activation) -> { | ||
190 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
191 | var modelElement = activation.get(0); | ||
192 | |||
193 | var newClassElement = dseAdapter.createObject(); | ||
194 | var newClassElementId = newClassElement.get(0); | ||
195 | |||
196 | classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); | ||
197 | classElementInterpretation.put(Tuple.of(newClassElementId), true); | ||
198 | }); | ||
199 | }); | ||
200 | |||
201 | var store = ModelStore.builder() | ||
202 | .symbols(classModel, classElement, classes) | ||
203 | .with(ViatraModelQueryAdapter.builder() | ||
204 | .queries(createClassPrecondition)) | ||
205 | .with(ModelVisualizerAdapter.builder()) | ||
206 | .with(DesignSpaceExplorationAdapter.builder() | ||
207 | .transformations(createClassRule) | ||
208 | .strategy(new DepthFirstStrategy(4).continueIfHardObjectivesFulfilled() | ||
209 | )) | ||
210 | .build(); | ||
211 | |||
212 | var model = store.createEmptyModel(); | ||
213 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
214 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
215 | |||
216 | var modelElementInterpretation = model.getInterpretation(classModel); | ||
217 | modelElementInterpretation.put(dseAdapter.createObject(), true); | ||
218 | queryEngine.flushChanges(); | ||
219 | |||
220 | var states = dseAdapter.explore(); | ||
221 | var iterator = states.iterator(); | ||
222 | assertEquals(5, states.size()); | ||
223 | assertEquals(0, iterator.next()); | ||
224 | assertEquals(1, iterator.next()); | ||
225 | assertEquals(2, iterator.next()); | ||
226 | assertEquals(3, iterator.next()); | ||
227 | assertEquals(4, iterator.next()); | ||
228 | } | ||
229 | |||
230 | @Test | ||
231 | void DFSCompletenessTest() { | ||
232 | var createClassPrecondition = Query.of("CreateClassPrecondition", | ||
233 | (builder, model) -> builder.clause( | ||
234 | classModelView.call(model) | ||
235 | )); | ||
236 | |||
237 | var createClassRule = new TransformationRule("CreateClass", | ||
238 | createClassPrecondition, | ||
239 | (model) -> { | ||
240 | var classesInterpretation = model.getInterpretation(classes); | ||
241 | var classElementInterpretation = model.getInterpretation(classElement); | ||
242 | return ((Tuple activation) -> { | ||
243 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
244 | var modelElement = activation.get(0); | ||
245 | |||
246 | var newClassElement = dseAdapter.createObject(); | ||
247 | var newClassElementId = newClassElement.get(0); | ||
248 | |||
249 | classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); | ||
250 | classElementInterpretation.put(Tuple.of(newClassElementId), true); | ||
251 | }); | ||
252 | }); | ||
253 | |||
254 | var createFeaturePrecondition = Query.of("CreateFeaturePrecondition", | ||
255 | (builder, model) -> builder.clause( | ||
256 | classModelView.call(model) | ||
257 | )); | ||
258 | |||
259 | var createFeatureRule = new TransformationRule("CreateFeature", | ||
260 | createFeaturePrecondition, | ||
261 | (model) -> { | ||
262 | var featuresInterpretation = model.getInterpretation(features); | ||
263 | var featureInterpretation = model.getInterpretation(feature); | ||
264 | return ((Tuple activation) -> { | ||
265 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
266 | var modelElement = activation.get(0); | ||
267 | |||
268 | var newClassElement = dseAdapter.createObject(); | ||
269 | var newClassElementId = newClassElement.get(0); | ||
270 | |||
271 | featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true); | ||
272 | featureInterpretation.put(Tuple.of(newClassElementId), true); | ||
273 | }); | ||
274 | }); | ||
275 | |||
276 | var store = ModelStore.builder() | ||
277 | .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates) | ||
278 | .with(ViatraModelQueryAdapter.builder() | ||
279 | .queries(createClassPrecondition, createFeaturePrecondition)) | ||
280 | .with(ModelVisualizerAdapter.builder()) | ||
281 | .with(DesignSpaceExplorationAdapter.builder() | ||
282 | .transformations(createClassRule, createFeatureRule) | ||
283 | .strategy(new DepthFirstStrategy(10).continueIfHardObjectivesFulfilled() | ||
284 | )) | ||
285 | .build(); | ||
286 | |||
287 | var model = store.createEmptyModel(); | ||
288 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
289 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
290 | |||
291 | var modelElementInterpretation = model.getInterpretation(classModel); | ||
292 | modelElementInterpretation.put(dseAdapter.createObject(), true); | ||
293 | queryEngine.flushChanges(); | ||
294 | |||
295 | var states = dseAdapter.explore(); | ||
296 | assertEquals(2047, states.size()); | ||
297 | } | ||
298 | |||
299 | @Test | ||
300 | void BFSTrivialTest() { | ||
301 | var store = ModelStore.builder() | ||
302 | .symbols(classModel) | ||
303 | .with(ViatraModelQueryAdapter.builder()) | ||
304 | .with(ModelVisualizerAdapter.builder()) | ||
305 | .with(DesignSpaceExplorationAdapter.builder() | ||
306 | .strategy(new BestFirstStrategy(0))) | ||
307 | .build(); | ||
308 | |||
309 | var model = store.createEmptyModel(); | ||
310 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
311 | |||
312 | var states = dseAdapter.explore(); | ||
313 | assertEquals(1, states.size()); | ||
314 | assertEquals(0, states.iterator().next()); | ||
315 | } | ||
316 | |||
317 | @Test | ||
318 | void BFSOneRuleTest() { | ||
319 | var createClassPrecondition = Query.of("CreateClassPrecondition", | ||
320 | (builder, model) -> builder.clause( | ||
321 | classModelView.call(model) | ||
322 | )); | ||
323 | |||
324 | var createClassRule = new TransformationRule("CreateClass", | ||
325 | createClassPrecondition, | ||
326 | (model) -> { | ||
327 | var classesInterpretation = model.getInterpretation(classes); | ||
328 | var classElementInterpretation = model.getInterpretation(classElement); | ||
329 | return ((Tuple activation) -> { | ||
330 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
331 | var modelElement = activation.get(0); | ||
332 | |||
333 | var newClassElement = dseAdapter.createObject(); | ||
334 | var newClassElementId = newClassElement.get(0); | ||
335 | |||
336 | classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); | ||
337 | classElementInterpretation.put(Tuple.of(newClassElementId), true); | ||
338 | }); | ||
339 | }); | ||
340 | |||
341 | var store = ModelStore.builder() | ||
342 | .symbols(classModel, classElement, classes) | ||
343 | .with(ViatraModelQueryAdapter.builder() | ||
344 | .queries(createClassPrecondition)) | ||
345 | .with(ModelVisualizerAdapter.builder()) | ||
346 | .with(DesignSpaceExplorationAdapter.builder() | ||
347 | .transformations(createClassRule) | ||
348 | .strategy(new BestFirstStrategy(4) | ||
349 | )) | ||
350 | .build(); | ||
351 | |||
352 | var model = store.createEmptyModel(); | ||
353 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
354 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
355 | |||
356 | var modelElementInterpretation = model.getInterpretation(classModel); | ||
357 | modelElementInterpretation.put(dseAdapter.createObject(), true); | ||
358 | queryEngine.flushChanges(); | ||
359 | |||
360 | var states = dseAdapter.explore(); | ||
361 | assertEquals(1, states.size()); | ||
362 | assertEquals(0, states.iterator().next()); | ||
363 | } | ||
364 | |||
365 | @Test | ||
366 | void BFSContinueTest() { | ||
367 | var createClassPrecondition = Query.of("CreateClassPrecondition", | ||
368 | (builder, model) -> builder.clause( | ||
369 | classModelView.call(model) | ||
370 | )); | ||
371 | |||
372 | var createClassRule = new TransformationRule("CreateClass", | ||
373 | createClassPrecondition, | ||
374 | (model) -> { | ||
375 | var classesInterpretation = model.getInterpretation(classes); | ||
376 | var classElementInterpretation = model.getInterpretation(classElement); | ||
377 | return ((Tuple activation) -> { | ||
378 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
379 | var modelElement = activation.get(0); | ||
380 | |||
381 | var newClassElement = dseAdapter.createObject(); | ||
382 | var newClassElementId = newClassElement.get(0); | ||
383 | |||
384 | classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); | ||
385 | classElementInterpretation.put(Tuple.of(newClassElementId), true); | ||
386 | }); | ||
387 | }); | ||
388 | |||
389 | var store = ModelStore.builder() | ||
390 | .symbols(classModel, classElement, classes) | ||
391 | .with(ViatraModelQueryAdapter.builder() | ||
392 | .queries(createClassPrecondition)) | ||
393 | .with(ModelVisualizerAdapter.builder()) | ||
394 | .with(DesignSpaceExplorationAdapter.builder() | ||
395 | .transformations(createClassRule) | ||
396 | .strategy(new BestFirstStrategy(4).continueIfHardObjectivesFulfilled() | ||
397 | )) | ||
398 | .build(); | ||
399 | |||
400 | var model = store.createEmptyModel(); | ||
401 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
402 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
403 | |||
404 | var modelElementInterpretation = model.getInterpretation(classModel); | ||
405 | modelElementInterpretation.put(dseAdapter.createObject(), true); | ||
406 | queryEngine.flushChanges(); | ||
407 | |||
408 | var states = dseAdapter.explore(); | ||
409 | var iterator = states.iterator(); | ||
410 | assertEquals(5, states.size()); | ||
411 | assertEquals(0, iterator.next()); | ||
412 | assertEquals(1, iterator.next()); | ||
413 | assertEquals(2, iterator.next()); | ||
414 | assertEquals(3, iterator.next()); | ||
415 | assertEquals(4, iterator.next()); | ||
416 | } | ||
417 | |||
418 | @Test | ||
419 | void BFSCompletenessTest() { | ||
420 | var createClassPrecondition = Query.of("CreateClassPrecondition", | ||
421 | (builder, model) -> builder.clause( | ||
422 | classModelView.call(model) | ||
423 | )); | ||
424 | |||
425 | var createClassRule = new TransformationRule("CreateClass", | ||
426 | createClassPrecondition, | ||
427 | (model) -> { | ||
428 | var classesInterpretation = model.getInterpretation(classes); | ||
429 | var classElementInterpretation = model.getInterpretation(classElement); | ||
430 | return ((Tuple activation) -> { | ||
431 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
432 | var modelElement = activation.get(0); | ||
433 | |||
434 | var newClassElement = dseAdapter.createObject(); | ||
435 | var newClassElementId = newClassElement.get(0); | ||
436 | |||
437 | classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); | ||
438 | classElementInterpretation.put(Tuple.of(newClassElementId), true); | ||
439 | }); | ||
440 | }); | ||
441 | |||
442 | var createFeaturePrecondition = Query.of("CreateFeaturePrecondition", | ||
443 | (builder, model) -> builder.clause( | ||
444 | classModelView.call(model) | ||
445 | )); | ||
446 | |||
447 | var createFeatureRule = new TransformationRule("CreateFeature", | ||
448 | createFeaturePrecondition, | ||
449 | (model) -> { | ||
450 | var featuresInterpretation = model.getInterpretation(features); | ||
451 | var featureInterpretation = model.getInterpretation(feature); | ||
452 | return ((Tuple activation) -> { | ||
453 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
454 | var modelElement = activation.get(0); | ||
455 | |||
456 | var newClassElement = dseAdapter.createObject(); | ||
457 | var newClassElementId = newClassElement.get(0); | ||
458 | |||
459 | featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true); | ||
460 | featureInterpretation.put(Tuple.of(newClassElementId), true); | ||
461 | }); | ||
462 | }); | ||
463 | |||
464 | var store = ModelStore.builder() | ||
465 | .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates) | ||
466 | .with(ViatraModelQueryAdapter.builder() | ||
467 | .queries(createClassPrecondition, createFeaturePrecondition)) | ||
468 | .with(ModelVisualizerAdapter.builder()) | ||
469 | .with(DesignSpaceExplorationAdapter.builder() | ||
470 | .transformations(createClassRule, createFeatureRule) | ||
471 | .strategy(new BestFirstStrategy(10).continueIfHardObjectivesFulfilled() | ||
472 | )) | ||
473 | .build(); | ||
474 | |||
475 | var model = store.createEmptyModel(); | ||
476 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
477 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
478 | |||
479 | var modelElementInterpretation = model.getInterpretation(classModel); | ||
480 | modelElementInterpretation.put(dseAdapter.createObject(), true); | ||
481 | queryEngine.flushChanges(); | ||
482 | |||
483 | var states = dseAdapter.explore(); | ||
484 | assertEquals(2047, states.size()); | ||
485 | } | ||
486 | |||
487 | } | ||
diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/TransformationRuleTest.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/TransformationRuleTest.java new file mode 100644 index 00000000..a32d392b --- /dev/null +++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/TransformationRuleTest.java | |||
@@ -0,0 +1,403 @@ | |||
1 | package tools.refinery.store.dse; | ||
2 | |||
3 | import org.junit.jupiter.api.Test; | ||
4 | import tools.refinery.store.model.ModelStore; | ||
5 | import tools.refinery.store.query.ModelQueryAdapter; | ||
6 | import tools.refinery.store.query.dnf.Query; | ||
7 | import tools.refinery.store.dse.internal.TransformationRule; | ||
8 | import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; | ||
9 | import tools.refinery.store.query.view.AnySymbolView; | ||
10 | import tools.refinery.store.query.view.KeyOnlyView; | ||
11 | import tools.refinery.store.representation.Symbol; | ||
12 | import tools.refinery.store.tuple.Tuple; | ||
13 | |||
14 | import java.util.List; | ||
15 | import java.util.Map; | ||
16 | |||
17 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
18 | import static tools.refinery.store.query.literal.Literals.not; | ||
19 | import static tools.refinery.store.dse.tests.QueryAssertions.assertResults; | ||
20 | |||
21 | public class TransformationRuleTest { | ||
22 | |||
23 | private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1); | ||
24 | private static final Symbol<Boolean> classElement = Symbol.of("ClassElement", 1); | ||
25 | private static final Symbol<Boolean> feature = Symbol.of("Feature", 1); | ||
26 | |||
27 | private static final Symbol<Boolean> isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); | ||
28 | private static final Symbol<Boolean> encapsulates = Symbol.of("Encapsulates", 2); | ||
29 | |||
30 | private static final Symbol<Boolean> features = Symbol.of("Features", 2); | ||
31 | private static final Symbol<Boolean> classes = Symbol.of("Classes", 2); | ||
32 | |||
33 | private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); | ||
34 | private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); | ||
35 | private static final AnySymbolView featureView = new KeyOnlyView<>(feature); | ||
36 | private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); | ||
37 | private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); | ||
38 | private static final AnySymbolView featuresView = new KeyOnlyView<>(features); | ||
39 | private static final AnySymbolView classesView = new KeyOnlyView<>(classes); | ||
40 | |||
41 | @Test | ||
42 | void activationsTest() { | ||
43 | var assignFeaturePreconditionHelper = Query.of("AssignFeaturePreconditionHelper", | ||
44 | (builder, model, c, f) -> builder.clause( | ||
45 | classElementView.call(c), | ||
46 | classesView.call(model, c), | ||
47 | encapsulatesView.call(c, f) | ||
48 | )); | ||
49 | |||
50 | var assignFeaturePrecondition = Query.of("AssignFeaturePrecondition", (builder, c2, f) | ||
51 | -> builder.clause((model, c1) -> List.of( | ||
52 | classModelView.call(model), | ||
53 | featureView.call(f), | ||
54 | classElementView.call(c2), | ||
55 | featuresView.call(model, f), | ||
56 | classesView.call(model, c1), | ||
57 | not(assignFeaturePreconditionHelper.call(model, c2, f)), | ||
58 | not(encapsulatesView.call(c2, f)) | ||
59 | ))); | ||
60 | |||
61 | var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", | ||
62 | (builder, model, c) -> builder.clause((f) -> List.of( | ||
63 | classModelView.call(model), | ||
64 | classElementView.call(c), | ||
65 | featuresView.call(model, f), | ||
66 | not(encapsulatesView.call(c, f)) | ||
67 | ))); | ||
68 | |||
69 | TransformationRule assignFeatureRule = new TransformationRule("AssignFeature", | ||
70 | assignFeaturePrecondition, | ||
71 | (model) -> { | ||
72 | var isEncapsulatedByInterpretation = model.getInterpretation(isEncapsulatedBy); | ||
73 | return ((Tuple activation) -> { | ||
74 | var feature = activation.get(0); | ||
75 | var classElement = activation.get(1); | ||
76 | |||
77 | isEncapsulatedByInterpretation.put(Tuple.of(feature, classElement), true); | ||
78 | }); | ||
79 | }); | ||
80 | |||
81 | TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass", | ||
82 | deleteEmptyClassPrecondition, | ||
83 | (model) -> { | ||
84 | var classesInterpretation = model.getInterpretation(classes); | ||
85 | var classElementInterpretation = model.getInterpretation(classElement); | ||
86 | return ((Tuple activation) -> { | ||
87 | var modelElement = activation.get(0); | ||
88 | var classElement = activation.get(1); | ||
89 | |||
90 | classesInterpretation.put(Tuple.of(modelElement, classElement), false); | ||
91 | classElementInterpretation.put(Tuple.of(classElement), false); | ||
92 | }); | ||
93 | }); | ||
94 | |||
95 | |||
96 | var store = ModelStore.builder() | ||
97 | .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) | ||
98 | .with(ViatraModelQueryAdapter.builder() | ||
99 | .queries(assignFeaturePrecondition, assignFeaturePreconditionHelper, | ||
100 | deleteEmptyClassPrecondition)) | ||
101 | .with(DesignSpaceExplorationAdapter.builder()) | ||
102 | .build(); | ||
103 | |||
104 | var model = store.createEmptyModel(); | ||
105 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
106 | assignFeatureRule.prepare(model, queryEngine); | ||
107 | deleteEmptyClassRule.prepare(model, queryEngine); | ||
108 | |||
109 | var classModelInterpretation = model.getInterpretation(classModel); | ||
110 | var classElementInterpretation = model.getInterpretation(classElement); | ||
111 | var featureInterpretation = model.getInterpretation(feature); | ||
112 | var featuresInterpretation = model.getInterpretation(features); | ||
113 | var classesInterpretation = model.getInterpretation(classes); | ||
114 | |||
115 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
116 | var newModel = dseAdapter.createObject(); | ||
117 | var newModelId = newModel.get(0); | ||
118 | var newClass1 = dseAdapter.createObject(); | ||
119 | var newClass1Id = newClass1.get(0); | ||
120 | var newClass2 = dseAdapter.createObject(); | ||
121 | var newClass2Id = newClass2.get(0); | ||
122 | var newField = dseAdapter.createObject(); | ||
123 | var newFieldId = newField.get(0); | ||
124 | |||
125 | classModelInterpretation.put(newModel, true); | ||
126 | classElementInterpretation.put(newClass1, true); | ||
127 | classElementInterpretation.put(newClass2, true); | ||
128 | featureInterpretation.put(newField, true); | ||
129 | classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); | ||
130 | classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); | ||
131 | featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); | ||
132 | |||
133 | queryEngine.flushChanges(); | ||
134 | |||
135 | var assignFeatureRuleActivations = assignFeatureRule.getAllActivationsAsSets(); | ||
136 | var deleteEmptyClassRuleActivations = deleteEmptyClassRule.getAllActivationsAsSets(); | ||
137 | |||
138 | assertResults(Map.of( | ||
139 | Tuple.of(newClass1Id, newFieldId), true, | ||
140 | Tuple.of(newClass2Id, newFieldId), true | ||
141 | ), assignFeatureRuleActivations); | ||
142 | |||
143 | assertResults(Map.of( | ||
144 | Tuple.of(newModelId, newClass1Id), true, | ||
145 | Tuple.of(newModelId, newClass2Id), true | ||
146 | ), deleteEmptyClassRuleActivations); | ||
147 | } | ||
148 | |||
149 | @Test | ||
150 | void randomActivationTest() { | ||
151 | var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", | ||
152 | (builder, model, c) -> builder.clause((f) -> List.of( | ||
153 | classModelView.call(model), | ||
154 | classElementView.call(c), | ||
155 | featuresView.call(model, f), | ||
156 | not(encapsulatesView.call(c, f)) | ||
157 | ))); | ||
158 | |||
159 | TransformationRule deleteEmptyClassRule0 = new TransformationRule("DeleteEmptyClass0", | ||
160 | deleteEmptyClassPrecondition, | ||
161 | (model) -> { | ||
162 | var classesInterpretation = model.getInterpretation(classes); | ||
163 | var classElementInterpretation = model.getInterpretation(classElement); | ||
164 | return ((Tuple activation) -> { | ||
165 | var modelElement = activation.get(0); | ||
166 | var classElement = activation.get(1); | ||
167 | |||
168 | classesInterpretation.put(Tuple.of(modelElement, classElement), false); | ||
169 | classElementInterpretation.put(Tuple.of(classElement), false); | ||
170 | }); | ||
171 | }, | ||
172 | 0L); | ||
173 | |||
174 | TransformationRule deleteEmptyClassRule1 = new TransformationRule("DeleteEmptyClass1", | ||
175 | deleteEmptyClassPrecondition, | ||
176 | (model) -> { | ||
177 | var classesInterpretation = model.getInterpretation(classes); | ||
178 | var classElementInterpretation = model.getInterpretation(classElement); | ||
179 | return ((Tuple activation) -> { | ||
180 | var modelElement = activation.get(0); | ||
181 | var classElement = activation.get(1); | ||
182 | |||
183 | classesInterpretation.put(Tuple.of(modelElement, classElement), false); | ||
184 | classElementInterpretation.put(Tuple.of(classElement), false); | ||
185 | }); | ||
186 | }, | ||
187 | 78634L); | ||
188 | |||
189 | var store = ModelStore.builder() | ||
190 | .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) | ||
191 | .with(ViatraModelQueryAdapter.builder() | ||
192 | .queries(deleteEmptyClassPrecondition)) | ||
193 | .with(DesignSpaceExplorationAdapter.builder()) | ||
194 | .build(); | ||
195 | |||
196 | var model = store.createEmptyModel(); | ||
197 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
198 | deleteEmptyClassRule0.prepare(model, queryEngine); | ||
199 | deleteEmptyClassRule1.prepare(model, queryEngine); | ||
200 | |||
201 | var classModelInterpretation = model.getInterpretation(classModel); | ||
202 | var classElementInterpretation = model.getInterpretation(classElement); | ||
203 | var featureInterpretation = model.getInterpretation(feature); | ||
204 | var featuresInterpretation = model.getInterpretation(features); | ||
205 | var classesInterpretation = model.getInterpretation(classes); | ||
206 | |||
207 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
208 | var newModel = dseAdapter.createObject(); | ||
209 | var newModelId = newModel.get(0); | ||
210 | var newClass1 = dseAdapter.createObject(); | ||
211 | var newClass1Id = newClass1.get(0); | ||
212 | var newClass2 = dseAdapter.createObject(); | ||
213 | var newClass2Id = newClass2.get(0); | ||
214 | var newField = dseAdapter.createObject(); | ||
215 | var newFieldId = newField.get(0); | ||
216 | |||
217 | classModelInterpretation.put(newModel, true); | ||
218 | classElementInterpretation.put(newClass1, true); | ||
219 | classElementInterpretation.put(newClass2, true); | ||
220 | featureInterpretation.put(newField, true); | ||
221 | classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); | ||
222 | classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); | ||
223 | featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); | ||
224 | |||
225 | queryEngine.flushChanges(); | ||
226 | |||
227 | |||
228 | var activation0 = deleteEmptyClassRule0.getRandomActivation().activation(); | ||
229 | var activation1 = deleteEmptyClassRule1.getRandomActivation().activation(); | ||
230 | |||
231 | assertResults(Map.of( | ||
232 | Tuple.of(newModelId, newClass1Id), true, | ||
233 | Tuple.of(newModelId, newClass2Id), true | ||
234 | ), deleteEmptyClassRule0.getAllActivationsAsSets()); | ||
235 | |||
236 | assertResults(Map.of( | ||
237 | Tuple.of(newModelId, newClass1Id), true, | ||
238 | Tuple.of(newModelId, newClass2Id), true | ||
239 | ), deleteEmptyClassRule1.getAllActivationsAsSets()); | ||
240 | |||
241 | assertEquals(Tuple.of(newModelId, newClass2Id), activation0); | ||
242 | assertEquals(Tuple.of(newModelId, newClass1Id), activation1); | ||
243 | |||
244 | } | ||
245 | |||
246 | @Test | ||
247 | void fireTest() { | ||
248 | var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", | ||
249 | (builder, model, c) -> builder.clause((f) -> List.of( | ||
250 | classModelView.call(model), | ||
251 | classElementView.call(c), | ||
252 | featuresView.call(model, f), | ||
253 | not(encapsulatesView.call(c, f)) | ||
254 | ))); | ||
255 | |||
256 | TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass", | ||
257 | deleteEmptyClassPrecondition, | ||
258 | (model) -> { | ||
259 | var classesInterpretation = model.getInterpretation(classes); | ||
260 | var classElementInterpretation = model.getInterpretation(classElement); | ||
261 | return ((Tuple activation) -> { | ||
262 | var modelElement = activation.get(0); | ||
263 | var classElement = activation.get(1); | ||
264 | |||
265 | classesInterpretation.put(Tuple.of(modelElement, classElement), false); | ||
266 | classElementInterpretation.put(Tuple.of(classElement), false); | ||
267 | }); | ||
268 | }); | ||
269 | |||
270 | var store = ModelStore.builder() | ||
271 | .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) | ||
272 | .with(ViatraModelQueryAdapter.builder() | ||
273 | .queries(deleteEmptyClassPrecondition)) | ||
274 | .with(DesignSpaceExplorationAdapter.builder()) | ||
275 | .build(); | ||
276 | |||
277 | var model = store.createEmptyModel(); | ||
278 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
279 | deleteEmptyClassRule.prepare(model, queryEngine); | ||
280 | |||
281 | var classModelInterpretation = model.getInterpretation(classModel); | ||
282 | var classElementInterpretation = model.getInterpretation(classElement); | ||
283 | var featureInterpretation = model.getInterpretation(feature); | ||
284 | var featuresInterpretation = model.getInterpretation(features); | ||
285 | var classesInterpretation = model.getInterpretation(classes); | ||
286 | |||
287 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
288 | var newModel = dseAdapter.createObject(); | ||
289 | var newModelId = newModel.get(0); | ||
290 | var newClass1 = dseAdapter.createObject(); | ||
291 | var newClass1Id = newClass1.get(0); | ||
292 | var newClass2 = dseAdapter.createObject(); | ||
293 | var newClass2Id = newClass2.get(0); | ||
294 | var newField = dseAdapter.createObject(); | ||
295 | var newFieldId = newField.get(0); | ||
296 | |||
297 | classModelInterpretation.put(newModel, true); | ||
298 | classElementInterpretation.put(newClass1, true); | ||
299 | classElementInterpretation.put(newClass2, true); | ||
300 | featureInterpretation.put(newField, true); | ||
301 | classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); | ||
302 | classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); | ||
303 | featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); | ||
304 | |||
305 | queryEngine.flushChanges(); | ||
306 | |||
307 | assertResults(Map.of( | ||
308 | Tuple.of(newModelId, newClass1Id), true, | ||
309 | Tuple.of(newModelId, newClass2Id), true | ||
310 | ), deleteEmptyClassRule.getAllActivationsAsSets()); | ||
311 | |||
312 | |||
313 | deleteEmptyClassRule.fireActivation(Tuple.of(0, 1)); | ||
314 | |||
315 | assertResults(Map.of( | ||
316 | Tuple.of(newModelId, newClass1Id), false, | ||
317 | Tuple.of(newModelId, newClass2Id), true | ||
318 | ), deleteEmptyClassRule.getAllActivationsAsSets()); | ||
319 | } | ||
320 | |||
321 | @Test | ||
322 | void randomFireTest() { | ||
323 | var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", | ||
324 | (builder, model, c) -> builder.clause((f) -> List.of( | ||
325 | classModelView.call(model), | ||
326 | classElementView.call(c), | ||
327 | featuresView.call(model, f), | ||
328 | not(encapsulatesView.call(c, f)) | ||
329 | ))); | ||
330 | |||
331 | TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass0", | ||
332 | deleteEmptyClassPrecondition, | ||
333 | (model) -> { | ||
334 | var classesInterpretation = model.getInterpretation(classes); | ||
335 | var classElementInterpretation = model.getInterpretation(classElement); | ||
336 | return ((Tuple activation) -> { | ||
337 | var modelElement = activation.get(0); | ||
338 | var classElement = activation.get(1); | ||
339 | |||
340 | classesInterpretation.put(Tuple.of(modelElement, classElement), false); | ||
341 | classElementInterpretation.put(Tuple.of(classElement), false); | ||
342 | }); | ||
343 | }, | ||
344 | 0L); | ||
345 | |||
346 | var store = ModelStore.builder() | ||
347 | .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) | ||
348 | .with(ViatraModelQueryAdapter.builder() | ||
349 | .queries(deleteEmptyClassPrecondition)) | ||
350 | .with(DesignSpaceExplorationAdapter.builder()) | ||
351 | .build(); | ||
352 | |||
353 | var model = store.createEmptyModel(); | ||
354 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
355 | deleteEmptyClassRule.prepare(model, queryEngine); | ||
356 | |||
357 | var classModelInterpretation = model.getInterpretation(classModel); | ||
358 | var classElementInterpretation = model.getInterpretation(classElement); | ||
359 | var featureInterpretation = model.getInterpretation(feature); | ||
360 | var featuresInterpretation = model.getInterpretation(features); | ||
361 | var classesInterpretation = model.getInterpretation(classes); | ||
362 | |||
363 | var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
364 | var newModel = dseAdapter.createObject(); | ||
365 | var newModelId = newModel.get(0); | ||
366 | var newClass1 = dseAdapter.createObject(); | ||
367 | var newClass1Id = newClass1.get(0); | ||
368 | var newClass2 = dseAdapter.createObject(); | ||
369 | var newClass2Id = newClass2.get(0); | ||
370 | var newField = dseAdapter.createObject(); | ||
371 | var newFieldId = newField.get(0); | ||
372 | |||
373 | classModelInterpretation.put(newModel, true); | ||
374 | classElementInterpretation.put(newClass1, true); | ||
375 | classElementInterpretation.put(newClass2, true); | ||
376 | featureInterpretation.put(newField, true); | ||
377 | classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); | ||
378 | classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); | ||
379 | featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); | ||
380 | |||
381 | queryEngine.flushChanges(); | ||
382 | |||
383 | assertResults(Map.of( | ||
384 | Tuple.of(newModelId, newClass1Id), true, | ||
385 | Tuple.of(newModelId, newClass2Id), true | ||
386 | ), deleteEmptyClassRule.getAllActivationsAsSets()); | ||
387 | |||
388 | deleteEmptyClassRule.fireRandomActivation(); | ||
389 | |||
390 | assertResults(Map.of( | ||
391 | Tuple.of(newModelId, newClass1Id), true, | ||
392 | Tuple.of(newModelId, newClass2Id), false | ||
393 | ), deleteEmptyClassRule.getAllActivationsAsSets()); | ||
394 | |||
395 | deleteEmptyClassRule.fireRandomActivation(); | ||
396 | |||
397 | assertResults(Map.of( | ||
398 | Tuple.of(newModelId, newClass1Id), false, | ||
399 | Tuple.of(newModelId, newClass2Id), false | ||
400 | ), deleteEmptyClassRule.getAllActivationsAsSets()); | ||
401 | |||
402 | } | ||
403 | } | ||
diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/tests/QueryAssertions.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/tests/QueryAssertions.java new file mode 100644 index 00000000..be514eaf --- /dev/null +++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/tests/QueryAssertions.java | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.dse.tests; | ||
7 | |||
8 | import org.junit.jupiter.api.function.Executable; | ||
9 | import tools.refinery.store.query.resultset.ResultSet; | ||
10 | import tools.refinery.store.tuple.Tuple; | ||
11 | |||
12 | import java.util.*; | ||
13 | |||
14 | import static org.hamcrest.MatcherAssert.assertThat; | ||
15 | import static org.hamcrest.Matchers.is; | ||
16 | import static org.hamcrest.Matchers.nullValue; | ||
17 | import static org.junit.jupiter.api.Assertions.assertAll; | ||
18 | |||
19 | public final class QueryAssertions { | ||
20 | private QueryAssertions() { | ||
21 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); | ||
22 | } | ||
23 | |||
24 | public static <T> void assertNullableResults(Map<Tuple, Optional<T>> expected, ResultSet<T> resultSet) { | ||
25 | var nullableValuesMap = new LinkedHashMap<Tuple, T>(expected.size()); | ||
26 | for (var entry : expected.entrySet()) { | ||
27 | nullableValuesMap.put(entry.getKey(), entry.getValue().orElse(null)); | ||
28 | } | ||
29 | assertResults(nullableValuesMap, resultSet); | ||
30 | } | ||
31 | |||
32 | public static <T> void assertResults(Map<Tuple, T> expected, ResultSet<T> resultSet) { | ||
33 | var defaultValue = resultSet.getQuery().defaultValue(); | ||
34 | var filteredExpected = new LinkedHashMap<Tuple, T>(); | ||
35 | var executables = new ArrayList<Executable>(); | ||
36 | for (var entry : expected.entrySet()) { | ||
37 | var key = entry.getKey(); | ||
38 | var value = entry.getValue(); | ||
39 | if (!Objects.equals(value, defaultValue)) { | ||
40 | filteredExpected.put(key, value); | ||
41 | } | ||
42 | executables.add(() -> assertThat("value for key " + key,resultSet.get(key), is(value))); | ||
43 | } | ||
44 | executables.add(() -> assertThat("results size", resultSet.size(), is(filteredExpected.size()))); | ||
45 | |||
46 | var actual = new LinkedHashMap<Tuple, T>(); | ||
47 | var cursor = resultSet.getAll(); | ||
48 | while (cursor.move()) { | ||
49 | var key = cursor.getKey(); | ||
50 | var previous = actual.put(key, cursor.getValue()); | ||
51 | assertThat("duplicate value for key " + key, previous, nullValue()); | ||
52 | } | ||
53 | executables.add(() -> assertThat("results cursor", actual, is(filteredExpected))); | ||
54 | |||
55 | assertAll(executables); | ||
56 | } | ||
57 | } | ||