From 68e8c8ea4091482c43d810fdaa2fd6ddd6316d07 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Sat, 6 Nov 2021 16:02:37 +0100 Subject: fix(lang): mark transient references Xtext fails to serialize non-transient references that have no corresponding assignment in the grammar. Therefore, we mark * Problem.nodes * ClassDeclaration.newNode * ExistentialQualifier.implicitVariables * VariableOrNodeArgument.singletonVariable as transient. This will allow serializing Problem instances using the textual concrete syntax for display. --- .../tests/serializer/ProblemSerializerTest.java | 199 +++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java (limited to 'language') diff --git a/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java b/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java new file mode 100644 index 00000000..34c1d14b --- /dev/null +++ b/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java @@ -0,0 +1,199 @@ +package tools.refinery.language.tests.serializer; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Map; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import com.google.inject.Inject; + +import tools.refinery.language.model.ProblemUtil; +import tools.refinery.language.model.problem.Atom; +import tools.refinery.language.model.problem.LogicValue; +import tools.refinery.language.model.problem.Node; +import tools.refinery.language.model.problem.PredicateDefinition; +import tools.refinery.language.model.problem.Problem; +import tools.refinery.language.model.problem.ProblemFactory; +import tools.refinery.language.model.problem.Relation; +import tools.refinery.language.model.problem.VariableOrNode; +import tools.refinery.language.model.tests.ProblemTestUtil; +import tools.refinery.language.tests.ProblemInjectorProvider; + +@ExtendWith(InjectionExtension.class) +@InjectWith(ProblemInjectorProvider.class) +public class ProblemSerializerTest { + @Inject + ResourceSet resourceSet; + + @Inject + ProblemTestUtil testUtil; + + Resource resource; + + Problem problem; + + Problem builtin; + + @BeforeEach + void beforeEach() { + problem = ProblemFactory.eINSTANCE.createProblem(); + resource = resourceSet.createResource(URI.createFileURI("test.problem")); + resource.getContents().add(problem); + builtin = ProblemUtil.getBuiltInLibrary(problem).get(); + } + + @Test + void implicitNodeTest() { + var pred = createPred(); + var node = ProblemFactory.eINSTANCE.createNode(); + node.setName("a"); + problem.getNodes().add(node); + createAssertion(pred, node); + + assertSerializedResult("pred foo ( node p ) . foo ( a ) : true ."); + } + + @Test + void individualNodeTest() { + var pred = createPred(); + var node = ProblemFactory.eINSTANCE.createNode(); + node.setName("a"); + var individualDeclaration = ProblemFactory.eINSTANCE.createIndividualDeclaration(); + individualDeclaration.getNodes().add(node); + problem.getStatements().add(individualDeclaration); + createAssertion(pred, node); + + assertSerializedResult("pred foo ( node p ) . individual a . foo ( a ) : true ."); + } + + private PredicateDefinition createPred() { + var pred = ProblemFactory.eINSTANCE.createPredicateDefinition(); + pred.setName("foo"); + var parameter = ProblemFactory.eINSTANCE.createParameter(); + var nodeType = testUtil.findClass(builtin, "node"); + parameter.setParameterType(nodeType); + parameter.setName("p"); + pred.getParameters().add(parameter); + problem.getStatements().add(pred); + return pred; + } + + @Test + void newNodeTest() { + var classDeclaration = ProblemFactory.eINSTANCE.createClassDeclaration(); + classDeclaration.setName("Foo"); + var newNode = ProblemFactory.eINSTANCE.createNode(); + newNode.setName("new"); + classDeclaration.setNewNode(newNode); + problem.getStatements().add(classDeclaration); + createAssertion(classDeclaration, newNode); + + assertSerializedResult("class Foo . Foo ( Foo::new ) : true ."); + } + + private void createAssertion(Relation relation, Node node) { + var assertion = ProblemFactory.eINSTANCE.createAssertion(); + assertion.setRelation(relation); + var argument = ProblemFactory.eINSTANCE.createNodeAssertionArgument(); + argument.setNode(node); + assertion.getArguments().add(argument); + assertion.setValue(LogicValue.TRUE); + problem.getStatements().add(assertion); + } + + @Test + void implicitVariableTest() { + var pred = ProblemFactory.eINSTANCE.createPredicateDefinition(); + pred.setName("foo"); + var nodeType = testUtil.findClass(builtin, "node"); + var parameter1 = ProblemFactory.eINSTANCE.createParameter(); + parameter1.setParameterType(nodeType); + parameter1.setName("p1"); + pred.getParameters().add(parameter1); + var parameter2 = ProblemFactory.eINSTANCE.createParameter(); + parameter2.setParameterType(nodeType); + parameter2.setName("p2"); + pred.getParameters().add(parameter2); + var conjunction = ProblemFactory.eINSTANCE.createConjunction(); + var variable = ProblemFactory.eINSTANCE.createImplicitVariable(); + variable.setName("q"); + conjunction.getImplicitVariables().add(variable); + var equals = testUtil.reference(nodeType, "equals"); + conjunction.getLiterals().add(createAtom(equals, parameter1, variable)); + conjunction.getLiterals().add(createAtom(equals, variable, parameter2)); + pred.getBodies().add(conjunction); + problem.getStatements().add(pred); + + assertSerializedResult("pred foo ( node p1 , node p2 ) <-> equals ( p1 , q ) , equals ( q , p2 ) ."); + } + + private Atom createAtom(Relation relation, VariableOrNode variable1, VariableOrNode variable2) { + var atom = ProblemFactory.eINSTANCE.createAtom(); + atom.setRelation(relation); + var arg1 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument(); + arg1.setVariableOrNode(variable1); + atom.getArguments().add(arg1); + var arg2 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument(); + arg2.setVariableOrNode(variable2); + atom.getArguments().add(arg2); + return atom; + } + + @Test + void singletonVariableTest() { + var pred = ProblemFactory.eINSTANCE.createPredicateDefinition(); + pred.setName("foo"); + var nodeType = testUtil.findClass(builtin, "node"); + var parameter = ProblemFactory.eINSTANCE.createParameter(); + parameter.setParameterType(nodeType); + parameter.setName("p"); + pred.getParameters().add(parameter); + var conjunction = ProblemFactory.eINSTANCE.createConjunction(); + var atom = ProblemFactory.eINSTANCE.createAtom(); + var equals = testUtil.reference(nodeType, "equals"); + atom.setRelation(equals); + var arg1 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument(); + arg1.setVariableOrNode(parameter); + atom.getArguments().add(arg1); + var arg2 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument(); + var variable = ProblemFactory.eINSTANCE.createImplicitVariable(); + variable.setName("_q"); + arg2.setSingletonVariable(variable); + arg2.setVariableOrNode(variable); + atom.getArguments().add(arg2); + conjunction.getLiterals().add(atom); + pred.getBodies().add(conjunction); + problem.getStatements().add(pred); + + assertSerializedResult("pred foo ( node p ) <-> equals ( p , _q ) ."); + } + + private void assertSerializedResult(String expected) { + var outputStream = new ByteArrayOutputStream(); + try { + resource.save(outputStream, Map.of()); + } catch (IOException e) { + throw new AssertionError("Failed to serialize problem", e); + } finally { + try { + outputStream.close(); + } catch (IOException e) { + // Nothing to handle in a test. + } + } + var problemString = outputStream.toString(); + + assertThat(problemString, equalTo(expected)); + } +} -- cgit v1.2.3-54-g00ecf