From 8918b3d766f8ef24a0d8d29c8f55f4dc6a482c2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20Marussy?= Date: Sun, 21 Jul 2024 01:18:00 +0200 Subject: [PATCH 1/9] test: ModelSemantics test framework --- subprojects/generator/build.gradle.kts | 2 + .../generator/ModelSemanticsFactory.java | 15 +- .../generator/FileBasedSemanticsTest.java | 32 ++++ .../generator/abstractTypeHierarchy.problem | 47 ++++++ .../refinery/generator/typeHierarchy.problem | 24 +++ .../generator/tests/DynamicTestLoader.java | 143 ++++++++++++++++++ .../generator/tests/SemanticsExpectation.java | 117 ++++++++++++++ .../generator/tests/SemanticsTest.java | 18 +++ .../generator/tests/SemanticsTestBuilder.java | 93 ++++++++++++ .../generator/tests/SemanticsTestCase.java | 99 ++++++++++++ .../tests/SemanticsTestCaseBuilder.java | 95 ++++++++++++ .../generator/tests/SemanticsTestLoader.java | 71 +++++++++ .../tests/internal/ChunkAcceptor.java | 12 ++ .../generator/tests/internal/ChunkHeader.java | 9 ++ .../tests/internal/CommonHeader.java | 18 +++ .../tests/internal/ExpectationHeader.java | 12 ++ .../tests/internal/ProblemSplitter.java | 92 +++++++++++ .../tests/internal/TestCaseHeader.java | 9 ++ .../logic/term/truthvalue/TruthValue.java | 1 - 19 files changed, 907 insertions(+), 2 deletions(-) create mode 100644 subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java create mode 100644 subprojects/generator/src/test/resources/tools/refinery/generator/abstractTypeHierarchy.problem create mode 100644 subprojects/generator/src/test/resources/tools/refinery/generator/typeHierarchy.problem create mode 100644 subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/DynamicTestLoader.java create mode 100644 subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsExpectation.java create mode 100644 subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTest.java create mode 100644 subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestBuilder.java create mode 100644 subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCase.java create mode 100644 subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCaseBuilder.java create mode 100644 subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestLoader.java create mode 100644 subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkAcceptor.java create mode 100644 subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkHeader.java create mode 100644 subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/CommonHeader.java create mode 100644 subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ExpectationHeader.java create mode 100644 subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ProblemSplitter.java create mode 100644 subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/TestCaseHeader.java diff --git a/subprojects/generator/build.gradle.kts b/subprojects/generator/build.gradle.kts index e5cf1bc4b..7fa4b8494 100644 --- a/subprojects/generator/build.gradle.kts +++ b/subprojects/generator/build.gradle.kts @@ -6,6 +6,7 @@ plugins { id("tools.refinery.gradle.java-library") + id("tools.refinery.gradle.java-test-fixtures") } mavenArtifact { @@ -15,5 +16,6 @@ mavenArtifact { dependencies { api(project(":refinery-language-semantics")) implementation(project(":refinery-store-query-interpreter")) + testFixturesImplementation(libs.junit.api) testImplementation(testFixtures(project(":refinery-language"))) } diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/ModelSemanticsFactory.java b/subprojects/generator/src/main/java/tools/refinery/generator/ModelSemanticsFactory.java index 434275020..b624a507c 100644 --- a/subprojects/generator/src/main/java/tools/refinery/generator/ModelSemanticsFactory.java +++ b/subprojects/generator/src/main/java/tools/refinery/generator/ModelSemanticsFactory.java @@ -12,14 +12,22 @@ import tools.refinery.store.reasoning.ReasoningAdapter; import tools.refinery.store.reasoning.literal.Concreteness; +import java.util.Collection; import java.util.Set; public final class ModelSemanticsFactory extends ModelFacadeFactory { + private boolean withCandidateInterpretations; + @Override protected ModelSemanticsFactory getSelf() { return this; } + public ModelSemanticsFactory withCandidateInterpretations(boolean withCandidateInterpretations) { + this.withCandidateInterpretations = withCandidateInterpretations; + return this; + } + public ModelSemantics createSemantics(Problem problem) { var semantics = tryCreateSemantics(problem); semantics.getPropagationResult().throwIfRejected(); @@ -36,9 +44,14 @@ public ModelSemantics tryCreateSemantics(Problem problem) { .with(PropagationAdapter.builder() .throwOnFatalRejection(false)) .with(ReasoningAdapter.builder() - .requiredInterpretations(Set.of(Concreteness.PARTIAL))); + .requiredInterpretations(getRequiredInterpretations())); initializer.configureStoreBuilder(storeBuilder, isKeepNonExistingObjects()); var store = storeBuilder.build(); return new ModelSemantics(initializer.getProblemTrace(), store, initializer.getModelSeed()); } + + private Collection getRequiredInterpretations() { + return withCandidateInterpretations ? Set.of(Concreteness.PARTIAL, Concreteness.CANDIDATE) : + Set.of(Concreteness.PARTIAL); + } } diff --git a/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java b/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java new file mode 100644 index 000000000..6fdcf3fd5 --- /dev/null +++ b/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.generator; + +import com.google.inject.Inject; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.junit.jupiter.api.DynamicNode; +import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.extension.ExtendWith; +import tools.refinery.generator.tests.DynamicTestLoader; +import tools.refinery.language.tests.ProblemInjectorProvider; + +import java.util.stream.Stream; + +@ExtendWith(InjectionExtension.class) +@InjectWith(ProblemInjectorProvider.class) +class FileBasedSemanticsTest { + @Inject + private DynamicTestLoader loader; + + @TestFactory + Stream fileBasedTests() { + return loader.fromClasspath(getClass(), + "abstractTypeHierarchy.problem", + "typeHierarchy.problem" + ); + } +} diff --git a/subprojects/generator/src/test/resources/tools/refinery/generator/abstractTypeHierarchy.problem b/subprojects/generator/src/test/resources/tools/refinery/generator/abstractTypeHierarchy.problem new file mode 100644 index 000000000..559c077db --- /dev/null +++ b/subprojects/generator/src/test/resources/tools/refinery/generator/abstractTypeHierarchy.problem @@ -0,0 +1,47 @@ +% SPDX-FileCopyrightText: 2024 The Refinery Authors +% +% SPDX-License-Identifier: EPL-2.0 + +abstract class A. + +class B extends A. + +class C extends A. + +class D extends A. + +% TEST: negative subclasses +!B(a). +!C(a). +!D(a). +% EXPECT: +!A(a). + +% TEST: infer subclass by exclusion +A(a). +!B(a). +!C(a). +% EXPECT: +D(a). + +% TEST: candidate rounding +A(a). +% EXPECT EXACTLY: +?B(a). +?C(a). +?D(a). +% EXPECT CANDIDATE: +B(a). +!C(a). +!D(a). + +% TEST: candidate rounding with exclusion +A(a). +!B(a). +% EXPECT EXACTLY: +?C(a). +?D(a). +% EXPECT CANDIDATE: +!B(a). +C(a). +!D(a). diff --git a/subprojects/generator/src/test/resources/tools/refinery/generator/typeHierarchy.problem b/subprojects/generator/src/test/resources/tools/refinery/generator/typeHierarchy.problem new file mode 100644 index 000000000..2d2970670 --- /dev/null +++ b/subprojects/generator/src/test/resources/tools/refinery/generator/typeHierarchy.problem @@ -0,0 +1,24 @@ +% SPDX-FileCopyrightText: 2024 The Refinery Authors +% +% SPDX-License-Identifier: EPL-2.0 + +class A. + +class B extends A. + +% TEST: positive subclass +B(b). +% EXPECT: +A(b). + +% TEST: negative superclass +!A(b). +% EXPECT: +!B(b). + +% TEST WITH ERRORS: inconsistent type +!A(b). +B(b). +% EXPECT: +A(b): error. +B(b): error. diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/DynamicTestLoader.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/DynamicTestLoader.java new file mode 100644 index 000000000..4a93e77ad --- /dev/null +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/DynamicTestLoader.java @@ -0,0 +1,143 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.generator.tests; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import org.junit.jupiter.api.DynamicNode; +import org.junit.jupiter.api.function.Executable; +import tools.refinery.generator.ModelSemanticsFactory; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.DynamicContainer.dynamicContainer; +import static org.junit.jupiter.api.DynamicTest.dynamicTest; + +public class DynamicTestLoader { + @Inject + private SemanticsTestLoader testLoader; + + @Inject + private Provider semanticsFactoryProvider; + + public Stream fromClasspath(Class klass, String name) { + URL url; + URI uri; + try { + url = safeGetResource(klass, name); + uri = url.toURI(); + } catch (RuntimeException | URISyntaxException e) { + return Stream.of(createErrorNode(name, null, e)); + } + SemanticsTest test; + try { + test = loadFromUrl(uri, url); + } catch (IOException | RuntimeException e) { + return Stream.of(createErrorNode(name, uri, e)); + } + return createDynamicNodes(uri, test); + } + + public Stream fromClasspath(Class klass, String... names) { + return fromClasspath(klass, Stream.of(names)); + } + + public Stream fromClasspath(Class klass, Stream names) { + return names.map(name -> nodeFromClasspath(klass, name)); + } + + private DynamicNode nodeFromClasspath(Class klass, String name) { + URL url; + URI uri; + try { + url = safeGetResource(klass, name); + uri = url.toURI(); + } catch (RuntimeException | URISyntaxException e) { + return createErrorNode(name, null, e); + } + SemanticsTest test; + try { + test = loadFromUrl(uri, url); + } catch (IOException | RuntimeException e) { + return createErrorNode(name, uri, e); + } + return createDynamicNode(name, uri, test); + } + + private static URL safeGetResource(Class klass, String name) { + var url = klass.getResource(name); + if (url == null) { + throw new IllegalStateException("Test resource %s was not found.".formatted(name)); + } + return url; + } + + private SemanticsTest loadFromUrl(URI uri, URL url) throws IOException { + var eclipseUri = org.eclipse.emf.common.util.URI.createURI(uri.toString()); + try (var inputStream = url.openStream()) { + return testLoader.loadStream(inputStream, eclipseUri); + } + } + + public Stream fromString(String problem) { + SemanticsTest test; + try { + test = testLoader.loadString(problem); + } catch (RuntimeException e) { + return Stream.of(createErrorNode("", null, e)); + } + return createDynamicNodes(null, test); + } + + private DynamicNode createDynamicNode(String name, URI uri, SemanticsTest test) { + var testCases = test.testCases(); + if (testCases.size() == 1 && testCases.getFirst().name() == null) { + var testCase = testCases.getFirst(); + return dynamicTest(name, uri, asExecutable(testCase)); + } + var children = createDynamicNodes(uri, test); + return dynamicContainer(name, uri, children); + } + + private Stream createDynamicNodes(URI uri, SemanticsTest test) { + var testCases = test.testCases(); + var children = new ArrayList(); + int testCaseCount = testCases.size(); + for (int i = 0; i < testCaseCount; i++) { + var testCase = testCases.get(i); + var testCaseName = testCase.name(); + if (testCaseName == null) { + testCaseName = "[%d]".formatted(i); + } + children.add(dynamicTest(testCaseName, uri, asExecutable(testCase))); + } + return children.stream(); + } + + private Executable asExecutable(SemanticsTestCase testCase) { + return () -> testCase.execute(semanticsFactoryProvider.get()); + } + + private DynamicNode createErrorNode(String name, URI uri, Throwable cause) { + var messageBuilder = new StringBuilder(); + messageBuilder.append("Error while reading test '").append(name).append("'"); + if (uri != null) { + messageBuilder.append(" from ").append(uri); + } + if (cause != null) { + messageBuilder.append(": ").append(cause.getMessage()); + } + var message = messageBuilder.toString(); + return dynamicTest(name, uri, () -> { + throw new RuntimeException(message, cause); + }); + } +} diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsExpectation.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsExpectation.java new file mode 100644 index 000000000..5cc28cd94 --- /dev/null +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsExpectation.java @@ -0,0 +1,117 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.generator.tests; + +import org.eclipse.core.runtime.AssertionFailedException; +import tools.refinery.generator.FilteredInterpretation; +import tools.refinery.generator.ModelSemantics; +import tools.refinery.language.model.problem.Assertion; +import tools.refinery.language.model.problem.Node; +import tools.refinery.language.model.problem.NodeAssertionArgument; +import tools.refinery.language.model.problem.WildcardAssertionArgument; +import tools.refinery.language.semantics.SemanticsUtils; +import tools.refinery.logic.term.truthvalue.TruthValue; +import tools.refinery.store.reasoning.ReasoningAdapter; +import tools.refinery.store.reasoning.interpretation.PartialInterpretation; +import tools.refinery.store.reasoning.literal.Concreteness; +import tools.refinery.store.tuple.Tuple; + +public record SemanticsExpectation(Assertion assertion, Concreteness concreteness, boolean exact, + int lineNumber, String description, String source) { + public void execute(ModelSemantics semantics) { + var trace = semantics.getProblemTrace(); + var symbol = trace.getPartialRelation(assertion.getRelation()); + var reasoningAdapter = semantics.getModel().getAdapter(ReasoningAdapter.class); + var interpretation = reasoningAdapter.getPartialInterpretation(concreteness, symbol); + var existsInterpretation = reasoningAdapter.getPartialInterpretation(concreteness, + ReasoningAdapter.EXISTS_SYMBOL); + var filteredInterpretation = new FilteredInterpretation<>(interpretation, existsInterpretation); + + var arguments = assertion.getArguments(); + int arity = arguments.size(); + var nodeIds = new int[arity]; + boolean wildcard = false; + for (int i = 0; i < arity; i++) { + var argument = arguments.get(i); + switch (argument) { + case NodeAssertionArgument nodeAssertionArgument -> { + var nodeOrVariable = nodeAssertionArgument.getNode(); + if (!(nodeOrVariable instanceof Node node)) { + throw new IllegalArgumentException("Invalid Node: " + nodeOrVariable); + } + nodeIds[i] = trace.getNodeId(node); + } + case WildcardAssertionArgument ignored -> { + nodeIds[i] = 1; + wildcard = true; + } + default -> throw new IllegalArgumentException("Invalid AssertionArgument: " + argument); + } + } + + var expectedValue = SemanticsUtils.getTruthValue(assertion.getValue()); + if (wildcard) { + checkWildcard(filteredInterpretation, nodeIds, expectedValue); + } else { + checkSingle(filteredInterpretation, nodeIds, expectedValue); + } + } + + + private void checkSingle(PartialInterpretation interpretation, int[] nodeIds, + TruthValue expectedValue) { + var tuple = Tuple.of(nodeIds); + var actual = interpretation.get(tuple); + if (assertionFailed(expectedValue, actual)) { + throw new AssertionFailedException(getMessage(actual)); + } + } + + private void checkWildcard(PartialInterpretation interpretation, int[] nodeIds, + TruthValue expectedValue) { + int arity = nodeIds.length; + var cursor = interpretation.getAll(); + while (cursor.move()) { + var key = cursor.getKey(); + boolean matches = true; + for (int i = 0; matches && i < arity; i++) { + int nodeId = nodeIds[i]; + if (nodeId >= 0 && key.get(i) != nodeId) { + matches = false; + } + } + if (matches && assertionFailed(expectedValue, cursor.getValue())) { + throw new AssertionFailedException(getMessage(null)); + } + } + } + + private boolean assertionFailed(TruthValue expectedValue, TruthValue actual) { + return !(exact ? actual.equals(expectedValue) : actual.isRefinementOf(expectedValue)); + } + + private String getMessage(TruthValue actual) { + var messageBuilder = new StringBuilder(); + messageBuilder.append("EXPECT"); + if (concreteness == Concreteness.CANDIDATE) { + messageBuilder.append(" CANDIDATE"); + } + if (exact) { + messageBuilder.append(" EXACTLY"); + } + messageBuilder.append(" ").append(source); + if (description != null) { + messageBuilder.append(" (").append(description).append(")"); + } + if (actual == null) { + messageBuilder.append(" failed"); + } else { + messageBuilder.append(" was ").append(actual).append(" instead"); + } + messageBuilder.append(" in line ").append(lineNumber); + return messageBuilder.toString(); + } +} diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTest.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTest.java new file mode 100644 index 000000000..6a34f6efc --- /dev/null +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTest.java @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.generator.tests; + +import tools.refinery.generator.ModelSemanticsFactory; + +import java.util.List; + +public record SemanticsTest(List testCases) { + public void execute(ModelSemanticsFactory semanticsFactory) { + for (var testCase : testCases) { + testCase.execute(semanticsFactory); + } + } +} diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestBuilder.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestBuilder.java new file mode 100644 index 000000000..2d40af5fd --- /dev/null +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestBuilder.java @@ -0,0 +1,93 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.generator.tests; + +import org.eclipse.emf.common.util.URI; +import tools.refinery.generator.ProblemLoader; +import tools.refinery.generator.tests.internal.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + +class SemanticsTestBuilder implements ChunkAcceptor { + private final Pattern LINE_PATTERN = Pattern.compile("^.+$", Pattern.MULTILINE); + + private final ProblemLoader problemLoader; + private final URI uri; + private final StringBuilder commonBuilder = new StringBuilder(); + private final List testCases = new ArrayList<>(); + private SemanticsTestCaseBuilder testCaseBuilder; + private boolean singleTestMode; + + public SemanticsTestBuilder(ProblemLoader problemLoader, URI uri) { + this.problemLoader = problemLoader; + this.uri = uri; + } + + @Override + public void acceptChunk(ChunkHeader header, String body) { + switch (header) { + case CommonHeader ignored -> { + if (testCaseBuilder != null) { + throw new IllegalStateException("Can't accept common test code after the first test case."); + } + commonBuilder.append(body); + } + case TestCaseHeader testCaseHeader -> { + if (singleTestMode) { + throw new IllegalStateException("Can't accept TEST chunk after an EXPECT chunk."); + } + acceptTestCase(testCaseHeader, body); + appendEmptyLines(body); + } + case ExpectationHeader expectationHeader -> { + if (testCaseBuilder == null) { + acceptTestCase(new TestCaseHeader(false, null), null); + singleTestMode = true; + } + testCaseBuilder.acceptExpectation(expectationHeader, body); + appendEmptyLines(body); + } + default -> throw new IllegalArgumentException("Unknown ChunkHeader: " + header); + } + } + + private void appendEmptyLines(String body) { + if (singleTestMode) { + return; + } + var placeholder = LINE_PATTERN.matcher(body).replaceAll(""); + commonBuilder.append(placeholder); + } + + private void acceptTestCase(TestCaseHeader header, String body) { + if (testCaseBuilder != null) { + testCases.add(testCaseBuilder.build()); + } + var problemStringBuilder = new StringBuilder(commonBuilder); + if (body != null) { + problemStringBuilder.append(body); + } + testCaseBuilder = new SemanticsTestCaseBuilder(header, problemStringBuilder, problemLoader, uri); + } + + @Override + public void acceptEnd() { + if (testCaseBuilder == null) { + throw new IllegalStateException("Test file contained no TEST or EXPECT chunks."); + } + testCases.add(testCaseBuilder.build()); + } + + public SemanticsTest build() { + if (testCases.isEmpty()) { + throw new IllegalStateException("No test cases."); + } + return new SemanticsTest(Collections.unmodifiableList(testCases)); + } +} diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCase.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCase.java new file mode 100644 index 000000000..952924e2e --- /dev/null +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCase.java @@ -0,0 +1,99 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.generator.tests; + +import org.eclipse.collections.api.factory.primitive.IntObjectMaps; +import org.eclipse.collections.api.map.primitive.IntObjectMap; +import org.eclipse.core.runtime.AssertionFailedException; +import tools.refinery.generator.ModelSemantics; +import tools.refinery.generator.ModelSemanticsFactory; +import tools.refinery.language.model.problem.Problem; +import tools.refinery.language.semantics.ProblemTrace; +import tools.refinery.logic.term.truthvalue.TruthValue; +import tools.refinery.store.map.Cursor; +import tools.refinery.store.reasoning.literal.Concreteness; +import tools.refinery.store.reasoning.representation.PartialRelation; +import tools.refinery.store.tuple.Tuple; + +import java.util.List; + +public record SemanticsTestCase(String name, boolean allowErrors, Problem problem, + List expectations) { + public void execute(ModelSemanticsFactory semanticsFactory) { + semanticsFactory.withCandidateInterpretations(needsCandidateInterpretations()); + var semantics = semanticsFactory.createSemantics(problem); + if (!allowErrors) { + checkNoErrors(semantics); + } + for (var expectation : expectations) { + expectation.execute(semantics); + } + } + + public boolean needsCandidateInterpretations() { + for (var expectation : expectations) { + if (expectation.concreteness() == Concreteness.CANDIDATE) { + return true; + } + } + return false; + } + + private void checkNoErrors(ModelSemantics semantics) { + boolean hasError = false; + var errorsBuilder = new StringBuilder("Errors found in partial model:\n\n"); + var trace = semantics.getProblemTrace(); + IntObjectMap nodeNames = null; + for (var symbol : trace.getRelationTrace().values()) { + var interpretation = semantics.getPartialInterpretation(symbol); + var cursor = interpretation.getAll(); + while (cursor.move()) { + if (!cursor.getValue().isError()) { + continue; + } + hasError = true; + if (nodeNames == null) { + nodeNames = getNodeNames(trace); + } + appendError(symbol, errorsBuilder, cursor, nodeNames); + } + } + if (hasError) { + throw new AssertionFailedException(errorsBuilder.toString()); + } + } + + private IntObjectMap getNodeNames(ProblemTrace trace) { + var nodeNames = IntObjectMaps.mutable.empty(); + trace.getNodeTrace().forEachKeyValue((node, i) -> { + var name = node.getName(); + if (name != null) { + nodeNames.put(i, name); + } + }); + return nodeNames; + } + + private static void appendError(PartialRelation symbol, StringBuilder errorsBuilder, + Cursor cursor, IntObjectMap nodeNames) { + errorsBuilder.append('\t').append(symbol.name()).append("("); + var key = cursor.getKey(); + int arity = key.getSize(); + for (int i = 0; i < arity; i++) { + if (i > 0) { + errorsBuilder.append(", "); + } + int nodeId = key.get(i); + var name = nodeNames.get(nodeId); + if (name == null) { + errorsBuilder.append("::").append(i); + } else { + errorsBuilder.append(name); + } + } + errorsBuilder.append("): error.\n"); + } +} diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCaseBuilder.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCaseBuilder.java new file mode 100644 index 000000000..cd163cb89 --- /dev/null +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCaseBuilder.java @@ -0,0 +1,95 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.generator.tests; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.xtext.nodemodel.INode; +import org.eclipse.xtext.nodemodel.util.NodeModelUtils; +import tools.refinery.generator.ProblemLoader; +import tools.refinery.generator.tests.internal.ExpectationHeader; +import tools.refinery.generator.tests.internal.TestCaseHeader; +import tools.refinery.language.model.problem.Assertion; +import tools.refinery.language.model.problem.Problem; +import tools.refinery.language.model.problem.Statement; + +import java.io.IOException; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Deque; + +class SemanticsTestCaseBuilder { + private final TestCaseHeader testCaseHeader; + private final StringBuilder stringBuilder; + private final ProblemLoader problemLoader; + private final URI uri; + private final Deque expectationsDeque = new ArrayDeque<>(); + + public SemanticsTestCaseBuilder(TestCaseHeader testCaseHeader, StringBuilder stringBuilder, + ProblemLoader problemLoader, URI uri) { + this.testCaseHeader = testCaseHeader; + this.stringBuilder = stringBuilder; + this.problemLoader = problemLoader; + this.uri = uri; + } + + public void acceptExpectation(ExpectationHeader header, String body) { + stringBuilder.append(body); + expectationsDeque.addLast(header); + } + + public SemanticsTestCase build() { + Problem problem; + try { + problem = problemLoader.loadString(stringBuilder.toString(), uri); + } catch (IOException e) { + throw new IllegalStateException("Failed to parse problem: " + uri, e); + } + if (expectationsDeque.isEmpty() && testCaseHeader.allowErrors()) { + throw new IllegalStateException("Test has no EXPECT chunks."); + } + var statements = problem.getStatements(); + int initialStatementCount = 0; + ExpectationHeader currentHeader = null; + var expectations = new ArrayList(); + for (var statement : statements) { + var node = NodeModelUtils.findActualNodeFor(statement); + if (node == null) { + throw new IllegalStateException("No node for statement: " + statement); + } + var nextHeader = expectationsDeque.peekFirst(); + if (nextHeader != null && node.getStartLine() >= nextHeader.startLine()) { + currentHeader = nextHeader; + expectationsDeque.removeFirst(); + } + if (currentHeader == null) { + initialStatementCount++; + } else { + var expectation = createExpectation(currentHeader, statement, node); + expectations.add(expectation); + } + } + int statementCount = statements.size(); + if (statementCount > initialStatementCount) { + statements.subList(initialStatementCount, statementCount).clear(); + } + return new SemanticsTestCase(testCaseHeader.name(), testCaseHeader.allowErrors(), problem, + Collections.unmodifiableList(expectations)); + } + + private static SemanticsExpectation createExpectation(ExpectationHeader header, Statement statement, + INode node) { + if (!(statement instanceof Assertion assertion)) { + throw new IllegalArgumentException("Only assertions are supported in EXPECT chunks, got %s instead." + .formatted(statement.eClass().getName())); + } + if (assertion.isDefault()) { + throw new IllegalArgumentException("Default assertions are not supported in EXPECT chunks."); + } + return new SemanticsExpectation(assertion, header.concreteness(), header.exact(), + node.getStartLine(), header.description(), NodeModelUtils.getTokenText(node).strip()); + } +} diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestLoader.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestLoader.java new file mode 100644 index 000000000..82c8deb1e --- /dev/null +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestLoader.java @@ -0,0 +1,71 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.generator.tests; + +import com.google.inject.Inject; +import org.eclipse.emf.common.util.URI; +import tools.refinery.generator.ProblemLoader; +import tools.refinery.generator.tests.internal.ProblemSplitter; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; + +public class SemanticsTestLoader { + @Inject + private ProblemSplitter problemSplitter; + + @Inject + private ProblemLoader problemLoader; + + public SemanticsTestLoader extraPath(String path) { + problemLoader.extraPath(Path.of(path)); + return this; + } + + public SemanticsTestLoader extraPath(Path path) { + problemLoader.extraPath(path); + return this; + } + + public SemanticsTest loadString(String problemString, URI uri) { + var builder = new SemanticsTestBuilder(problemLoader, uri); + problemSplitter.transformProblem(problemString, builder); + return builder.build(); + } + + public SemanticsTest loadString(String problemString) { + return loadString(problemString, null); + } + + public SemanticsTest loadStream(InputStream inputStream, URI uri) throws IOException { + byte[] bytes; + try (var outputStream = new ByteArrayOutputStream()) { + inputStream.transferTo(outputStream); + bytes = outputStream.toByteArray(); + } + var problemString = new String(bytes, StandardCharsets.UTF_8); + return loadString(problemString, uri); + } + + public SemanticsTest loadStream(InputStream inputStream) throws IOException { + return loadStream(inputStream, null); + } + + public SemanticsTest loadFile(File file) throws IOException { + var uri = URI.createFileURI(file.getAbsolutePath()); + try (var inputStream = new FileInputStream(file)) { + return loadStream(inputStream, uri); + } + } + + public SemanticsTest loadFile(String filePath) throws IOException { + var uri = URI.createFileURI(filePath); + try (var inputStream = new FileInputStream(filePath)) { + return loadStream(inputStream, uri); + } + } +} diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkAcceptor.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkAcceptor.java new file mode 100644 index 000000000..cf867b190 --- /dev/null +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkAcceptor.java @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.generator.tests.internal; + +public interface ChunkAcceptor { + void acceptChunk(ChunkHeader header, String body); + + void acceptEnd(); +} diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkHeader.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkHeader.java new file mode 100644 index 000000000..a69668ec2 --- /dev/null +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkHeader.java @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.generator.tests.internal; + +public sealed interface ChunkHeader permits CommonHeader, TestCaseHeader, ExpectationHeader { +} diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/CommonHeader.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/CommonHeader.java new file mode 100644 index 000000000..bec9e7484 --- /dev/null +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/CommonHeader.java @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.generator.tests.internal; + +public final class CommonHeader implements ChunkHeader { + public static final CommonHeader INSTANCE = new CommonHeader(); + + private CommonHeader() { + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[]"; + } +} diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ExpectationHeader.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ExpectationHeader.java new file mode 100644 index 000000000..00608739e --- /dev/null +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ExpectationHeader.java @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.generator.tests.internal; + +import tools.refinery.store.reasoning.literal.Concreteness; + +public record ExpectationHeader(Concreteness concreteness, boolean exact, String description, + int startLine) implements ChunkHeader { +} diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ProblemSplitter.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ProblemSplitter.java new file mode 100644 index 000000000..33a0ca6ed --- /dev/null +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ProblemSplitter.java @@ -0,0 +1,92 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.generator.tests.internal; + +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.Provider; +import com.google.inject.Singleton; +import com.google.inject.name.Named; +import org.antlr.runtime.ANTLRStringStream; +import org.antlr.runtime.CommonToken; +import org.antlr.runtime.Token; +import org.antlr.runtime.TokenSource; +import org.eclipse.xtext.parser.antlr.Lexer; +import tools.refinery.language.parser.antlr.ProblemTokenSource; +import tools.refinery.language.parser.antlr.lexer.InternalProblemLexer; +import tools.refinery.store.reasoning.literal.Concreteness; + +import java.util.regex.Pattern; + +@Singleton +public class ProblemSplitter { + private static final String COMMENT_PREFIX = "(//|%)\\s*"; + + private static final Pattern TEST_CASE_PATTERN = Pattern.compile(COMMENT_PREFIX + + "TEST(?\\s+WITH\\s+ERRORS)?(\\s*:\\s*(?\\S.*)?)?"); + + private static final Pattern EXPECTATION_PATTERN = Pattern.compile(COMMENT_PREFIX + + "EXPECT(?\\s+CANDIDATE)?(?\\s+EXACTLY)?(\\s*:\\s*(?\\S.*)?)?"); + + @Inject + @Named("org.eclipse.xtext.parser.antlr.Lexer.RUNTIME") + private Provider lexerProvider; + + @Inject + private Injector injector; + + public void transformProblem(String problemString, ChunkAcceptor acceptor) { + var tokenSource = getTokenSource(problemString); + Token token = tokenSource.nextToken(); + ChunkHeader lastHeader = CommonHeader.INSTANCE; + int lastStartIndex = 0; + do { + if (token.getType() == InternalProblemLexer.RULE_SL_COMMENT) { + if (!(token instanceof CommonToken commonToken)) { + throw new IllegalStateException("Unexpected token: " + token); + } + var header = parseHeader(token); + if (header != null) { + int startIndex = commonToken.getStartIndex(); + var body = problemString.substring(lastStartIndex, startIndex); + acceptor.acceptChunk(lastHeader, body); + lastHeader = header; + lastStartIndex = startIndex; + } + } + token = tokenSource.nextToken(); + } while (token != null && token.getType() != Token.EOF); + acceptor.acceptChunk(lastHeader, problemString.substring(lastStartIndex)); + acceptor.acceptEnd(); + } + + private TokenSource getTokenSource(String problemString) { + var charStream = new ANTLRStringStream(problemString); + var lexer = lexerProvider.get(); + lexer.setCharStream(charStream); + var tokenSource = new ProblemTokenSource(lexer); + injector.injectMembers(tokenSource); + return tokenSource; + } + + private ChunkHeader parseHeader(Token token) { + var headerText = token.getText().strip(); + var testCaseMatcher = TEST_CASE_PATTERN.matcher(headerText); + if (testCaseMatcher.matches()) { + boolean allowErrors = testCaseMatcher.group("allowErrors") != null; + return new TestCaseHeader(allowErrors, testCaseMatcher.group("name")); + } + var expectationMatcher = EXPECTATION_PATTERN.matcher(headerText); + if (expectationMatcher.matches()) { + var concreteness = expectationMatcher.group("candidate") == null ? Concreteness.PARTIAL : + Concreteness.CANDIDATE; + var exact = expectationMatcher.group("exact") != null; + return new ExpectationHeader(concreteness, exact, expectationMatcher.group("description"), + token.getLine()); + } + return null; + } +} diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/TestCaseHeader.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/TestCaseHeader.java new file mode 100644 index 000000000..505b4769b --- /dev/null +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/TestCaseHeader.java @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.generator.tests.internal; + +public record TestCaseHeader(boolean allowErrors, String name) implements ChunkHeader { +} diff --git a/subprojects/logic/src/main/java/tools/refinery/logic/term/truthvalue/TruthValue.java b/subprojects/logic/src/main/java/tools/refinery/logic/term/truthvalue/TruthValue.java index 59bdeab39..671e1a055 100644 --- a/subprojects/logic/src/main/java/tools/refinery/logic/term/truthvalue/TruthValue.java +++ b/subprojects/logic/src/main/java/tools/refinery/logic/term/truthvalue/TruthValue.java @@ -50,7 +50,6 @@ public boolean isConsistent() { return !isError(); } - public boolean isComplete() { return this != UNKNOWN; } From cc3ae9605b999f4cf372109d9a9c76f696359a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20Marussy?= Date: Sun, 21 Jul 2024 14:47:15 +0200 Subject: [PATCH 2/9] test: filesystem-based semantics test loading --- .../generator/FileBasedSemanticsTest.java | 5 +- .../generator/tests/DynamicTestLoader.java | 150 ++++++++++++++++-- 2 files changed, 134 insertions(+), 21 deletions(-) diff --git a/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java b/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java index 6fdcf3fd5..af62a90b8 100644 --- a/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java +++ b/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java @@ -24,9 +24,6 @@ class FileBasedSemanticsTest { @TestFactory Stream fileBasedTests() { - return loader.fromClasspath(getClass(), - "abstractTypeHierarchy.problem", - "typeHierarchy.problem" - ); + return loader.allFromClasspath(getClass()); } } diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/DynamicTestLoader.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/DynamicTestLoader.java index 4a93e77ad..7886ec0ae 100644 --- a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/DynamicTestLoader.java +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/DynamicTestLoader.java @@ -9,85 +9,147 @@ import com.google.inject.Provider; import org.junit.jupiter.api.DynamicNode; import org.junit.jupiter.api.function.Executable; +import org.opentest4j.TestAbortedException; import tools.refinery.generator.ModelSemanticsFactory; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; import java.util.stream.Stream; import static org.junit.jupiter.api.DynamicContainer.dynamicContainer; import static org.junit.jupiter.api.DynamicTest.dynamicTest; public class DynamicTestLoader { + private static final String TEST_SUFFIX = ".problem"; + @Inject - private SemanticsTestLoader testLoader; + private Provider testLoaderProvider; @Inject private Provider semanticsFactoryProvider; - public Stream fromClasspath(Class klass, String name) { + public Stream allFromClasspath(Class contextClass) { + var paths = getExtraPaths(contextClass); + if (paths.isEmpty()) { + throw new IllegalArgumentException("No file system paths found for class: " + contextClass); + } + var loader = getTestLoader(paths); + var nodes = new ArrayList(); + for (var path : paths) { + List childNodes; + try { + childNodes = nodesFromPath(loader, path); + } catch (IOException e) { + throw new IllegalArgumentException("Failed to enumerate path: " + path, e); + } + nodes.addAll(childNodes); + } + if (nodes.isEmpty()) { + throw new TestAbortedException("No tests found for class: " + contextClass); + } + return nodes.stream(); + } + + private List nodesFromPath(SemanticsTestLoader loader, Path path) throws IOException { + var nodes = new ArrayList(); + try (var childList = Files.list(path)) { + var iterator = childList.iterator(); + while (iterator.hasNext()) { + var childPath = iterator.next(); + var fileName = childPath.getFileName().toString(); + var uri = childPath.toUri(); + try { + if (Files.isDirectory(childPath)) { + var childNodes = nodesFromPath(loader, childPath); + if (!childNodes.isEmpty()) { + nodes.add(dynamicContainer(fileName, uri, childNodes.stream())); + } + } else if (fileName.endsWith(TEST_SUFFIX)) { + SemanticsTest test = loader.loadFile(childPath.toFile()); + if (test != null) { + nodes.add(createDynamicNode(fileName, uri, test)); + } + } + } catch (IOException | RuntimeException e) { + nodes.add(createErrorNode(fileName, uri, e)); + } + } + } + return nodes; + } + + public Stream fromClasspath(Class contextClass, String name) { + var loader = getTestLoader(contextClass); URL url; URI uri; try { - url = safeGetResource(klass, name); + url = safeGetResource(contextClass, name); uri = url.toURI(); } catch (RuntimeException | URISyntaxException e) { return Stream.of(createErrorNode(name, null, e)); } SemanticsTest test; try { - test = loadFromUrl(uri, url); + test = loadFromUrl(loader, uri, url); } catch (IOException | RuntimeException e) { return Stream.of(createErrorNode(name, uri, e)); } return createDynamicNodes(uri, test); } - public Stream fromClasspath(Class klass, String... names) { - return fromClasspath(klass, Stream.of(names)); + public Stream fromClasspath(Class contextClass, String... names) { + return fromClasspath(contextClass, Stream.of(names)); } - public Stream fromClasspath(Class klass, Stream names) { - return names.map(name -> nodeFromClasspath(klass, name)); + public Stream fromClasspath(Class contextClass, Stream names) { + var loader = getTestLoader(contextClass); + return names.map(name -> nodeFromClasspath(loader, contextClass, name)); } - private DynamicNode nodeFromClasspath(Class klass, String name) { + private DynamicNode nodeFromClasspath(SemanticsTestLoader loader, Class contextClass, String name) { URL url; URI uri; try { - url = safeGetResource(klass, name); + url = safeGetResource(contextClass, name); uri = url.toURI(); } catch (RuntimeException | URISyntaxException e) { return createErrorNode(name, null, e); } SemanticsTest test; try { - test = loadFromUrl(uri, url); + test = loadFromUrl(loader, uri, url); } catch (IOException | RuntimeException e) { return createErrorNode(name, uri, e); } return createDynamicNode(name, uri, test); } - private static URL safeGetResource(Class klass, String name) { - var url = klass.getResource(name); + private static URL safeGetResource(Class contextClass, String name) { + var url = contextClass.getResource(name); if (url == null) { throw new IllegalStateException("Test resource %s was not found.".formatted(name)); } return url; } - private SemanticsTest loadFromUrl(URI uri, URL url) throws IOException { + private SemanticsTest loadFromUrl(SemanticsTestLoader testLoader, URI uri, URL url) throws IOException { var eclipseUri = org.eclipse.emf.common.util.URI.createURI(uri.toString()); try (var inputStream = url.openStream()) { return testLoader.loadStream(inputStream, eclipseUri); } } - public Stream fromString(String problem) { + public Stream fromString(Class contextClass, String problem) { + var testLoader = getTestLoader(contextClass); SemanticsTest test; try { test = testLoader.loadString(problem); @@ -97,6 +159,10 @@ public Stream fromString(String problem) { return createDynamicNodes(null, test); } + public Stream fromString(String problem) { + return fromString(null, problem); + } + private DynamicNode createDynamicNode(String name, URI uri, SemanticsTest test) { var testCases = test.testCases(); if (testCases.size() == 1 && testCases.getFirst().name() == null) { @@ -115,7 +181,7 @@ private Stream createDynamicNodes(URI uri, SemanticsTest test) { var testCase = testCases.get(i); var testCaseName = testCase.name(); if (testCaseName == null) { - testCaseName = "[%d]".formatted(i); + testCaseName = "[%d]".formatted(i + 1); } children.add(dynamicTest(testCaseName, uri, asExecutable(testCase))); } @@ -136,8 +202,58 @@ private DynamicNode createErrorNode(String name, URI uri, Throwable cause) { messageBuilder.append(": ").append(cause.getMessage()); } var message = messageBuilder.toString(); - return dynamicTest(name, uri, () -> { + return dynamicTest(name, uri, () -> { throw new RuntimeException(message, cause); }); } + + private SemanticsTestLoader getTestLoader(Class contextClass) { + var extraPaths = getExtraPaths(contextClass); + return getTestLoader(extraPaths); + } + + private SemanticsTestLoader getTestLoader(List extraPaths) { + var loader = testLoaderProvider.get(); + extraPaths.forEach(loader::extraPath); + return loader; + } + + private List getExtraPaths(Class contextClass) { + if (contextClass == null) { + return List.of(); + } + var resourceName = contextClass.getPackageName().replace('.', '/'); + Enumeration resources; + try { + resources = contextClass.getClassLoader().getResources(resourceName); + } catch (IOException e) { + // Failed to find any resources. + return List.of(); + } + var directories = new ArrayList(); + while (resources.hasMoreElements()) { + var url = resources.nextElement(); + var path = getPath(url); + if (path != null && path.getFileSystem() == FileSystems.getDefault()) { + directories.add(path); + } + } + return directories; + } + + private static Path getPath(URL url) { + URI uri; + try { + uri = url.toURI(); + } catch (URISyntaxException e) { + return null; + } + Path path; + try { + path = Path.of(uri); + } catch (FileSystemNotFoundException e) { + return null; + } + return path.toAbsolutePath(); + } } From 509d4db75c6121fd6fac665c5ec8cebd683867e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20Marussy?= Date: Sun, 21 Jul 2024 15:55:49 +0200 Subject: [PATCH 3/9] test(language): add @InjectWithRefinery annotation --- subprojects/generator/build.gradle.kts | 2 +- .../generator/FileBasedSemanticsTest.java | 8 +--- .../refinery/generator/ProblemLoaderTest.java | 8 +--- .../semantics/ModelGenerationTest.java | 10 ++--- .../semantics/SolutionSerializerTest.java | 10 ++--- subprojects/language/build.gradle.kts | 1 + .../language/tests/ProblemParsingTest.java | 8 +--- .../DocumentationCommentParserTest.java | 10 ++--- .../formatting2/ProblemFormatterTest.java | 8 +--- .../tests/linking/AmbiguousReferenceTest.java | 10 ++--- .../antlr/IdentifierTokenProviderTest.java | 8 +--- .../parser/antlr/ProblemTokenSourceTest.java | 8 +--- .../antlr/TransitiveClosureParserTest.java | 10 ++--- .../language/tests/rules/RuleParsingTest.java | 40 ------------------- .../tests/scoping/NodeScopingTest.java | 12 ++---- .../serializer/ProblemSerializerTest.java | 10 ++--- .../tests/validation/ArityValidationTest.java | 10 ++--- .../validation/AssertionValidationTest.java | 11 ++--- .../validation/AssignmentValidationTest.java | 10 ++--- .../validation/ModuleValidationTest.java | 10 ++--- .../MultiplicityValidationTest.java | 10 ++--- .../validation/OppositeValidationTest.java | 10 ++--- .../language/tests/InjectWithRefinery.java | 22 ++++++++++ .../tests/utils/ProblemNavigationUtil.java | 2 +- .../tests/utils/ProblemParseHelper.java | 2 +- .../tests/utils/WrappedAction.java | 2 +- .../tests/utils/WrappedArgument.java | 2 +- .../tests/utils/WrappedAssertion.java | 2 +- .../tests/utils/WrappedAssertionArgument.java | 2 +- .../{model => }/tests/utils/WrappedAtom.java | 4 +- .../tests/utils/WrappedClassDeclaration.java | 2 +- .../tests/utils/WrappedConjunction.java | 4 +- .../tests/utils/WrappedConsequent.java | 2 +- .../tests/utils/WrappedEnumDeclaration.java | 4 +- .../tests/utils/WrappedLiteral.java | 2 +- .../utils/WrappedParametricDefinition.java | 2 +- .../utils/WrappedPredicateDefinition.java | 2 +- .../tests/utils/WrappedProblem.java | 2 +- .../tests/utils/WrappedRuleDefinition.java | 2 +- 39 files changed, 95 insertions(+), 189 deletions(-) delete mode 100644 subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java create mode 100644 subprojects/language/src/testFixtures/java/tools/refinery/language/tests/InjectWithRefinery.java rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/ProblemNavigationUtil.java (93%) rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/ProblemParseHelper.java (94%) rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/WrappedAction.java (84%) rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/WrappedArgument.java (90%) rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/WrappedAssertion.java (89%) rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/WrappedAssertionArgument.java (91%) rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/WrappedAtom.java (87%) rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/WrappedClassDeclaration.java (91%) rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/WrappedConjunction.java (88%) rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/WrappedConsequent.java (88%) rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/WrappedEnumDeclaration.java (90%) rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/WrappedLiteral.java (92%) rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/WrappedParametricDefinition.java (88%) rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/WrappedPredicateDefinition.java (91%) rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/WrappedProblem.java (98%) rename subprojects/language/src/testFixtures/java/tools/refinery/language/{model => }/tests/utils/WrappedRuleDefinition.java (92%) diff --git a/subprojects/generator/build.gradle.kts b/subprojects/generator/build.gradle.kts index 7fa4b8494..14eebf7de 100644 --- a/subprojects/generator/build.gradle.kts +++ b/subprojects/generator/build.gradle.kts @@ -16,6 +16,6 @@ mavenArtifact { dependencies { api(project(":refinery-language-semantics")) implementation(project(":refinery-store-query-interpreter")) + testFixturesApi(testFixtures(project(":refinery-language"))) testFixturesImplementation(libs.junit.api) - testImplementation(testFixtures(project(":refinery-language"))) } diff --git a/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java b/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java index af62a90b8..6e954188a 100644 --- a/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java +++ b/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java @@ -6,18 +6,14 @@ package tools.refinery.generator; import com.google.inject.Inject; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.junit.jupiter.api.DynamicNode; import org.junit.jupiter.api.TestFactory; -import org.junit.jupiter.api.extension.ExtendWith; import tools.refinery.generator.tests.DynamicTestLoader; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; import java.util.stream.Stream; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class FileBasedSemanticsTest { @Inject private DynamicTestLoader loader; diff --git a/subprojects/generator/src/test/java/tools/refinery/generator/ProblemLoaderTest.java b/subprojects/generator/src/test/java/tools/refinery/generator/ProblemLoaderTest.java index b0f31e03e..14ae14936 100644 --- a/subprojects/generator/src/test/java/tools/refinery/generator/ProblemLoaderTest.java +++ b/subprojects/generator/src/test/java/tools/refinery/generator/ProblemLoaderTest.java @@ -6,13 +6,10 @@ package tools.refinery.generator; import com.google.inject.Inject; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -24,8 +21,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class ProblemLoaderTest { private static final String PREFIX = """ class Foo. diff --git a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/ModelGenerationTest.java b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/ModelGenerationTest.java index b4abce818..44d83cdc4 100644 --- a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/ModelGenerationTest.java +++ b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/ModelGenerationTest.java @@ -6,14 +6,11 @@ package tools.refinery.language.semantics; import com.google.inject.Inject; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import tools.refinery.language.ProblemStandaloneSetup; -import tools.refinery.language.model.tests.utils.ProblemParseHelper; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; +import tools.refinery.language.tests.utils.ProblemParseHelper; import tools.refinery.store.dse.propagation.PropagationAdapter; import tools.refinery.store.dse.strategy.BestFirstStoreManager; import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter; @@ -33,8 +30,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.empty; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery @Disabled("For debugging purposes only") class ModelGenerationTest { @Inject diff --git a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/SolutionSerializerTest.java b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/SolutionSerializerTest.java index 9f36445ae..69b5f1c2a 100644 --- a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/SolutionSerializerTest.java +++ b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/SolutionSerializerTest.java @@ -7,14 +7,11 @@ import com.google.inject.Inject; import com.google.inject.Provider; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import tools.refinery.language.model.tests.utils.ProblemParseHelper; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; +import tools.refinery.language.tests.utils.ProblemParseHelper; import tools.refinery.store.dse.propagation.PropagationAdapter; import tools.refinery.store.dse.strategy.BestFirstStoreManager; import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter; @@ -34,8 +31,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class SolutionSerializerTest { @Inject private ProblemParseHelper parseHelper; diff --git a/subprojects/language/build.gradle.kts b/subprojects/language/build.gradle.kts index dc3386862..6cbecaa67 100644 --- a/subprojects/language/build.gradle.kts +++ b/subprojects/language/build.gradle.kts @@ -33,6 +33,7 @@ dependencies { api(libs.xtext.core) api(libs.xtext.xbase) api(project(":refinery-language-model")) + testFixturesApi(libs.junit.api) testFixturesApi(libs.xtext.testing) mwe2(libs.xtext.generator) mwe2(libs.xtext.generator.antlr) diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java index 17ae5fbb4..68c5d31e4 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java @@ -6,17 +6,13 @@ package tools.refinery.language.tests; import com.google.inject.Inject; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import tools.refinery.language.model.tests.utils.ProblemParseHelper; +import tools.refinery.language.tests.utils.ProblemParseHelper; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.empty; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class ProblemParsingTest { @Inject private ProblemParseHelper parseHelper; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/documentation/DocumentationCommentParserTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/documentation/DocumentationCommentParserTest.java index 0566e7e26..5227a733c 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/documentation/DocumentationCommentParserTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/documentation/DocumentationCommentParserTest.java @@ -6,23 +6,19 @@ package tools.refinery.language.tests.documentation; import com.google.inject.Inject; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import tools.refinery.language.documentation.DocumentationCommentParser; -import tools.refinery.language.model.tests.utils.ProblemParseHelper; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; +import tools.refinery.language.tests.utils.ProblemParseHelper; import java.util.stream.Stream; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class DocumentationCommentParserTest { @Inject private ProblemParseHelper parseHelper; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java index 4a15f9de2..52806be1d 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java @@ -13,21 +13,17 @@ import org.eclipse.xtext.formatting2.regionaccess.ITextReplacement; import org.eclipse.xtext.formatting2.regionaccess.TextRegionAccessBuilder; import org.eclipse.xtext.resource.XtextResource; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.eclipse.xtext.testing.util.ParseHelper; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import tools.refinery.language.model.problem.Problem; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class ProblemFormatterTest { @Inject private ParseHelper parseHelper; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/linking/AmbiguousReferenceTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/linking/AmbiguousReferenceTest.java index 464c207ce..ffeaace26 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/linking/AmbiguousReferenceTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/linking/AmbiguousReferenceTest.java @@ -8,19 +8,15 @@ import com.google.inject.Inject; import org.eclipse.xtext.diagnostics.Diagnostic; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import tools.refinery.language.model.tests.utils.ProblemParseHelper; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; +import tools.refinery.language.tests.utils.ProblemParseHelper; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class AmbiguousReferenceTest { @Inject private ProblemParseHelper parseHelper; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java index 37d38dd9b..e798cc95d 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java @@ -6,23 +6,19 @@ package tools.refinery.language.tests.parser.antlr; import com.google.inject.Inject; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import tools.refinery.language.tests.InjectWithRefinery; import tools.refinery.language.parser.antlr.IdentifierTokenProvider; import tools.refinery.language.parser.antlr.internal.InternalProblemParser; -import tools.refinery.language.tests.ProblemInjectorProvider; import java.util.stream.Stream; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class IdentifierTokenProviderTest { @Inject private IdentifierTokenProvider identifierTokenProvider; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java index 644744a0f..d42a57282 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java @@ -12,18 +12,15 @@ import org.antlr.runtime.Token; import org.eclipse.xtext.parser.antlr.Lexer; import org.eclipse.xtext.parser.antlr.LexerBindings; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.hamcrest.Matcher; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; +import tools.refinery.language.tests.InjectWithRefinery; import tools.refinery.language.parser.antlr.IdentifierTokenProvider; import tools.refinery.language.parser.antlr.ProblemTokenSource; import tools.refinery.language.parser.antlr.internal.InternalProblemParser; -import tools.refinery.language.tests.ProblemInjectorProvider; import java.util.ArrayList; import java.util.List; @@ -32,8 +29,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class ProblemTokenSourceTest { @Inject @Named(LexerBindings.RUNTIME) diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java index a9c5f62a2..bfac1c0ca 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java @@ -6,22 +6,18 @@ package tools.refinery.language.tests.parser.antlr; import com.google.inject.Inject; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import tools.refinery.language.model.problem.ArithmeticBinaryExpr; import tools.refinery.language.model.problem.Atom; import tools.refinery.language.model.problem.BinaryOp; import tools.refinery.language.model.problem.ComparisonExpr; -import tools.refinery.language.model.tests.utils.ProblemParseHelper; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; +import tools.refinery.language.tests.utils.ProblemParseHelper; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class TransitiveClosureParserTest { @Inject private ProblemParseHelper parseHelper; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java deleted file mode 100644 index 156364837..000000000 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.language.tests.rules; - -import com.google.inject.Inject; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import tools.refinery.language.model.tests.utils.ProblemParseHelper; -import tools.refinery.language.tests.ProblemInjectorProvider; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.empty; - -@Disabled("TODO: Rework transformation rules") -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) -class RuleParsingTest { - @Inject - private ProblemParseHelper parseHelper; - - @ParameterizedTest - @ValueSource(strings = { """ - pred Person(p). - rule r(p1): must Person(p1) ==> Person(p1): false. - """, """ - pred Person(p). - rule r(p1): must Person(p1) ==> !Person(p1). - """ }) - void simpleTest(String text) { - var problem = parseHelper.parse(text); - assertThat(problem.getResourceErrors(), empty()); - } -} diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java index 0704e026e..ca843734f 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java @@ -6,26 +6,22 @@ package tools.refinery.language.tests.scoping; import com.google.inject.Inject; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; -import tools.refinery.language.model.tests.utils.ProblemParseHelper; -import tools.refinery.language.model.tests.utils.WrappedProblem; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; +import tools.refinery.language.tests.utils.ProblemParseHelper; +import tools.refinery.language.tests.utils.WrappedProblem; import java.util.stream.Stream; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class NodeScopingTest { @Inject private ProblemParseHelper parseHelper; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java index ad583f8ed..2757e08ac 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java @@ -9,17 +9,14 @@ 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 org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import tools.refinery.language.model.problem.*; -import tools.refinery.language.model.tests.utils.WrappedProblem; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; +import tools.refinery.language.tests.utils.WrappedProblem; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -29,8 +26,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class ProblemSerializerTest { @Inject private ResourceSet resourceSet; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ArityValidationTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ArityValidationTest.java index 68e9fa8d8..84ec19aba 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ArityValidationTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ArityValidationTest.java @@ -7,16 +7,13 @@ import com.google.inject.Inject; import org.eclipse.emf.common.util.Diagnostic; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; -import tools.refinery.language.model.tests.utils.ProblemParseHelper; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; +import tools.refinery.language.tests.utils.ProblemParseHelper; import tools.refinery.language.validation.ProblemValidator; import java.util.stream.Stream; @@ -24,8 +21,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class ArityValidationTest { @Inject private ProblemParseHelper parseHelper; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssertionValidationTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssertionValidationTest.java index 274a1aeb4..67bea5d61 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssertionValidationTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssertionValidationTest.java @@ -6,22 +6,17 @@ package tools.refinery.language.tests.validation; import com.google.inject.Inject; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import tools.refinery.language.model.tests.utils.ProblemParseHelper; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; +import tools.refinery.language.tests.utils.ProblemParseHelper; import tools.refinery.language.validation.ProblemValidator; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -import static org.hamcrest.Matchers.is; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class AssertionValidationTest { @Inject private ProblemParseHelper parseHelper; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssignmentValidationTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssignmentValidationTest.java index a9e0e3115..ef0c62ec8 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssignmentValidationTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssignmentValidationTest.java @@ -7,21 +7,17 @@ import com.google.inject.Inject; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import tools.refinery.language.model.tests.utils.ProblemParseHelper; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; +import tools.refinery.language.tests.utils.ProblemParseHelper; import tools.refinery.language.validation.ProblemValidator; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class AssignmentValidationTest { @Inject private ProblemParseHelper parseHelper; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ModuleValidationTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ModuleValidationTest.java index 00ad051bf..6dc16029b 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ModuleValidationTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ModuleValidationTest.java @@ -6,15 +6,12 @@ package tools.refinery.language.tests.validation; import com.google.inject.Inject; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import tools.refinery.language.model.tests.utils.ProblemParseHelper; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; +import tools.refinery.language.tests.utils.ProblemParseHelper; import tools.refinery.language.validation.ProblemValidator; import java.util.stream.Stream; @@ -22,8 +19,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class ModuleValidationTest { @Inject private ProblemParseHelper parseHelper; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/MultiplicityValidationTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/MultiplicityValidationTest.java index a8bcb1a6b..81264d3a0 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/MultiplicityValidationTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/MultiplicityValidationTest.java @@ -7,20 +7,16 @@ import com.google.inject.Inject; import org.eclipse.emf.common.util.Diagnostic; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import tools.refinery.language.model.tests.utils.ProblemParseHelper; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; +import tools.refinery.language.tests.utils.ProblemParseHelper; import tools.refinery.language.validation.ProblemValidator; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class MultiplicityValidationTest { @Inject private ProblemParseHelper parseHelper; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/OppositeValidationTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/OppositeValidationTest.java index d73ef8e71..7844f49ce 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/OppositeValidationTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/OppositeValidationTest.java @@ -7,14 +7,11 @@ import com.google.inject.Inject; import org.eclipse.emf.common.util.Diagnostic; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import tools.refinery.language.model.tests.utils.ProblemParseHelper; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; +import tools.refinery.language.tests.utils.ProblemParseHelper; import tools.refinery.language.validation.ProblemValidator; import java.util.Set; @@ -22,8 +19,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery class OppositeValidationTest { @Inject private ProblemParseHelper parseHelper; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/InjectWithRefinery.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/InjectWithRefinery.java new file mode 100644 index 000000000..c9fb453e2 --- /dev/null +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/InjectWithRefinery.java @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.language.tests; + +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(InjectionExtension.class) +@InjectWith(ProblemInjectorProvider.class) +public @interface InjectWithRefinery { +} diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemNavigationUtil.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/ProblemNavigationUtil.java similarity index 93% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemNavigationUtil.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/ProblemNavigationUtil.java index d92011a97..7033dd45c 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemNavigationUtil.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/ProblemNavigationUtil.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import java.util.List; import java.util.stream.Stream; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemParseHelper.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/ProblemParseHelper.java similarity index 94% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemParseHelper.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/ProblemParseHelper.java index f1535716c..02fefa78e 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemParseHelper.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/ProblemParseHelper.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import com.google.inject.Inject; import org.eclipse.emf.ecore.util.EcoreUtil; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAction.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAction.java similarity index 84% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAction.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAction.java index 4987cb892..1128b9eff 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAction.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAction.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import tools.refinery.language.model.problem.Action; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedArgument.java similarity index 90% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedArgument.java index ed749fed2..c396cab39 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedArgument.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import tools.refinery.language.model.problem.*; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertion.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAssertion.java similarity index 89% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertion.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAssertion.java index b2ef6e488..b94e164dc 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertion.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAssertion.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import tools.refinery.language.model.problem.Assertion; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAssertionArgument.java similarity index 91% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAssertionArgument.java index 50cb958d1..bdc3dd499 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAssertionArgument.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import tools.refinery.language.model.problem.AssertionArgument; import tools.refinery.language.model.problem.Node; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAtom.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAtom.java similarity index 87% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAtom.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAtom.java index c02f447bb..c88b899eb 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAtom.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAtom.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import tools.refinery.language.model.problem.Atom; @@ -11,7 +11,7 @@ public record WrappedAtom(Atom atom) { public Atom get() { return atom; } - + public WrappedArgument arg(int i) { return new WrappedArgument(atom.getArguments().get(i)); } diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedClassDeclaration.java similarity index 91% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedClassDeclaration.java index 14ac7bfcd..2f20b3bdc 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedClassDeclaration.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import tools.refinery.language.model.problem.ClassDeclaration; import tools.refinery.language.model.problem.ReferenceDeclaration; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConjunction.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedConjunction.java similarity index 88% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConjunction.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedConjunction.java index b126b1ce2..a01594da5 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConjunction.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedConjunction.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import tools.refinery.language.model.problem.Conjunction; @@ -11,7 +11,7 @@ public record WrappedConjunction(Conjunction conjunction) { public Conjunction get() { return conjunction; } - + public WrappedLiteral lit(int i) { return new WrappedLiteral(conjunction.getLiterals().get(i)); } diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConsequent.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedConsequent.java similarity index 88% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConsequent.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedConsequent.java index 8d6a92f8b..5af3f352a 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConsequent.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedConsequent.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import tools.refinery.language.model.problem.Consequent; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedEnumDeclaration.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedEnumDeclaration.java similarity index 90% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedEnumDeclaration.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedEnumDeclaration.java index 229a8c0ab..d20382d7e 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedEnumDeclaration.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedEnumDeclaration.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import tools.refinery.language.model.problem.EnumDeclaration; import tools.refinery.language.model.problem.Node; @@ -12,7 +12,7 @@ public record WrappedEnumDeclaration(EnumDeclaration enumDeclaration) { public EnumDeclaration get() { return enumDeclaration; } - + public Node literal(String name) { return ProblemNavigationUtil.named(enumDeclaration.getLiterals(), name); } diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedLiteral.java similarity index 92% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedLiteral.java index 160e5dd80..f62fb6301 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedLiteral.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import tools.refinery.language.model.problem.Atom; import tools.refinery.language.model.problem.Expr; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedParametricDefinition.java similarity index 88% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedParametricDefinition.java index d44b79edf..598ff1f46 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedParametricDefinition.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import tools.refinery.language.model.problem.Parameter; import tools.refinery.language.model.problem.ParametricDefinition; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedPredicateDefinition.java similarity index 91% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedPredicateDefinition.java index 2cf5fd891..15268d0db 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedPredicateDefinition.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import tools.refinery.language.model.problem.PredicateDefinition; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedProblem.java similarity index 98% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedProblem.java index b31eed6d3..174f66e7f 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedProblem.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import org.eclipse.emf.ecore.resource.Resource.Diagnostic; import org.eclipse.emf.ecore.util.Diagnostician; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedRuleDefinition.java similarity index 92% rename from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java rename to subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedRuleDefinition.java index 326d8ec38..e66b1030e 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedRuleDefinition.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.language.model.tests.utils; +package tools.refinery.language.tests.utils; import tools.refinery.language.model.problem.RuleDefinition; From 691c53a846dad053208044cd3f393c187a067244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20Marussy?= Date: Mon, 22 Jul 2024 20:20:28 +0200 Subject: [PATCH 4/9] test(semantics): add integration test --- .../tools/refinery/generator/sudoku.problem | 384 ++++++++++++++++++ .../abstract.problem} | 0 .../basic.problem} | 0 3 files changed, 384 insertions(+) create mode 100644 subprojects/generator/src/test/resources/tools/refinery/generator/sudoku.problem rename subprojects/generator/src/test/resources/tools/refinery/generator/{abstractTypeHierarchy.problem => typehierarchy/abstract.problem} (100%) rename subprojects/generator/src/test/resources/tools/refinery/generator/{typeHierarchy.problem => typehierarchy/basic.problem} (100%) diff --git a/subprojects/generator/src/test/resources/tools/refinery/generator/sudoku.problem b/subprojects/generator/src/test/resources/tools/refinery/generator/sudoku.problem new file mode 100644 index 000000000..fa5b7159d --- /dev/null +++ b/subprojects/generator/src/test/resources/tools/refinery/generator/sudoku.problem @@ -0,0 +1,384 @@ +% Copyright (c) 2020 Frank McSherry +% Copyright (c) 2024 The Refinery Authors +% +% SPDX-License-Identifier: MIT AND EPL-2.0 +% +% The sudoku example in this file was adapted from Frank McSherry's +% differential-dataflow tutorial, which is available at +% https://www.youtube.com/watch?v=DR5V5bNpclg and +% https://github.com/frankmcsherry/WIP/tree/master/sudoku + +class Row { + Field[9] field opposite row +} + +class Column { + Field[9] field opposite column +} + +class Block { + Field[9] field opposite block +} + +class Field { + Row[1] row opposite field + Column[1] column opposite field + Block[1] block opposite field + Number[1] number +} + +class Number. + +error multipleInRow(r, n) <-> + row(f1, r), + row(f2, r), + f1 != f2, + number(f1, n), + number(f2, n). + +propagation rule singleInRow(f, n) <-> + may number(f, n), + row(f, r), + !multipleInRow::computed(r, n) +==> + number(f, n). + +propagation rule noMoreInRow(f, n) <-> + row(f, r), + number(f2, n), + row(f2, r), + f != f2 +==> + !number(f, n). + +error multipleInColumn(c, n) <-> + column(f1, c), + column(f2, c), + f1 != f2, + number(f1, n), + number(f2, n). + +propagation rule singleInColumn(f, n) <-> + may number(f, n), + column(n, c), + !multipleInColumn::computed(c, n) +==> + number(f, n). + +propagation rule noMoreInColumn(f, n) <-> + column(f, c), + number(f2, n), + column(f2, c), + f != f2 +==> + !number(f, n). + +error multipleInBlock(b, n) <-> + block(f1, b), + block(f2, b), + f1 != f2, + number(f1, n), + number(f2, n). + +propagation rule singleInBlock(f, n) <-> + may number(f, n), + block(f, b), + !multipleInBlock::computed(b, n) +==> + number(f, n). + +propagation rule noMoreInBlock(f, n) <-> + block(f, b), + number(f2, n), + block(f2, b), + f != f2 +==> + !number(f, n). + +Number(n1). +Number(n2). +Number(n3). +Number(n4). +Number(n5). +Number(n6). +Number(n7). +Number(n8). +Number(n9). + +row(f1_1, r1). column(f1_1, c1). block(f1_1, b1_1). +row(f1_2, r1). column(f1_2, c2). block(f1_2, b1_1). +row(f1_3, r1). column(f1_3, c3). block(f1_3, b1_1). +row(f1_4, r1). column(f1_4, c4). block(f1_4, b1_2). +row(f1_5, r1). column(f1_5, c5). block(f1_5, b1_2). +row(f1_6, r1). column(f1_6, c6). block(f1_6, b1_2). +row(f1_7, r1). column(f1_7, c7). block(f1_7, b1_3). +row(f1_8, r1). column(f1_8, c8). block(f1_8, b1_3). +row(f1_9, r1). column(f1_9, c9). block(f1_9, b1_3). +row(f2_1, r2). column(f2_1, c1). block(f2_1, b1_1). +row(f2_2, r2). column(f2_2, c2). block(f2_2, b1_1). +row(f2_3, r2). column(f2_3, c3). block(f2_3, b1_1). +row(f2_4, r2). column(f2_4, c4). block(f2_4, b1_2). +row(f2_5, r2). column(f2_5, c5). block(f2_5, b1_2). +row(f2_6, r2). column(f2_6, c6). block(f2_6, b1_2). +row(f2_7, r2). column(f2_7, c7). block(f2_7, b1_3). +row(f2_8, r2). column(f2_8, c8). block(f2_8, b1_3). +row(f2_9, r2). column(f2_9, c9). block(f2_9, b1_3). +row(f3_1, r3). column(f3_1, c1). block(f3_1, b1_1). +row(f3_2, r3). column(f3_2, c2). block(f3_2, b1_1). +row(f3_3, r3). column(f3_3, c3). block(f3_3, b1_1). +row(f3_4, r3). column(f3_4, c4). block(f3_4, b1_2). +row(f3_5, r3). column(f3_5, c5). block(f3_5, b1_2). +row(f3_6, r3). column(f3_6, c6). block(f3_6, b1_2). +row(f3_7, r3). column(f3_7, c7). block(f3_7, b1_3). +row(f3_8, r3). column(f3_8, c8). block(f3_8, b1_3). +row(f3_9, r3). column(f3_9, c9). block(f3_9, b1_3). +row(f4_1, r4). column(f4_1, c1). block(f4_1, b2_1). +row(f4_2, r4). column(f4_2, c2). block(f4_2, b2_1). +row(f4_3, r4). column(f4_3, c3). block(f4_3, b2_1). +row(f4_4, r4). column(f4_4, c4). block(f4_4, b2_2). +row(f4_5, r4). column(f4_5, c5). block(f4_5, b2_2). +row(f4_6, r4). column(f4_6, c6). block(f4_6, b2_2). +row(f4_7, r4). column(f4_7, c7). block(f4_7, b2_3). +row(f4_8, r4). column(f4_8, c8). block(f4_8, b2_3). +row(f4_9, r4). column(f4_9, c9). block(f4_9, b2_3). +row(f5_1, r5). column(f5_1, c1). block(f5_1, b2_1). +row(f5_2, r5). column(f5_2, c2). block(f5_2, b2_1). +row(f5_3, r5). column(f5_3, c3). block(f5_3, b2_1). +row(f5_4, r5). column(f5_4, c4). block(f5_4, b2_2). +row(f5_5, r5). column(f5_5, c5). block(f5_5, b2_2). +row(f5_6, r5). column(f5_6, c6). block(f5_6, b2_2). +row(f5_7, r5). column(f5_7, c7). block(f5_7, b2_3). +row(f5_8, r5). column(f5_8, c8). block(f5_8, b2_3). +row(f5_9, r5). column(f5_9, c9). block(f5_9, b2_3). +row(f6_1, r6). column(f6_1, c1). block(f6_1, b2_1). +row(f6_2, r6). column(f6_2, c2). block(f6_2, b2_1). +row(f6_3, r6). column(f6_3, c3). block(f6_3, b2_1). +row(f6_4, r6). column(f6_4, c4). block(f6_4, b2_2). +row(f6_5, r6). column(f6_5, c5). block(f6_5, b2_2). +row(f6_6, r6). column(f6_6, c6). block(f6_6, b2_2). +row(f6_7, r6). column(f6_7, c7). block(f6_7, b2_3). +row(f6_8, r6). column(f6_8, c8). block(f6_8, b2_3). +row(f6_9, r6). column(f6_9, c9). block(f6_9, b2_3). +row(f7_1, r7). column(f7_1, c1). block(f7_1, b3_1). +row(f7_2, r7). column(f7_2, c2). block(f7_2, b3_1). +row(f7_3, r7). column(f7_3, c3). block(f7_3, b3_1). +row(f7_4, r7). column(f7_4, c4). block(f7_4, b3_2). +row(f7_5, r7). column(f7_5, c5). block(f7_5, b3_2). +row(f7_6, r7). column(f7_6, c6). block(f7_6, b3_2). +row(f7_7, r7). column(f7_7, c7). block(f7_7, b3_3). +row(f7_8, r7). column(f7_8, c8). block(f7_8, b3_3). +row(f7_9, r7). column(f7_9, c9). block(f7_9, b3_3). +row(f8_1, r8). column(f8_1, c1). block(f8_1, b3_1). +row(f8_2, r8). column(f8_2, c2). block(f8_2, b3_1). +row(f8_3, r8). column(f8_3, c3). block(f8_3, b3_1). +row(f8_4, r8). column(f8_4, c4). block(f8_4, b3_2). +row(f8_5, r8). column(f8_5, c5). block(f8_5, b3_2). +row(f8_6, r8). column(f8_6, c6). block(f8_6, b3_2). +row(f8_7, r8). column(f8_7, c7). block(f8_7, b3_3). +row(f8_8, r8). column(f8_8, c8). block(f8_8, b3_3). +row(f8_9, r8). column(f8_9, c9). block(f8_9, b3_3). +row(f9_1, r9). column(f9_1, c1). block(f9_1, b3_1). +row(f9_2, r9). column(f9_2, c2). block(f9_2, b3_1). +row(f9_3, r9). column(f9_3, c3). block(f9_3, b3_1). +row(f9_4, r9). column(f9_4, c4). block(f9_4, b3_2). +row(f9_5, r9). column(f9_5, c5). block(f9_5, b3_2). +row(f9_6, r9). column(f9_6, c6). block(f9_6, b3_2). +row(f9_7, r9). column(f9_7, c7). block(f9_7, b3_3). +row(f9_8, r9). column(f9_8, c8). block(f9_8, b3_3). +row(f9_9, r9). column(f9_9, c9). block(f9_9, b3_3). + +scope Field += 0, Number += 0. + +% TEST: initial grid is not filled + +pred filled() <-> number(_, _). + +% EXPECT EXACTLY: + +?filled(). + +% TEST: sudoku with single solution + +% Adapted from Frank McSherry's differential-dataflow tutorial, +% which is available at https://www.youtube.com/watch?v=DR5V5bNpclg and +% https://github.com/frankmcsherry/WIP/tree/master/sudoku +% +% 53.|.7.|... +% 6..|195|... +% .98|...|.6. +% ---+---+--- +% 8..|.6.|..3 +% 4..|8.3|..1 +% 7..|.2.|..6 +% ---+---+--- +% .6.|...|28. +% ...|419|..5 +% ...|.8.|.79 + +number(f1_1, n5). +number(f1_2, n3). +number(f1_5, n7). +number(f2_1, n6). +number(f2_4, n1). +number(f2_5, n9). +number(f2_6, n5). +number(f3_2, n9). +number(f3_3, n8). +number(f3_8, n6). +number(f4_1, n8). +number(f4_5, n6). +number(f4_9, n3). +number(f5_1, n4). +number(f5_4, n8). +number(f5_6, n3). +number(f5_9, n1). +number(f6_1, n7). +number(f6_5, n2). +number(f6_9, n6). +number(f7_2, n6). +number(f7_7, n2). +number(f7_8, n8). +number(f8_4, n4). +number(f8_5, n1). +number(f8_6, n9). +number(f8_9, n5). +number(f9_5, n8). +number(f9_8, n7). +number(f9_9, n9). + +% EXPECT: + +% 534|678|912 +% 672|195|348 +% 198|342|567 +% ---+---+--- +% 859|761|423 +% 426|853|791 +% 713|924|856 +% ---+---+--- +% 961|537|284 +% 287|419|635 +% 345|286|179 + +number(f1_1, n5). +number(f1_2, n3). +number(f1_3, n4). +number(f1_4, n6). +number(f1_5, n7). +number(f1_6, n8). +number(f1_7, n9). +number(f1_8, n1). +number(f1_9, n2). +number(f2_1, n6). +number(f2_2, n7). +number(f2_3, n2). +number(f2_4, n1). +number(f2_5, n9). +number(f2_6, n5). +number(f2_7, n3). +number(f2_8, n4). +number(f2_9, n8). +number(f3_1, n1). +number(f3_2, n9). +number(f3_3, n8). +number(f3_4, n3). +number(f3_5, n4). +number(f3_6, n2). +number(f3_7, n5). +number(f3_8, n6). +number(f3_9, n7). +number(f4_1, n8). +number(f4_2, n5). +number(f4_3, n9). +number(f4_4, n7). +number(f4_5, n6). +number(f4_6, n1). +number(f4_7, n4). +number(f4_8, n2). +number(f4_9, n3). +number(f5_1, n4). +number(f5_2, n2). +number(f5_3, n6). +number(f5_4, n8). +number(f5_5, n5). +number(f5_6, n3). +number(f5_7, n7). +number(f5_8, n9). +number(f5_9, n1). +number(f6_1, n7). +number(f6_2, n1). +number(f6_3, n3). +number(f6_4, n9). +number(f6_5, n2). +number(f6_6, n4). +number(f6_7, n8). +number(f6_8, n5). +number(f6_9, n6). +number(f7_1, n9). +number(f7_2, n6). +number(f7_3, n1). +number(f7_4, n5). +number(f7_5, n3). +number(f7_6, n7). +number(f7_7, n2). +number(f7_8, n8). +number(f7_9, n4). +number(f8_1, n2). +number(f8_2, n8). +number(f8_3, n7). +number(f8_4, n4). +number(f8_5, n1). +number(f8_6, n9). +number(f8_7, n6). +number(f8_8, n3). +number(f8_9, n5). +number(f9_1, n3). +number(f9_2, n4). +number(f9_3, n5). +number(f9_4, n2). +number(f9_5, n8). +number(f9_6, n6). +number(f9_7, n1). +number(f9_8, n7). +number(f9_9, n9). + +% TEST: sudoku with multiple solutions + +pred notFilled(Field f) <-> !number(f, _). + +pred allFilled() <-> !notFilled(_). + +number(f1_1, n5). +number(f1_2, n3). +number(f1_5, n7). +number(f2_1, n6). +number(f2_4, n1). +number(f2_5, n9). +number(f2_6, n5). +number(f3_2, n9). +number(f3_3, n8). +number(f3_8, n6). +number(f4_1, n8). +number(f4_5, n6). +number(f4_9, n3). +number(f5_1, n4). +number(f5_4, n8). +number(f5_6, n3). +number(f5_9, n1). +number(f6_1, n7). +number(f6_5, n2). +number(f6_9, n6). +number(f7_2, n6). +% number(f7_7, n2). +number(f7_8, n8). +number(f8_4, n4). +number(f8_5, n1). +number(f8_6, n9). +number(f8_9, n5). +number(f9_5, n8). +number(f9_8, n7). +number(f9_9, n9). + +% EXPECT EXACTLY: + +?allFilled(). diff --git a/subprojects/generator/src/test/resources/tools/refinery/generator/abstractTypeHierarchy.problem b/subprojects/generator/src/test/resources/tools/refinery/generator/typehierarchy/abstract.problem similarity index 100% rename from subprojects/generator/src/test/resources/tools/refinery/generator/abstractTypeHierarchy.problem rename to subprojects/generator/src/test/resources/tools/refinery/generator/typehierarchy/abstract.problem diff --git a/subprojects/generator/src/test/resources/tools/refinery/generator/typeHierarchy.problem b/subprojects/generator/src/test/resources/tools/refinery/generator/typehierarchy/basic.problem similarity index 100% rename from subprojects/generator/src/test/resources/tools/refinery/generator/typeHierarchy.problem rename to subprojects/generator/src/test/resources/tools/refinery/generator/typehierarchy/basic.problem From b7ed339e5c67ff38635a430f8faa1578eb690b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20Marussy?= Date: Fri, 26 Jul 2024 20:26:09 +0200 Subject: [PATCH 5/9] refactor(docs): use a single docs plugin instance Prepare for versioning documentations. --- subprojects/docs/docusaurus.config.ts | 16 +++------------- subprojects/docs/sidebars.ts | 16 ++++++++++++++++ .../{ => docs}/develop/contributing/commands.md | 4 ++-- .../{ => docs}/develop/contributing/ide-setup.md | 0 .../src/{ => docs}/develop/contributing/index.md | 0 subprojects/docs/src/{ => docs}/develop/java.md | 2 +- .../docs/src/{ => docs}/develop/javadoc.md | 2 +- .../docs/src/{ => docs}/learn/docker/cli.md | 8 ++++---- .../docs/src/{ => docs}/learn/docker/index.md | 1 + subprojects/docs/src/{ => docs}/learn/index.md | 0 .../src/{ => docs}/learn/language/_category_.yml | 2 +- .../language/classes/ContainmentInstance.svg | 0 .../classes/ContainmentInstance.svg.license | 0 .../learn/language/classes/InvalidInstance.svg | 0 .../language/classes/InvalidInstance.svg.license | 0 .../classes/MultiplicityConstraintsInstance.svg | 0 .../MultiplicityConstraintsInstance.svg.license | 0 .../learn/language/classes/NewObjectsSimple.svg | 0 .../classes/NewObjectsSimple.svg.license | 0 .../classes/NewObjectsWithInheritance.svg | 0 .../NewObjectsWithInheritance.svg.license | 0 .../classes/ReferencesOppositeInstance.svg | 0 .../ReferencesOppositeInstance.svg.license | 0 .../language/classes/ReferencesOppositeSelf.svg | 0 .../classes/ReferencesOppositeSelf.svg.license | 0 .../learn/language/classes/ReferencesSimple.svg | 0 .../classes/ReferencesSimple.svg.license | 0 .../{ => docs}/learn/language/classes/index.md | 0 .../learn/language/logic/AssertionsError.svg | 0 .../language/logic/AssertionsError.svg.license | 0 .../learn/language/logic/AssertionsExample.svg | 0 .../language/logic/AssertionsExample.svg.license | 0 .../learn/language/logic/DefaultAssertions.svg | 0 .../language/logic/DefaultAssertions.svg.license | 0 .../learn/language/logic/MultiObjects.svg | 0 .../language/logic/MultiObjects.svg.license | 0 .../learn/language/logic/ObjectScopes.svg | 0 .../language/logic/ObjectScopes.svg.license | 0 .../language/logic/StrongerObjectScopes.svg | 0 .../logic/StrongerObjectScopes.svg.license | 0 .../src/{ => docs}/learn/language/logic/index.md | 0 .../learn/language/predicates/DerivedFeature.svg | 0 .../predicates/DerivedFeature.svg.license | 0 .../learn/language/predicates/index.md | 0 .../{ => docs}/learn/tutorials/_category_.yml | 2 +- .../learn/tutorials/file-system/fig1.svg | 0 .../learn/tutorials/file-system/fig1.svg.license | 0 .../learn/tutorials/file-system/fig2.svg | 0 .../learn/tutorials/file-system/fig2.svg.license | 0 .../learn/tutorials/file-system/fig3.svg | 0 .../learn/tutorials/file-system/fig3.svg.license | 0 .../learn/tutorials/file-system/fig4.svg | 0 .../learn/tutorials/file-system/fig4.svg.license | 0 .../learn/tutorials/file-system/index.md | 0 54 files changed, 30 insertions(+), 23 deletions(-) create mode 100644 subprojects/docs/sidebars.ts rename subprojects/docs/src/{ => docs}/develop/contributing/commands.md (94%) rename subprojects/docs/src/{ => docs}/develop/contributing/ide-setup.md (100%) rename subprojects/docs/src/{ => docs}/develop/contributing/index.md (100%) rename subprojects/docs/src/{ => docs}/develop/java.md (99%) rename subprojects/docs/src/{ => docs}/develop/javadoc.md (99%) rename subprojects/docs/src/{ => docs}/learn/docker/cli.md (92%) rename subprojects/docs/src/{ => docs}/learn/docker/index.md (99%) rename subprojects/docs/src/{ => docs}/learn/index.md (100%) rename subprojects/docs/src/{ => docs}/learn/language/_category_.yml (90%) rename subprojects/docs/src/{ => docs}/learn/language/classes/ContainmentInstance.svg (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/ContainmentInstance.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/InvalidInstance.svg (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/InvalidInstance.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/MultiplicityConstraintsInstance.svg (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/MultiplicityConstraintsInstance.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/NewObjectsSimple.svg (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/NewObjectsSimple.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/NewObjectsWithInheritance.svg (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/NewObjectsWithInheritance.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/ReferencesOppositeInstance.svg (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/ReferencesOppositeInstance.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/ReferencesOppositeSelf.svg (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/ReferencesOppositeSelf.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/ReferencesSimple.svg (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/ReferencesSimple.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/language/classes/index.md (100%) rename subprojects/docs/src/{ => docs}/learn/language/logic/AssertionsError.svg (100%) rename subprojects/docs/src/{ => docs}/learn/language/logic/AssertionsError.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/language/logic/AssertionsExample.svg (100%) rename subprojects/docs/src/{ => docs}/learn/language/logic/AssertionsExample.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/language/logic/DefaultAssertions.svg (100%) rename subprojects/docs/src/{ => docs}/learn/language/logic/DefaultAssertions.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/language/logic/MultiObjects.svg (100%) rename subprojects/docs/src/{ => docs}/learn/language/logic/MultiObjects.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/language/logic/ObjectScopes.svg (100%) rename subprojects/docs/src/{ => docs}/learn/language/logic/ObjectScopes.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/language/logic/StrongerObjectScopes.svg (100%) rename subprojects/docs/src/{ => docs}/learn/language/logic/StrongerObjectScopes.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/language/logic/index.md (100%) rename subprojects/docs/src/{ => docs}/learn/language/predicates/DerivedFeature.svg (100%) rename subprojects/docs/src/{ => docs}/learn/language/predicates/DerivedFeature.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/language/predicates/index.md (100%) rename subprojects/docs/src/{ => docs}/learn/tutorials/_category_.yml (90%) rename subprojects/docs/src/{ => docs}/learn/tutorials/file-system/fig1.svg (100%) rename subprojects/docs/src/{ => docs}/learn/tutorials/file-system/fig1.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/tutorials/file-system/fig2.svg (100%) rename subprojects/docs/src/{ => docs}/learn/tutorials/file-system/fig2.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/tutorials/file-system/fig3.svg (100%) rename subprojects/docs/src/{ => docs}/learn/tutorials/file-system/fig3.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/tutorials/file-system/fig4.svg (100%) rename subprojects/docs/src/{ => docs}/learn/tutorials/file-system/fig4.svg.license (100%) rename subprojects/docs/src/{ => docs}/learn/tutorials/file-system/index.md (100%) diff --git a/subprojects/docs/docusaurus.config.ts b/subprojects/docs/docusaurus.config.ts index 1edf277d0..e8201cb29 100644 --- a/subprojects/docs/docusaurus.config.ts +++ b/subprojects/docs/docusaurus.config.ts @@ -35,7 +35,6 @@ const markdownOptions: Partial = { const docsOptions = { ...markdownOptions, - sidebarPath: undefined, editUrl: 'https://github.com/graphs4value/refinery/edit/main/subprojects/docs', } satisfies DocsOptions; @@ -52,18 +51,9 @@ export default { [ '@docusaurus/plugin-content-docs', { - id: 'learn', - path: 'src/learn', - routeBasePath: '/learn', - ...docsOptions, - } satisfies DocsOptions, - ], - [ - '@docusaurus/plugin-content-docs', - { - id: 'develop', - path: 'src/develop', - routeBasePath: '/develop', + path: 'src/docs', + routeBasePath: '/', + sidebarPath: './sidebars.ts', ...docsOptions, } satisfies DocsOptions, ], diff --git a/subprojects/docs/sidebars.ts b/subprojects/docs/sidebars.ts new file mode 100644 index 000000000..ddd838b3a --- /dev/null +++ b/subprojects/docs/sidebars.ts @@ -0,0 +1,16 @@ +import { SidebarsConfig } from '@docusaurus/plugin-content-docs'; + +export default { + learnSidebar: [ + { + type: 'autogenerated', + dirName: 'learn', + }, + ], + developSidebar: [ + { + type: 'autogenerated', + dirName: 'develop', + }, + ], +} satisfies SidebarsConfig; diff --git a/subprojects/docs/src/develop/contributing/commands.md b/subprojects/docs/src/docs/develop/contributing/commands.md similarity index 94% rename from subprojects/docs/src/develop/contributing/commands.md rename to subprojects/docs/src/docs/develop/contributing/commands.md index 8024a0765..06b82873d 100644 --- a/subprojects/docs/src/develop/contributing/commands.md +++ b/subprojects/docs/src/docs/develop/contributing/commands.md @@ -49,7 +49,7 @@ This task is ideal for running the Refinery backend if you don't intend to work The Refinery frontend TypeScript projects is automatically built before the server starts. The server will use the latest build output of the frontend as static assets. -The behavior of this task is influenced by the same [environmental variables](/learn/docker#environmental-variables) as the Refinery [Docker container](/learn/docker). +The behavior of this task is influenced by the same [environmental variables](../../../learn/docker#environmental-variables) as the Refinery [Docker container](../../../learn/docker). However, the default value of `REFINERY_LISTEN_PORT` is `1312`. ### `serveBackend` @@ -64,7 +64,7 @@ This task is ideal for running the Refinery backend if you're working on the fro No static assets will be build. You'll need to use [`yarnw frontend dev`](#frontend-dev) -Like [`./gradlew serve`](#serve), the behavior of this task is influenced by the same [environmental variables](/learn/docker#environmental-variables) as the Refinery [Docker container](/learn/docker). +Like [`./gradlew serve`](#serve), the behavior of this task is influenced by the same [environmental variables](../../../learn/docker#environmental-variables) as the Refinery [Docker container](../../../learn/docker). However, the default value of `REFINERY_LISTEN_PORT` is `1312`. ## Yarn commands diff --git a/subprojects/docs/src/develop/contributing/ide-setup.md b/subprojects/docs/src/docs/develop/contributing/ide-setup.md similarity index 100% rename from subprojects/docs/src/develop/contributing/ide-setup.md rename to subprojects/docs/src/docs/develop/contributing/ide-setup.md diff --git a/subprojects/docs/src/develop/contributing/index.md b/subprojects/docs/src/docs/develop/contributing/index.md similarity index 100% rename from subprojects/docs/src/develop/contributing/index.md rename to subprojects/docs/src/docs/develop/contributing/index.md diff --git a/subprojects/docs/src/develop/java.md b/subprojects/docs/src/docs/develop/java.md similarity index 99% rename from subprojects/docs/src/develop/java.md rename to subprojects/docs/src/docs/develop/java.md index 2239c678b..1f1fd5da4 100644 --- a/subprojects/docs/src/develop/java.md +++ b/subprojects/docs/src/docs/develop/java.md @@ -13,7 +13,7 @@ See the [contributor's guide](../contributing) for information on building and m :::note Refinery can run as a cloud-based [_Graph Solver as a Service_](https://refinery.services/) without local installation. -You can also run a compiled version as a [Docker container](/learn/docker). +You can also run a compiled version as a [Docker container](../../learn/docker). ::: diff --git a/subprojects/docs/src/develop/javadoc.md b/subprojects/docs/src/docs/develop/javadoc.md similarity index 99% rename from subprojects/docs/src/develop/javadoc.md rename to subprojects/docs/src/docs/develop/javadoc.md index 4e2e7ba7f..97a44d36b 100644 --- a/subprojects/docs/src/develop/javadoc.md +++ b/subprojects/docs/src/docs/develop/javadoc.md @@ -2,7 +2,7 @@ SPDX-FileCopyrightText: 2024 The Refinery Authors SPDX-License-Identifier: EPL-2.0 description: API documentation for Refinery components automatically generated by Javadoc -sidebar_position: 999 +sidebar_position: 998 --- # Javadoc diff --git a/subprojects/docs/src/learn/docker/cli.md b/subprojects/docs/src/docs/learn/docker/cli.md similarity index 92% rename from subprojects/docs/src/learn/docker/cli.md rename to subprojects/docs/src/docs/learn/docker/cli.md index bd862f719..f9e8677cb 100644 --- a/subprojects/docs/src/learn/docker/cli.md +++ b/subprojects/docs/src/docs/learn/docker/cli.md @@ -66,7 +66,7 @@ Models generated with different values of `-random-seed` are highly likely (but ### `-scope`, `-s` {#generate-scope} -Add [scope constraints](/learn/language/logic#type-scopes) to the input problem. +Add [scope constraints](../../language/logic#type-scopes) to the input problem. This option is especially useful if you want to generate models of multiple sizes from the same partial model. @@ -83,7 +83,7 @@ scope File = 20..25. ``` to `input.problem`. -The syntax of the argument is equivalent to the [`scope`](/learn/language/logic#type-scopes) declaration, but you be careful with the handling of spaces in your shell. +The syntax of the argument is equivalent to the [`scope`](../../language/logic#type-scopes) declaration, but you be careful with the handling of spaces in your shell. Any number of `-s` arguments are supported. For example, the following argument lists are equivalent: ```shell @@ -102,9 +102,9 @@ The `*` opeator also has to be quoted to avoid shell expansion: ### `-scope-override`, `-S` {#generate-scope-override} -Override [scope constraints](/learn/language/logic#type-scopes) to the input problem. +Override [scope constraints](../../language/logic#type-scopes) to the input problem. -This argument is similar to [`-scope`](#generate-scope), but has higher precedence than the [`scope`](/learn/language/logic#type-scopes) declarations already present in the input file. +This argument is similar to [`-scope`](#generate-scope), but has higher precedence than the [`scope`](../../language/logic#type-scopes) declarations already present in the input file. However, you can't override `scope` declarations in modules imported in the input file using the `import` statement. For example, if we have diff --git a/subprojects/docs/src/learn/docker/index.md b/subprojects/docs/src/docs/learn/docker/index.md similarity index 99% rename from subprojects/docs/src/learn/docker/index.md rename to subprojects/docs/src/docs/learn/docker/index.md index e7ab41eb1..af090763f 100644 --- a/subprojects/docs/src/learn/docker/index.md +++ b/subprojects/docs/src/docs/learn/docker/index.md @@ -1,6 +1,7 @@ --- SPDX-FileCopyrightText: 2024 The Refinery Authors SPDX-License-Identifier: EPL-2.0 +autogenerated_sidebar_hidden: true sidebar_position: 100 sidebar_label: Docker --- diff --git a/subprojects/docs/src/learn/index.md b/subprojects/docs/src/docs/learn/index.md similarity index 100% rename from subprojects/docs/src/learn/index.md rename to subprojects/docs/src/docs/learn/index.md diff --git a/subprojects/docs/src/learn/language/_category_.yml b/subprojects/docs/src/docs/learn/language/_category_.yml similarity index 90% rename from subprojects/docs/src/learn/language/_category_.yml rename to subprojects/docs/src/docs/learn/language/_category_.yml index f5a6f8966..a261ebf65 100644 --- a/subprojects/docs/src/learn/language/_category_.yml +++ b/subprojects/docs/src/docs/learn/language/_category_.yml @@ -6,5 +6,5 @@ position: 2 label: Language reference link: type: generated-index - slug: /language + slug: /learn/language description: Learn more about the Refinery partial modeling language! diff --git a/subprojects/docs/src/learn/language/classes/ContainmentInstance.svg b/subprojects/docs/src/docs/learn/language/classes/ContainmentInstance.svg similarity index 100% rename from subprojects/docs/src/learn/language/classes/ContainmentInstance.svg rename to subprojects/docs/src/docs/learn/language/classes/ContainmentInstance.svg diff --git a/subprojects/docs/src/learn/language/classes/ContainmentInstance.svg.license b/subprojects/docs/src/docs/learn/language/classes/ContainmentInstance.svg.license similarity index 100% rename from subprojects/docs/src/learn/language/classes/ContainmentInstance.svg.license rename to subprojects/docs/src/docs/learn/language/classes/ContainmentInstance.svg.license diff --git a/subprojects/docs/src/learn/language/classes/InvalidInstance.svg b/subprojects/docs/src/docs/learn/language/classes/InvalidInstance.svg similarity index 100% rename from subprojects/docs/src/learn/language/classes/InvalidInstance.svg rename to subprojects/docs/src/docs/learn/language/classes/InvalidInstance.svg diff --git a/subprojects/docs/src/learn/language/classes/InvalidInstance.svg.license b/subprojects/docs/src/docs/learn/language/classes/InvalidInstance.svg.license similarity index 100% rename from subprojects/docs/src/learn/language/classes/InvalidInstance.svg.license rename to subprojects/docs/src/docs/learn/language/classes/InvalidInstance.svg.license diff --git a/subprojects/docs/src/learn/language/classes/MultiplicityConstraintsInstance.svg b/subprojects/docs/src/docs/learn/language/classes/MultiplicityConstraintsInstance.svg similarity index 100% rename from subprojects/docs/src/learn/language/classes/MultiplicityConstraintsInstance.svg rename to subprojects/docs/src/docs/learn/language/classes/MultiplicityConstraintsInstance.svg diff --git a/subprojects/docs/src/learn/language/classes/MultiplicityConstraintsInstance.svg.license b/subprojects/docs/src/docs/learn/language/classes/MultiplicityConstraintsInstance.svg.license similarity index 100% rename from subprojects/docs/src/learn/language/classes/MultiplicityConstraintsInstance.svg.license rename to subprojects/docs/src/docs/learn/language/classes/MultiplicityConstraintsInstance.svg.license diff --git a/subprojects/docs/src/learn/language/classes/NewObjectsSimple.svg b/subprojects/docs/src/docs/learn/language/classes/NewObjectsSimple.svg similarity index 100% rename from subprojects/docs/src/learn/language/classes/NewObjectsSimple.svg rename to subprojects/docs/src/docs/learn/language/classes/NewObjectsSimple.svg diff --git a/subprojects/docs/src/learn/language/classes/NewObjectsSimple.svg.license b/subprojects/docs/src/docs/learn/language/classes/NewObjectsSimple.svg.license similarity index 100% rename from subprojects/docs/src/learn/language/classes/NewObjectsSimple.svg.license rename to subprojects/docs/src/docs/learn/language/classes/NewObjectsSimple.svg.license diff --git a/subprojects/docs/src/learn/language/classes/NewObjectsWithInheritance.svg b/subprojects/docs/src/docs/learn/language/classes/NewObjectsWithInheritance.svg similarity index 100% rename from subprojects/docs/src/learn/language/classes/NewObjectsWithInheritance.svg rename to subprojects/docs/src/docs/learn/language/classes/NewObjectsWithInheritance.svg diff --git a/subprojects/docs/src/learn/language/classes/NewObjectsWithInheritance.svg.license b/subprojects/docs/src/docs/learn/language/classes/NewObjectsWithInheritance.svg.license similarity index 100% rename from subprojects/docs/src/learn/language/classes/NewObjectsWithInheritance.svg.license rename to subprojects/docs/src/docs/learn/language/classes/NewObjectsWithInheritance.svg.license diff --git a/subprojects/docs/src/learn/language/classes/ReferencesOppositeInstance.svg b/subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeInstance.svg similarity index 100% rename from subprojects/docs/src/learn/language/classes/ReferencesOppositeInstance.svg rename to subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeInstance.svg diff --git a/subprojects/docs/src/learn/language/classes/ReferencesOppositeInstance.svg.license b/subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeInstance.svg.license similarity index 100% rename from subprojects/docs/src/learn/language/classes/ReferencesOppositeInstance.svg.license rename to subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeInstance.svg.license diff --git a/subprojects/docs/src/learn/language/classes/ReferencesOppositeSelf.svg b/subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeSelf.svg similarity index 100% rename from subprojects/docs/src/learn/language/classes/ReferencesOppositeSelf.svg rename to subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeSelf.svg diff --git a/subprojects/docs/src/learn/language/classes/ReferencesOppositeSelf.svg.license b/subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeSelf.svg.license similarity index 100% rename from subprojects/docs/src/learn/language/classes/ReferencesOppositeSelf.svg.license rename to subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeSelf.svg.license diff --git a/subprojects/docs/src/learn/language/classes/ReferencesSimple.svg b/subprojects/docs/src/docs/learn/language/classes/ReferencesSimple.svg similarity index 100% rename from subprojects/docs/src/learn/language/classes/ReferencesSimple.svg rename to subprojects/docs/src/docs/learn/language/classes/ReferencesSimple.svg diff --git a/subprojects/docs/src/learn/language/classes/ReferencesSimple.svg.license b/subprojects/docs/src/docs/learn/language/classes/ReferencesSimple.svg.license similarity index 100% rename from subprojects/docs/src/learn/language/classes/ReferencesSimple.svg.license rename to subprojects/docs/src/docs/learn/language/classes/ReferencesSimple.svg.license diff --git a/subprojects/docs/src/learn/language/classes/index.md b/subprojects/docs/src/docs/learn/language/classes/index.md similarity index 100% rename from subprojects/docs/src/learn/language/classes/index.md rename to subprojects/docs/src/docs/learn/language/classes/index.md diff --git a/subprojects/docs/src/learn/language/logic/AssertionsError.svg b/subprojects/docs/src/docs/learn/language/logic/AssertionsError.svg similarity index 100% rename from subprojects/docs/src/learn/language/logic/AssertionsError.svg rename to subprojects/docs/src/docs/learn/language/logic/AssertionsError.svg diff --git a/subprojects/docs/src/learn/language/logic/AssertionsError.svg.license b/subprojects/docs/src/docs/learn/language/logic/AssertionsError.svg.license similarity index 100% rename from subprojects/docs/src/learn/language/logic/AssertionsError.svg.license rename to subprojects/docs/src/docs/learn/language/logic/AssertionsError.svg.license diff --git a/subprojects/docs/src/learn/language/logic/AssertionsExample.svg b/subprojects/docs/src/docs/learn/language/logic/AssertionsExample.svg similarity index 100% rename from subprojects/docs/src/learn/language/logic/AssertionsExample.svg rename to subprojects/docs/src/docs/learn/language/logic/AssertionsExample.svg diff --git a/subprojects/docs/src/learn/language/logic/AssertionsExample.svg.license b/subprojects/docs/src/docs/learn/language/logic/AssertionsExample.svg.license similarity index 100% rename from subprojects/docs/src/learn/language/logic/AssertionsExample.svg.license rename to subprojects/docs/src/docs/learn/language/logic/AssertionsExample.svg.license diff --git a/subprojects/docs/src/learn/language/logic/DefaultAssertions.svg b/subprojects/docs/src/docs/learn/language/logic/DefaultAssertions.svg similarity index 100% rename from subprojects/docs/src/learn/language/logic/DefaultAssertions.svg rename to subprojects/docs/src/docs/learn/language/logic/DefaultAssertions.svg diff --git a/subprojects/docs/src/learn/language/logic/DefaultAssertions.svg.license b/subprojects/docs/src/docs/learn/language/logic/DefaultAssertions.svg.license similarity index 100% rename from subprojects/docs/src/learn/language/logic/DefaultAssertions.svg.license rename to subprojects/docs/src/docs/learn/language/logic/DefaultAssertions.svg.license diff --git a/subprojects/docs/src/learn/language/logic/MultiObjects.svg b/subprojects/docs/src/docs/learn/language/logic/MultiObjects.svg similarity index 100% rename from subprojects/docs/src/learn/language/logic/MultiObjects.svg rename to subprojects/docs/src/docs/learn/language/logic/MultiObjects.svg diff --git a/subprojects/docs/src/learn/language/logic/MultiObjects.svg.license b/subprojects/docs/src/docs/learn/language/logic/MultiObjects.svg.license similarity index 100% rename from subprojects/docs/src/learn/language/logic/MultiObjects.svg.license rename to subprojects/docs/src/docs/learn/language/logic/MultiObjects.svg.license diff --git a/subprojects/docs/src/learn/language/logic/ObjectScopes.svg b/subprojects/docs/src/docs/learn/language/logic/ObjectScopes.svg similarity index 100% rename from subprojects/docs/src/learn/language/logic/ObjectScopes.svg rename to subprojects/docs/src/docs/learn/language/logic/ObjectScopes.svg diff --git a/subprojects/docs/src/learn/language/logic/ObjectScopes.svg.license b/subprojects/docs/src/docs/learn/language/logic/ObjectScopes.svg.license similarity index 100% rename from subprojects/docs/src/learn/language/logic/ObjectScopes.svg.license rename to subprojects/docs/src/docs/learn/language/logic/ObjectScopes.svg.license diff --git a/subprojects/docs/src/learn/language/logic/StrongerObjectScopes.svg b/subprojects/docs/src/docs/learn/language/logic/StrongerObjectScopes.svg similarity index 100% rename from subprojects/docs/src/learn/language/logic/StrongerObjectScopes.svg rename to subprojects/docs/src/docs/learn/language/logic/StrongerObjectScopes.svg diff --git a/subprojects/docs/src/learn/language/logic/StrongerObjectScopes.svg.license b/subprojects/docs/src/docs/learn/language/logic/StrongerObjectScopes.svg.license similarity index 100% rename from subprojects/docs/src/learn/language/logic/StrongerObjectScopes.svg.license rename to subprojects/docs/src/docs/learn/language/logic/StrongerObjectScopes.svg.license diff --git a/subprojects/docs/src/learn/language/logic/index.md b/subprojects/docs/src/docs/learn/language/logic/index.md similarity index 100% rename from subprojects/docs/src/learn/language/logic/index.md rename to subprojects/docs/src/docs/learn/language/logic/index.md diff --git a/subprojects/docs/src/learn/language/predicates/DerivedFeature.svg b/subprojects/docs/src/docs/learn/language/predicates/DerivedFeature.svg similarity index 100% rename from subprojects/docs/src/learn/language/predicates/DerivedFeature.svg rename to subprojects/docs/src/docs/learn/language/predicates/DerivedFeature.svg diff --git a/subprojects/docs/src/learn/language/predicates/DerivedFeature.svg.license b/subprojects/docs/src/docs/learn/language/predicates/DerivedFeature.svg.license similarity index 100% rename from subprojects/docs/src/learn/language/predicates/DerivedFeature.svg.license rename to subprojects/docs/src/docs/learn/language/predicates/DerivedFeature.svg.license diff --git a/subprojects/docs/src/learn/language/predicates/index.md b/subprojects/docs/src/docs/learn/language/predicates/index.md similarity index 100% rename from subprojects/docs/src/learn/language/predicates/index.md rename to subprojects/docs/src/docs/learn/language/predicates/index.md diff --git a/subprojects/docs/src/learn/tutorials/_category_.yml b/subprojects/docs/src/docs/learn/tutorials/_category_.yml similarity index 90% rename from subprojects/docs/src/learn/tutorials/_category_.yml rename to subprojects/docs/src/docs/learn/tutorials/_category_.yml index adf8293fa..fd563704e 100644 --- a/subprojects/docs/src/learn/tutorials/_category_.yml +++ b/subprojects/docs/src/docs/learn/tutorials/_category_.yml @@ -6,6 +6,6 @@ position: 1 label: Tutorials link: type: generated-index - slug: /tutorials + slug: /learn/tutorials title: Tutorial overview description: Try Refinery in practical partial modeling challenges! diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig1.svg b/subprojects/docs/src/docs/learn/tutorials/file-system/fig1.svg similarity index 100% rename from subprojects/docs/src/learn/tutorials/file-system/fig1.svg rename to subprojects/docs/src/docs/learn/tutorials/file-system/fig1.svg diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig1.svg.license b/subprojects/docs/src/docs/learn/tutorials/file-system/fig1.svg.license similarity index 100% rename from subprojects/docs/src/learn/tutorials/file-system/fig1.svg.license rename to subprojects/docs/src/docs/learn/tutorials/file-system/fig1.svg.license diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig2.svg b/subprojects/docs/src/docs/learn/tutorials/file-system/fig2.svg similarity index 100% rename from subprojects/docs/src/learn/tutorials/file-system/fig2.svg rename to subprojects/docs/src/docs/learn/tutorials/file-system/fig2.svg diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig2.svg.license b/subprojects/docs/src/docs/learn/tutorials/file-system/fig2.svg.license similarity index 100% rename from subprojects/docs/src/learn/tutorials/file-system/fig2.svg.license rename to subprojects/docs/src/docs/learn/tutorials/file-system/fig2.svg.license diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig3.svg b/subprojects/docs/src/docs/learn/tutorials/file-system/fig3.svg similarity index 100% rename from subprojects/docs/src/learn/tutorials/file-system/fig3.svg rename to subprojects/docs/src/docs/learn/tutorials/file-system/fig3.svg diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig3.svg.license b/subprojects/docs/src/docs/learn/tutorials/file-system/fig3.svg.license similarity index 100% rename from subprojects/docs/src/learn/tutorials/file-system/fig3.svg.license rename to subprojects/docs/src/docs/learn/tutorials/file-system/fig3.svg.license diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig4.svg b/subprojects/docs/src/docs/learn/tutorials/file-system/fig4.svg similarity index 100% rename from subprojects/docs/src/learn/tutorials/file-system/fig4.svg rename to subprojects/docs/src/docs/learn/tutorials/file-system/fig4.svg diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig4.svg.license b/subprojects/docs/src/docs/learn/tutorials/file-system/fig4.svg.license similarity index 100% rename from subprojects/docs/src/learn/tutorials/file-system/fig4.svg.license rename to subprojects/docs/src/docs/learn/tutorials/file-system/fig4.svg.license diff --git a/subprojects/docs/src/learn/tutorials/file-system/index.md b/subprojects/docs/src/docs/learn/tutorials/file-system/index.md similarity index 100% rename from subprojects/docs/src/learn/tutorials/file-system/index.md rename to subprojects/docs/src/docs/learn/tutorials/file-system/index.md From 13503690f5539fd4f103b02744808809e6bb041f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20Marussy?= Date: Fri, 26 Jul 2024 21:57:08 +0200 Subject: [PATCH 6/9] docs: enable documentation versioning --- subprojects/docs/build.gradle.kts | 45 ++- subprojects/docs/docusaurus.config.ts | 41 +- subprojects/docs/src/css/custom.css | 2 +- .../src/docs/develop/contributing/commands.md | 4 +- subprojects/docs/src/docs/develop/java.md | 55 +-- subprojects/docs/src/docs/learn/docker/cli.md | 25 +- .../docs/src/docs/learn/docker/index.md | 17 +- .../src/plugins/remarkReplaceVariables.ts | 12 +- .../develop/contributing/commands.md | 158 ++++++++ .../develop/contributing/ide-setup.md | 96 +++++ .../develop/contributing/index.md | 59 +++ .../version-0.1.0/develop/java.md | 351 ++++++++++++++++++ .../version-0.1.0/develop/javadoc.md | 41 ++ .../version-0.1.0/learn/docker/cli.md | 145 ++++++++ .../version-0.1.0/learn/docker/index.md | 174 +++++++++ .../version-0.1.0/learn/index.md | 11 + .../learn/language/_category_.yml | 10 + .../language/classes/ContainmentInstance.svg | 227 +++++++++++ .../classes/ContainmentInstance.svg.license | 3 + .../language/classes/InvalidInstance.svg | 20 + .../classes/InvalidInstance.svg.license | 3 + .../MultiplicityConstraintsInstance.svg | 229 ++++++++++++ ...ultiplicityConstraintsInstance.svg.license | 3 + .../language/classes/NewObjectsSimple.svg | 29 ++ .../classes/NewObjectsSimple.svg.license | 3 + .../classes/NewObjectsWithInheritance.svg | 38 ++ .../NewObjectsWithInheritance.svg.license | 3 + .../classes/ReferencesOppositeInstance.svg | 69 ++++ .../ReferencesOppositeInstance.svg.license | 3 + .../classes/ReferencesOppositeSelf.svg | 24 ++ .../ReferencesOppositeSelf.svg.license | 3 + .../language/classes/ReferencesSimple.svg | 43 +++ .../classes/ReferencesSimple.svg.license | 3 + .../learn/language/classes/index.md | 213 +++++++++++ .../learn/language/logic/AssertionsError.svg | 20 + .../logic/AssertionsError.svg.license | 3 + .../language/logic/AssertionsExample.svg | 99 +++++ .../logic/AssertionsExample.svg.license | 3 + .../language/logic/DefaultAssertions.svg | 129 +++++++ .../logic/DefaultAssertions.svg.license | 3 + .../learn/language/logic/MultiObjects.svg | 81 ++++ .../language/logic/MultiObjects.svg.license | 3 + .../learn/language/logic/ObjectScopes.svg | 58 +++ .../language/logic/ObjectScopes.svg.license | 3 + .../language/logic/StrongerObjectScopes.svg | 58 +++ .../logic/StrongerObjectScopes.svg.license | 3 + .../learn/language/logic/index.md | 256 +++++++++++++ .../language/predicates/DerivedFeature.svg | 76 ++++ .../predicates/DerivedFeature.svg.license | 3 + .../learn/language/predicates/index.md | 284 ++++++++++++++ .../learn/tutorials/_category_.yml | 11 + .../learn/tutorials/file-system/fig1.svg | 72 ++++ .../tutorials/file-system/fig1.svg.license | 3 + .../learn/tutorials/file-system/fig2.svg | 145 ++++++++ .../tutorials/file-system/fig2.svg.license | 3 + .../learn/tutorials/file-system/fig3.svg | 124 +++++++ .../tutorials/file-system/fig3.svg.license | 3 + .../learn/tutorials/file-system/fig4.svg | 131 +++++++ .../tutorials/file-system/fig4.svg.license | 3 + .../learn/tutorials/file-system/index.md | 209 +++++++++++ .../version-0.1.0-sidebars.json | 14 + subprojects/docs/versions.json | 3 + 62 files changed, 3845 insertions(+), 120 deletions(-) create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/commands.md create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/ide-setup.md create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/index.md create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/develop/java.md create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/develop/javadoc.md create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/docker/cli.md create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/docker/index.md create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/index.md create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/_category_.yml create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/index.md create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/index.md create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/index.md create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/_category_.yml create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig1.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig1.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig2.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig2.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig3.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig3.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig4.svg create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig4.svg.license create mode 100644 subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/index.md create mode 100644 subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json create mode 100644 subprojects/docs/versions.json diff --git a/subprojects/docs/build.gradle.kts b/subprojects/docs/build.gradle.kts index 092634e99..fcd6a6518 100644 --- a/subprojects/docs/build.gradle.kts +++ b/subprojects/docs/build.gradle.kts @@ -22,22 +22,37 @@ val javadocs: Configuration by configurations.creating { isCanBeResolved = true } +val releasedJavadocs: Configuration by configurations.creating { + isCanBeConsumed = false + isCanBeResolved = true +} + +val interpreterGroup = property("tools.refinery.interpreter.group").toString() +val releasedVersion = property("tools.refinery.release").toString() +val releasedInterpreterVersion = property("tools.refinery.interpreter.release").toString() + +repositories { + mavenCentral() +} + dependencies { gradle.projectsEvaluated { for (subproject in rootProject.subprojects) { if (subproject.plugins.hasPlugin(JavaLibraryPlugin::class)) { javadocs(project(subproject.path, "javadocElements")) + val releasedProjectVersion = if (subproject.group.toString() == interpreterGroup) + releasedInterpreterVersion else releasedVersion + releasedJavadocs("${subproject.group}:${subproject.name}:$releasedProjectVersion:javadoc@jar") } } } javadocs(project(":refinery-gradle-plugins", "javadocElements")) + releasedJavadocs("tools.refinery:refinery-gradle-plugins:$releasedVersion:javadoc@jar") } val srcDir = "src" - val docusaurusOutputDir = layout.buildDirectory.dir("docusaurus") - val javadocsDir = layout.buildDirectory.dir("javadocs") val configFiles: FileCollection = files( @@ -72,7 +87,7 @@ abstract class ExtractJavadocTask : DefaultTask() { fs.delete { delete(targetDir) } - val javadocsDocsDir = targetDir.get().dir("develop/javadoc") + val javadocsDocsDir = targetDir.get() resolvedJavadocArtifacts.get().forEach { artifact -> fs.copy { from(archive.zipTree(artifact.value)) @@ -82,19 +97,29 @@ abstract class ExtractJavadocTask : DefaultTask() { } } +fun resolveJavadocs(configuration: Configuration): Provider> { + return provider { + configuration.resolvedConfiguration.resolvedArtifacts.associate { artifact -> + artifact.moduleVersion.id.name to artifact.file + } + } +} + tasks { val extractJavadocs by registering(ExtractJavadocTask::class) { dependsOn(javadocs) - targetDir = javadocsDir - resolvedJavadocArtifacts = provider { - javadocs.resolvedConfiguration.resolvedArtifacts.associate { artifact -> - artifact.moduleVersion.id.name to artifact.file - } - } + targetDir = javadocsDir.map { it.dir("snapshot/develop/javadoc" ) } + resolvedJavadocArtifacts = resolveJavadocs(javadocs) + } + + val extractReleasedJavadocs by registering(ExtractJavadocTask::class) { + dependsOn(releasedJavadocs) + targetDir = javadocsDir.map { it.dir("develop/javadoc" ) } + resolvedJavadocArtifacts = resolveJavadocs(releasedJavadocs) } assembleFrontend { - dependsOn(extractJavadocs) + dependsOn(extractJavadocs, extractReleasedJavadocs) inputs.dir(srcDir) inputs.dir("static") inputs.dir(javadocsDir) diff --git a/subprojects/docs/docusaurus.config.ts b/subprojects/docs/docusaurus.config.ts index e8201cb29..b8641ccc3 100644 --- a/subprojects/docs/docusaurus.config.ts +++ b/subprojects/docs/docusaurus.config.ts @@ -16,29 +16,25 @@ import type { UserThemeConfig } from '@docusaurus/theme-common'; import type { UserThemeConfig as AlgoliaConfig } from '@docusaurus/theme-search-algolia'; import type { Config } from '@docusaurus/types'; import type { Config as SwcConfig } from '@swc/core'; +import { PropertiesFile } from 'java-properties'; import { themes } from 'prism-react-renderer'; import smartypants from 'remark-smartypants'; import remarkPosix2Windows from './src/plugins/remarkPosix2Windows'; import remarkReplaceVariables from './src/plugins/remarkReplaceVariables'; +const properties = new PropertiesFile( + path.join(__dirname, '../../gradle.properties'), +); + const markdownOptions: Partial = { remarkPlugins: [ - [ - remarkReplaceVariables, - { propertiesPath: path.join(__dirname, '../../gradle.properties') }, - ], + [remarkReplaceVariables, { properties }], [smartypants, { dashes: 'oldschool' }], remarkPosix2Windows, ], }; -const docsOptions = { - ...markdownOptions, - editUrl: - 'https://github.com/graphs4value/refinery/edit/main/subprojects/docs', -} satisfies DocsOptions; - export default { title: 'Refinery', tagline: 'An efficient graph solver for generating well-formed models', @@ -54,7 +50,15 @@ export default { path: 'src/docs', routeBasePath: '/', sidebarPath: './sidebars.ts', - ...docsOptions, + editUrl: + 'https://github.com/graphs4value/refinery/edit/main/subprojects/docs', + versions: { + current: { + path: 'snapshot', + label: `${String(properties.get('version'))} 🚧`, + }, + }, + ...markdownOptions, } satisfies DocsOptions, ], [ @@ -103,13 +107,14 @@ export default { hideOnScroll: true, items: [ { + type: 'doc', label: 'Learn', - to: '/learn', + docId: 'learn/index', }, { + type: 'doc', label: 'Develop', - to: '/develop/java', - activeBasePath: '/develop', + docId: 'develop/java', }, { label: 'GitHub', @@ -122,6 +127,10 @@ export default { href: 'https://refinery.services/', className: 'navbar__link--try-now', }, + { + type: 'docsVersionDropdown', + position: 'right', + }, ], }, footer: { @@ -218,10 +227,8 @@ export default { appId: 'KYHOYEO80F', apiKey: '152acfb8d1ad9e10f29f083a6b017a69', indexName: 'refinery', - // We don't have any context specified, so we need to disable this to return results. - contextualSearch: false, // Javadoc doesn't use the Docusaurus router and has to be navigated to with `location.href` instead. - externalUrlRegex: '/develop/javadoc/.+', + externalUrlRegex: '/([^/]+/)?develop/javadoc/.+', }, } satisfies UserThemeConfig & AlgoliaConfig, webpack: { diff --git a/subprojects/docs/src/css/custom.css b/subprojects/docs/src/css/custom.css index 64eeb5c4c..62369e496 100644 --- a/subprojects/docs/src/css/custom.css +++ b/subprojects/docs/src/css/custom.css @@ -112,7 +112,7 @@ code { } .navbar__inner .navbar__link--try-now { - margin: 0 0.75rem 0 0.5rem; + margin: 0 0.5rem; padding: 0.25rem 1.25rem; border-radius: 50em; } diff --git a/subprojects/docs/src/docs/develop/contributing/commands.md b/subprojects/docs/src/docs/develop/contributing/commands.md index 06b82873d..d0e300ec5 100644 --- a/subprojects/docs/src/docs/develop/contributing/commands.md +++ b/subprojects/docs/src/docs/develop/contributing/commands.md @@ -34,8 +34,8 @@ This will also be run by GitHub Actions for each commit or pull requests. Publishes the Refinery Java artifacts to the [Maven local repository](https://www.baeldung.com/maven-local-repository). -Build tools, such as Gradle, will be able to consume such artifacts, which enables you to use the latest version of Refinery -- possibly including your own modification -- in other Java projects. -For more information, see our [programming guide](../../java). +Build tools, such as Gradle, will be able to consume such artifacts, which enables you to use the latest version of Refinery -- possibly including your own modifications -- in other Java projects. +For more information, see our [programming guide](/snapshot/develop/java). ### `serve` diff --git a/subprojects/docs/src/docs/develop/java.md b/subprojects/docs/src/docs/develop/java.md index 1f1fd5da4..d19306e62 100644 --- a/subprojects/docs/src/docs/develop/java.md +++ b/subprojects/docs/src/docs/develop/java.md @@ -24,36 +24,17 @@ Below, you can find instructions on using [Gradle](#gradle) or [Apache Maven](#m We recommend [Gradle](https://gradle.org/) as a build system for creating Java programs that use Refinery as a library. We created a [Gradle plugin](pathname://../javadoc/refinery-gradle-plugins/) to simplify project configuration. -To find out how to add the plugin to your build, select below whether you want to use a **released** version or a **snapshot** version of refinery or whether you want to build Refinery **locally** yourself. +This tutorial explains how to use a **snapshot** or **local** pre-release version of Refinery with Gradle. +Released versions, such as the [**latest version**](/develop/java#gradle), are available from [Maven Central](https://central.sonatype.com/namespace/tools.refinery). import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; - - To find out the configuration required to use our artifacts, select whether you use a Kotlin-based (`.gradle.kts`) or a Groovy-based (`.gradle`) configuration format for your Gradle build. You should add this code to your Gradle *settings* file, which is named `settings.gradle.kts` or `settings.gradle`. - - - - ```kotlin title="settings.gradle.kts" - plugins { - id("tools.refinery.settings") version "@@@tools.refinery.release@@@" - } - ``` - - - ```groovy title="settings.gradle" - plugins { - id 'tools.refinery.settings' version '@@@tools.refinery.release@@@' - } - ``` - - - - + We always publish a [SNAPSHOT](https://maven.apache.org/guides/getting-started/index.html#what-is-a-snapshot-version) version of Refinery based on the latest commit in our [Git repository](https://github.com/graphs4value/refinery). This is the development version of our code and may change without warning at any time. - To find out the configuration required to use our snapshot artifacts, select whether you use a Kotlin-based (`.gradle.kts`) or a Groovy-based (`.gradle`) configuration format for your Gradle build. You should add this code to your Gradle *settings* file, which is named `settings.gradle.kts` or `settings.gradle`. + To find out the configuration for using our snapshot artifacts, select whether you use a Kotlin-based (`.gradle.kts`) or a Groovy-based (`.gradle`) configuration format for your Gradle build. You should add this code to your Gradle *settings* file, which is named `settings.gradle.kts` or `settings.gradle`. @@ -96,7 +77,7 @@ import TabItem from '@theme/TabItem'; Running Refinery from a local build is an _advanced technique_ that you should only use if you want to [contribute to Refinery](../contributing) and have modified it yourself. First you'll have to run the [`./gradlew publishToMavenLocal`](../contributing/commands#publishtomavenlocal) command in your local clone of the Refinery repository to install Refinery into your [local Maven repository](https://www.baeldung.com/maven-local-repository). - Next, to find out the configuration required to use the local artifacts, select whether you use a Kotlin-based (`.gradle.kts`) or a Groovy-based (`.gradle`) configuration format for your Gradle build. You should add this code to your Gradle *settings* file, which is named `settings.gradle.kts` or `settings.gradle`. + Next, to find out the configuration for using local artifacts, select whether you use a Kotlin-based (`.gradle.kts`) or a Groovy-based (`.gradle`) configuration format for your Gradle build. You should add this code to your Gradle *settings* file, which is named `settings.gradle.kts` or `settings.gradle`. @@ -398,31 +379,11 @@ Do *not* attempt to set a `version` for this plugin, because versioning is alrea You may also develop applications based on Refiney using [Apache Maven](https://maven.apache.org/) as the build system. Although we don't provide a Maven plugin for simplified configuration, you can still use our [platform](https://docs.gradle.org/current/userguide/platforms.html#sub:using-platform-to-control-transitive-deps) (Maven BOM) to lock the versions of Refinery and its dependencies to tested versions. -To find out how to add the BOM to your build, select below whether you want to use a **released** version or a **snapshot** version of refinery or whether you want to build Refinery **locally** yourself. +This tutorial explains how to use a **snapshot** or **local** pre-release version of Refinery with Maven. +Released versions, such as the [**latest version**](/develop/java#maven), are available from [Maven Central](https://central.sonatype.com/namespace/tools.refinery). - - You should add the following configuration to your `pom.xml` file. If you use multi-module projects, we recommend that you add this to your parent POM. - - ```xml title="pom.xml" - - ... - - - - tools.refinery - refinery-bom - @@@tools.refinery.release@@@ - pom - import - - - - ... - - ``` - - + We always publish a [SNAPSHOT](https://maven.apache.org/guides/getting-started/index.html#what-is-a-snapshot-version) version of Refinery based on the latest commit in our [Git repository](https://github.com/graphs4value/refinery). This is the development version of our code and may change without warning at any time. You should add the following configuration to your `pom.xml` file. If you use multi-module projects, we recommend that you add this to your parent POM. diff --git a/subprojects/docs/src/docs/learn/docker/cli.md b/subprojects/docs/src/docs/learn/docker/cli.md index f9e8677cb..0c3df0889 100644 --- a/subprojects/docs/src/docs/learn/docker/cli.md +++ b/subprojects/docs/src/docs/learn/docker/cli.md @@ -10,7 +10,7 @@ sidebar_label: CLI You can run Refinery as a command-line applications via our [Docker container](https://github.com/graphs4value/refinery/pkgs/container/refinery-cli) on either `amd64` or `arm64` machines: ```shell -docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:@@@tools.refinery.release@@@ +docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:latest ``` This will let you read input files and generate models in the current directory (`${PWD}`) of your terminal session. @@ -19,13 +19,13 @@ Module imports (e.g., `import some::module.` to import `some/module.refinery`) r For example, to generate a model based on the file named `input.problem` in the current directory and write the results into the file named `output.refinery`, you may run the [`generate` subcommand](#generate) with ```shell -docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:@@@tools.refinery.release@@@ generate -o output.refinery input.problem +docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:latest generate -o output.refinery input.problem ``` If you want Refinery CLI to print its documentation, run ```shell -docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:@@@tools.refinery.release@@@ -help +docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:latest -help ``` ## The `generate` subcommand {#generate} @@ -33,7 +33,7 @@ docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:@@@tools.r The `generate` subcommand generates a consistent concrete model from a partial model. ```shell -docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:@@@tools.refinery.release@@@ generate [options] input path +docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:latest generate [options] input path ``` The `input path` should be a path to a `.problem` file relative to the current directory. @@ -73,7 +73,7 @@ This option is especially useful if you want to generate models of multiple size For example, the command ```shell -docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:@@@tools.refinery.release@@@ generate -s File=20..25 input.problem +docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:latest generate -s File=20..25 input.problem ``` is equivalent to appending @@ -143,18 +143,3 @@ The generation is considered successful if it finds at least one solution, but m In this case, there will be fewer output files than requested. **Default value:** `1` - -## Pre-release versions - -You can take advantage of the most recent code submitted to our repository by using the `latest` tag instead. - - -```shell -docker run --pull always --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:latest -``` - -:::warning - -Pre-release versions may be unstable. - -::: diff --git a/subprojects/docs/src/docs/learn/docker/index.md b/subprojects/docs/src/docs/learn/docker/index.md index af090763f..1499bea3f 100644 --- a/subprojects/docs/src/docs/learn/docker/index.md +++ b/subprojects/docs/src/docs/learn/docker/index.md @@ -24,7 +24,7 @@ Installing Refinery as a Docker container can support more advanced use cases, s To generate larger models with a longer timeout, you can use our [Docker container](https://github.com/graphs4value/refinery/pkgs/container/refinery) on either `amd64` or `arm64` machines: ```shell -docker run --rm -it -p 8888:8888 ghcr.io/graphs4value/refinery:@@@tools.refinery.release@@@ +docker run --rm -it -p 8888:8888 ghcr.io/graphs4value/refinery:latest ``` Once Docker pulls and starts the container, you can navigate to http://localhost:8888 to open the model generation interface and start editing. @@ -163,18 +163,3 @@ Modules (`.refinery` files) in this directory or colon-separated list of directo :warning: Only expose files that you want to make public. It's best to expose a directory that contains nothing other than `.refinery` files to minimize potential information leaks. **Default value:** _empty_ (no directories are exposed) - -## Pre-release versions - -You can take advantage of the most recent code submitted to our repository by using the `latest` tag instead. - - -```shell -docker run --pull always --rm -it -p 8888:8888 ghcr.io/graphs4value/refinery:latest -``` - -:::warning - -Pre-release versions may be unstable. - -::: diff --git a/subprojects/docs/src/plugins/remarkReplaceVariables.ts b/subprojects/docs/src/plugins/remarkReplaceVariables.ts index 6ad2675a9..5c0ae7256 100644 --- a/subprojects/docs/src/plugins/remarkReplaceVariables.ts +++ b/subprojects/docs/src/plugins/remarkReplaceVariables.ts @@ -4,29 +4,27 @@ * SPDX-License-Identifier: EPL-2.0 */ -import { PropertiesFile } from 'java-properties'; +import type { PropertiesFile } from 'java-properties'; import type { Transformer } from 'unified'; import { visit } from 'unist-util-visit'; const TEMPLATE_REGEXP = /@@@([a-zA-Z\d._-]*)@@@/g; export default function remarkReplaceVariables({ - propertiesPath, + properties, }: { - propertiesPath?: string; + properties: PropertiesFile; }): Transformer { - if (propertiesPath === undefined) { + if (properties === undefined) { throw new Error('propertiesPath is required'); } - const variables = new PropertiesFile(propertiesPath); - function substitution(substring: string, name: string): string { if (name === '') { // Escape sequence. return '@@@'; } - const value = variables.get(name); + const value = properties.get(name); if (value !== undefined) { return String(value); } diff --git a/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/commands.md b/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/commands.md new file mode 100644 index 000000000..d0e300ec5 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/commands.md @@ -0,0 +1,158 @@ +--- +SPDX-FileCopyrightText: 2024 The Refinery Authors +SPDX-License-Identifier: EPL-2.0 +sidebar_position: 1 +title: Build commands +--- + +# Building from the command line + +## Gradle commands + +We use [Gradle](https://gradle.org/) to manage the compilation and tests of Refinery. + +Java code is built directly by Gradle. +We use the [frontend-gradle-plugin](https://siouan.github.io/frontend-gradle-plugin/) to manage a [Node.js](https://nodejs.org/en) and [Yarn](https://yarnpkg.com/) installation, which in turn is used to build TypeScript code (including this documentation website). +Typically, Yarn commands are issued by Gradle and you don't need to work with the TypeScript build system directly if you're only working on the Java parts of Refinery. + +### `build` + +```bash posix2windows +./gradlew build +``` + +Compile all code, run all tests, and produce all build artifacts. + +You should run this command before submitting a [Pull request](https://github.com/graphs4value/refinery/pulls) to make sure that all code builds and tests pass on your local machine. +This will also be run by GitHub Actions for each commit or pull requests. + +### `publishToMavenLocal` + +```bash posix2windows +./gradlew publishToMavenLocal +``` + +Publishes the Refinery Java artifacts to the [Maven local repository](https://www.baeldung.com/maven-local-repository). + +Build tools, such as Gradle, will be able to consume such artifacts, which enables you to use the latest version of Refinery -- possibly including your own modifications -- in other Java projects. +For more information, see our [programming guide](/snapshot/develop/java). + +### `serve` + +```bash posix2windows +./gradlew serve +``` + +Starts the Refinery backend and web interface on port 1312. + +This task is ideal for running the Refinery backend if you don't intend to work on the frontend. +The Refinery frontend TypeScript projects is automatically built before the server starts. +The server will use the latest build output of the frontend as static assets. + +The behavior of this task is influenced by the same [environmental variables](../../../learn/docker#environmental-variables) as the Refinery [Docker container](../../../learn/docker). +However, the default value of `REFINERY_LISTEN_PORT` is `1312`. + +### `serveBackend` + +```bash posix2windows +./gradlew serveBackend +``` + +Starts the Refinery backend on port 1312. + +This task is ideal for running the Refinery backend if you're working on the frontend. +No static assets will be build. +You'll need to use [`yarnw frontend dev`](#frontend-dev) + +Like [`./gradlew serve`](#serve), the behavior of this task is influenced by the same [environmental variables](../../../learn/docker#environmental-variables) as the Refinery [Docker container](../../../learn/docker). +However, the default value of `REFINERY_LISTEN_PORT` is `1312`. + +## Yarn commands + +We provide a `yarnw` wrapper script to invoke the Yarn distribution installed by frontend-gradle-plugin directly. +The following commands can only be run once [`./gradlew build`](#build) has installed the necessary Node.js and Yarn packages. + +### `docs dev` + +```bash posix2windows +./yarn docs dev +``` + +Builds and serves this documentation in development mode on port 3000. +Saved changes to most documentation sources are immediately reflected in the browse without reloading. + +You can set the port with the `-p` option, e.g. to use port 1313, use + +```bash posix2windows +./yarn docs dev -p 1313 +``` + +:::note + +Running this command for the first time may generate error messages like +``` +ERROR failed to read input source map: failed to parse inline source map url +``` +which can be safely ignored. + +::: + +### `frontend dev` + +```bash posix2windows +./yarn frontend dev +``` + +Builds and serves the refinery frontend on port 1313. +Saved changes to most source files are immediately reflected in the browser without reload. + +Before running this command, you need to start [`./gradlew serveBackend`](#servebackend) to provide a backend for the frontend to connect to. +The development server of the frontend will proxy all WebSocket connections to the backend. + +The following environmental variables influence the behavior of this command: + +#### `REFINERY_LISTEN_HOST` + +Hostname to listen at for incoming HTTP connections. + +**Default value:** `localhost` + +#### `REFINERY_LISTEN_PORT` + +TCP port to listen at for incoming HTTP connections. + +**Default value:** `1313` + +#### `REFINERY_BACKEND_HOST` + +Hostname of the Refinery backend. + +This should match the `REFINERY_LISTEN_HOST` passed to [`./gradlew serveBackend`](#servebackend). + +**Default value:** `127.0.0.1` (connect to `localhost` over IPv4 only) + +#### `REFINERY_LISTEN_PORT` + +TCP port of the Refinery backend. + +This should match the `REFINERY_LISTEN_PORT` passed to [`./gradlew serveBackend`](#servebackend). + +**Default value:** `1312` + +#### `REFINERY_PUBLIC_HOST` + +Publicly visible hostname of the Refinery instance. + +If you use a reverse proxy in front of the development server, you must set this variable. +Otherwise, connections to the development server will fail due to cross-origin protection. + +**Default value:** equal to `REFINERY_LISTEN_HOST` + +#### `REFINERY_PUBLIC_PORT` + +Publicly visible port of the Refinery instance. + +If you use a reverse proxy in front of the development server, you must set this variable. +Otherwise, connections to the development server will fail due to cross-origin protection. + +**Default value:** equal to `REFINERY_LISTEN_PORT` diff --git a/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/ide-setup.md b/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/ide-setup.md new file mode 100644 index 000000000..d5dd4eb55 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/ide-setup.md @@ -0,0 +1,96 @@ +--- +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors +SPDX-License-Identifier: EPL-2.0 +sidebar_position: 2 +title: IDE setup +--- + +# Setting up the development environment + +## IntelliJ IDEA + +We prefer [IntelliJ IDEA](https://www.jetbrains.com/idea/) as a Java development environment. +No special preparations should be necessary for importing the project as a Gradle project into IDEA: + +1. See the [required tools](/develop/contributing#required-tools) for compiling Refinery on obtaining the required JDK version. You'll also need a version of IntelliJ IDEA that supports **Java 21** (version **2023.3** or later). + +2. Clone the project git repository and open it in IntelliJ IDEA. Make sure to _open_ the project instead of creating a _new_ one in the same directory. + +3. IntelliJ IDEA should build and index the project. If there are errors, it is likely that the `JAVA_HOME` was incorrectly set: + * In _Project Structure > Project settings > Project > SDK_, a Java 21 compatible JDK should be selected. + * In _Project Structure > Project settings > Project > Language level_, either _SDK default_ or _21_ should be selected. + * Make sure that each module in _Project Structure > Project settings > Module_ uses the _Project default_ language level in _Sources > Language level_ and the _Project SDK_ in _Dependencies > Module SDK._ + * In _Settings > Gradle settings > Gradle Projects > Gradle_, the _Distribution_ should be set to _Wrapper_ and the _Gradle JVM_ should be set to _Project SDK._ + +4. We recommend installing the latest _SonarLint_ plugin in _Settings > Plugins_ to get real-time code quality analysis in your IDE. + +:::note + +You'll need [Eclipse](#eclipse) to edit Xtext (`*.xtext`) and MWE2 (`*.mwe2`) files and Ecore class diagrams (`*.aird`, `*.ecore`, `*.genmodel`). +If you do not plan on making changes to such files, feel free to skip the Eclipse installation steps below. + +You'll also need [VS Code](#vs-code) to edit the TypeScript code in Refinery. + +::: + +## Eclipse + +1. See the [required tools](/develop/contributing#required-tools) for compiling Refinery on obtaining the required JDK version. + +2. Download and extract the [Eclipse IDE for Java and DSL Developers 2023-12](https://www.eclipse.org/downloads/packages/release/2023-12/r/eclipse-ide-java-and-dsl-developers) package. + +3. Launch Eclipse and create a new workspace. + +4. Open _Help > Eclipse Marketplace_ and install the following software: + * _EclEmma Java Code Coverage_ + * _EcoreTools : Ecore Diagram Editor_ + * _Sirius_ (ignore the warning during installation about the solution _Sirius_ not being available) + * _SonarLint_ + +5. Open _Window > Preferences_ and set the following preferences: + * _General > Workspace > Text file encoding_ should be _UTF-8_. + * _General > Workspace > New text file line delimiter_ should be _Unix_. + * Add the JDK 21 to _Java > Installed JREs_. + * Make sure JDK 21 is selected for _JavaSE-21_ at _Java > Installed JREs > Execution Environments_. + * Set _Gradle > Java home_ to the `JAVA_HOME` directory (the directory which contains the `bin` directory) of JDK 21. Here, Buildship will show a yellow warning sign, which can be safely ignored. + * Set _Java > Compiler > JDK Compliance > Compiler compliance level_ to _21_. + +6. Clone the project Git repository but _do not_ import it into Eclipse yet. + +7. Open a new terminal and run + ```bash posix2windows + ./gradlew prepareEclipse + ``` + in the cloned repository. + * This should complete without any compilation errors. + * To troubleshoot any error, see the [instructions for compiling Refinery](/develop/contributing#compiling). + +8. Select _File > Import... > Gradle > Existing Gradle Project_ and import the cloned repository in Eclipse. + * Make sure to select the root of the repository (containing this file) as the _Project root directory_ and that the _Gradle distribution_ is _Gradle wrapper_. + * If you have previously imported the project into Eclipse, this step will likely fail. In that case, you should remove the projects from Eclipse, run `git clean -fxd` in the repository, and start over from step 8. + +## VS Code + +We recommend [VSCodium](https://github.com/VSCodium/vscodium) or [Visual Studio Code](https://code.visualstudio.com/) to work with the parts of Refinery that are written is TypeScript. + +1. See the [required tools](/develop/contributing#required-tools) for compiling Refinery on obtaining the required JDK version. + +2. Install the following VS Code extensions: + * _EditorConfig for VS Code_ [[Open VSX](https://open-vsx.org/extension/EditorConfig/EditorConfig)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig)] + * _ESLint_ [[Open VSX](https://open-vsx.org/extension/dbaeumer/vscode-eslint)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)] + * _MDX_ [[Open VSX](https://open-vsx.org/extension/unifiedjs/vscode-mdx)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=unifiedjs.vscode-mdx)] + * _Prettier - Code formatter_ [[Open VSX](https://open-vsx.org/extension/esbenp/prettier-vscode)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)] + * _XState VSCode_ [[Open VSX](https://open-vsx.org/extension/statelyai/stately-vscode)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=statelyai.stately-vscode)] + * _ZipFS - a zip file system_ [[Open VSX](https://open-vsx.org/extension/arcanis/vscode-zipfs)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=arcanis.vscode-zipfs)] + +3. Clone the project Git repository but _do not_ import it into VS Code yet. + +4. Run + ```bash posix2windows + ./gradlew installFrontend + ``` + to install all required Node.js tooling. + +5. Open the repository with _Open Folder…_ in VS Code. + * When asked, select that you _Trust_ the folder. + * When asked, enable using the TypeScript and ESLint tooling specified in the repository. diff --git a/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/index.md b/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/index.md new file mode 100644 index 000000000..aa0bdb2fd --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/index.md @@ -0,0 +1,59 @@ +--- +SPDX-FileCopyrightText: 2024 The Refinery Authors +SPDX-License-Identifier: EPL-2.0 +sidebar_position: 1 +title: Contributing +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +# Contributing to Refinery + +You can clone the refinery repository from GitHub at https://github.com/graphs4value/refinery. +If you want to contribute code, we recommend [forking](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) the repository on GitHub so that you can submit a [pull request](https://github.com/graphs4value/refinery/pulls) later. + +## Required tools + +Refinery is written in Java and TypeScript. To build Refinery, you'll need a **Java 21** compatible **Java Development Kit (JDK).** We recommend the [Adoptium Java 21 JDK](https://adoptium.net/) or the [Amazon Corretto Java 21 JDK](https://aws.amazon.com/corretto/). + +## Compiling Refinery {#compiling} + +To build Refinery, run the command +```bash posix2windows +./gradlew build +``` +in the cloned repository. + +This should complete without any compilation errors. + +If you get any errors about the JVM version, check whether the `JAVA_HOME` environment variable is set to the location of **JDK 21**. You can query the variable with + + + ```bash + echo $JAVA_HOME + ``` + + + ```bash + echo $Env:JAVA_HOME + ``` + + +To set the `JAVA_HOME` environmental variable, use + + + ```bash + export JAVA_HOME=/java/path/here + ``` + + + ```bash + $Env:JAVA_HOME="C:\java\path\here" + ``` + + + +If the build fails with a `Host name must not be empty` error, you [might need to remove the empty proxy configuration from your global `gradle.properties` file](https://stackoverflow.com/a/62128323). + +For further information, see the [supported build commands](/develop/contributing/commands) and the [instructions for setting up an IDE](/develop/contributing/ide-setup). diff --git a/subprojects/docs/versioned_docs/version-0.1.0/develop/java.md b/subprojects/docs/versioned_docs/version-0.1.0/develop/java.md new file mode 100644 index 000000000..26ba89f59 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/develop/java.md @@ -0,0 +1,351 @@ +--- +SPDX-FileCopyrightText: 2024 The Refinery Authors +SPDX-License-Identifier: EPL-2.0 +sidebar_position: 0 +--- + +# Programming guide + +This guide is aimed at developers who wish to create Java applications that leverage Refinery as a library. +We also recommend browsing the [Javadoc documentation](../javadoc) associated with Refinery components. +See the [contributor's guide](../contributing) for information on building and modifying Refinery itself. + +:::note + +Refinery can run as a cloud-based [_Graph Solver as a Service_](https://refinery.services/) without local installation. +You can also run a compiled version as a [Docker container](../../learn/docker). + +::: + +Below, you can find instructions on using [Gradle](#gradle) or [Apache Maven](#maven) to create applications that use Refinery as a Java library. + +## Working with Gradle {#gradle} + +We recommend [Gradle](https://gradle.org/) as a build system for creating Java programs that use Refinery as a library. +We created a [Gradle plugin](pathname://../javadoc/refinery-gradle-plugins/) to simplify project configuration. + +To find out the configuration for using our artifacts, select whether you use a Kotlin-based (`.gradle.kts`) or a Groovy-based (`.gradle`) configuration format for your Gradle build. You should add this code to your Gradle *settings* file, which is named `settings.gradle.kts` or `settings.gradle`. + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + + + + ```kotlin title="settings.gradle.kts" + plugins { + id("tools.refinery.settings") version "0.1.0" + } + ``` + + + ```groovy title="settings.gradle" + plugins { + id 'tools.refinery.settings' version '0.1.0' + } + ``` + + + +This plugin will perform the following actions automatically: +* Add a [version catalog](https://docs.gradle.org/current/userguide/platforms.html#sec:sharing-catalogs) to your build to enable easy access to Refinery artifacts and their [dependencies](#declaring-dependencies). +* Lock refinery artifacts and their dependencies to a [platform](https://docs.gradle.org/current/userguide/platforms.html#sub:using-platform-to-control-transitive-deps) (Maven BOM) of tested versions. +* Configure a logger based on [Log4J over SLF4J](https://www.slf4j.org/legacy.html) and [SLF4J Simple](https://www.slf4j.org/apidocs/org/slf4j/simple/SimpleLogger.html) that is free from vulnerabilities and works out of the box for most use-cases. +* Generate [application](#building-applications) artifacts, if any, according to best practices used in the Refinery project. +* Add common dependencies for writing [unit tests](#writing-tests) for your Java code. + +See the [multi-module projects](#multi-module-projects) section of this tutorial on how to disable some of these automated actions for a part of your build. + +### Declaring dependencies + +The Refinery Gradle plugins adds a [version catalog](https://docs.gradle.org/current/userguide/platforms.html#sec:sharing-catalogs) named `refinery` that you can use to quickly access dependencies. +For example, to add a dependency to the [`tools.refinery:refinery-generator`](pathname://../javadoc/refinery-generator/) library, you add the following to your `build.gradle.kts` or `build.gradle` file: + + + + ```kotlin title="build.gradle.kts" + depndencies { + implementation(refinery.generator) + } + ``` + + + ```groovy title="build.gradle" + dependencies { + implementation refinery.generator + } + ``` + + + +The version catalog also contains the external dependencies used by the Refinery framework. +For example, you may add [GSON](https://google.github.io/gson/) for JSON parsing and [JCommander](https://jcommander.org/) for command-line argument parsing as follows: + + + + ```kotlin title="build.gradle.kts" + depndencies { + implementation(refinery.gson) + implementation(refinery.jcommander) + } + ``` + + + ```groovy title="build.gradle" + dependencies { + implementation refinery.gson + implementation refinery.jcommander + } + ``` + + + +### Building applications + +You can use the built-in [`application`](https://docs.gradle.org/current/userguide/application_plugin.html) to build stand-alone Java applications. + +When developing you main application code in the `src/main/java` directory of you project, you can use the [`StandaloneRefinery`](pathname://../javadoc/refinery-generator/tools/refinery/generator/standalone/StandaloneRefinery.html) class from [`tools.refinery:refinery-generator`](pathname://../javadoc/refinery-generator/) to access Refinery generator components. See the tutorial on Xtext's [dependency injection](https://eclipse.dev/Xtext/documentation/302_configuration.html#dependency-injection) for more advanced use-cases. + +```java +package org.example; + +import tools.refinery.generator.standalone.StandaloneRefinery; + +import java.io.IOException; + +public class ExampleMain { + public static void main(String[] args) throws IOException { + var problem = StandaloneRefinery.getProblemLoader().loadString(""" + class Filesystem { + contains Directory[1] root + } + + class File. + + class Directory extends File { + contains Directory[] children + } + + scope Filesystem = 1, File = 20. + """); + var generator = StandaloneRefinery.getGeneratorFactory().createGenerator(problem); + generator.generate(); + var trace = generator.getProblemTrace(); + var childrenRelation = trace.getPartialRelation("Directory::children"); + var childrenInterpretation = generator.getPartialInterpretation(childrenRelation); + var cursor = childrenInterpretation.getAll(); + while (cursor.move()) { + System.out.printf("%s: %s%n", cursor.getKey(), cursor.getValue()); + } + } +} +``` + +If you want to produce a "fat JAR" that embeds all dependencies (e.g., for invoking from the command line or from Python with a single command), you should also add the [shadow](https://github.com/Goooler/shadow) plugin. +The recommended version of the shadow plugin is set in our [version catalog](#declaring-dependencies). You can add it to your build script as follows: + + + + ```kotlin title="build.gradle.kts" + plugins { + application + alias(refinery.plugins.shadow) + } + + application { + mainClass = "org.example.ExampleMain" + } + ``` + + + ```groovy title="build.gradle" + plugins { + application + alias refinery.plugins.shadow + } + + application { + mainClass 'org.example.ExampleMain' + } + ``` + + + +After building your project with `./gradlew build`, you may find the produced "fat JAR" in the `build/libs` directory. +Its file name will be suffixed with `-all.jar`. +In you have Java 21 installed, you'll be able to run the application with the command + + + + ```bash + java -jar ./build/libs/example-0.0.0-SNAPSHOT-all.jar + ``` + + + ```bash + java -jar .\build\libs\example-0.0.0-SNAPSHOT-all.jar + ``` + + + +Be sure to replace `example-0.0.0-SNAPSHOT` with the name and version of your project. + +### Writing tests + +Our Gradle plugin automatically sets up [JUnit 5](https://junit.org/junit5/) for writing tests and [parameterized tests](https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests). +It also sets up [Hamcrest](https://hamcrest.org/JavaHamcrest/) for writing assertions. +You should put your test files into the `src/test/java` directory in your projects. +You may run test with the commands `./gradlew test` or `./gradlew build`. + +To ensure that your tests are properly isolated, you should *not* rely on the [`StandaloneRefinery`](pathname://../javadoc/refinery-generator/tools/refinery/generator/standalone/StandaloneRefinery.html) class from [`tools.refinery:refinery-generator`](pathname://../javadoc/refinery-generator/) when accessing Refinery generator components. +Instead, you should use Xtext's [dependency injection](https://eclipse.dev/Xtext/documentation/302_configuration.html#dependency-injection) and [unit testing](https://eclipse.dev/Xtext/documentation/103_domainmodelnextsteps.html#tutorial-unit-tests) support to instantiate the components. You'll need to add a dependency to Refinery's Xtext testing support library to your project. + + + + ```kotlin title="build.gradle.kts" + depndencies { + implementation(refinery.generator) + // highlight-next-line + testImplementation(testFixtures(refinery.language)) + } + ``` + + + ```groovy title="build.gradle" + dependencies { + implementation refinery.generator + // highlight-next-line + testImplementation testFixtures(refinery.language) + } + ``` + + + +Afterwards, you can use the `@ExtendWith`, `@InjectWith`, and `@Inject` annotations to set up your unit test. + +```java +package org.example; + +import com.google.inject.Inject; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import tools.refinery.generator.GeneratorResult; +import tools.refinery.generator.ModelGeneratorFactory; +import tools.refinery.generator.ProblemLoader; +import tools.refinery.language.tests.ProblemInjectorProvider; + +import java.io.IOException; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +// highlight-start +@ExtendWith(InjectionExtension.class) +@InjectWith(ProblemInjectorProvider.class) +// highlight-end +class ExampleTest { + // highlight-start + @Inject + private ProblemLoader problemLoader; + + @Inject + private ModelGeneratorFactory generatorFactory; + // highlight-end + + @Test + void testModelGeneration() throws IOException { + var problem = problemLoader.loadString(""" + class Filesystem { + contains Directory[1] root + } + + class File. + + class Directory extends File { + contains Directory[] children + } + + scope Filesystem = 1, File = 20. + """); + var generator = generatorFactory.createGenerator(problem); + var result = generator.tryGenerate(); + assertThat(result, is(GeneratorResult.SUCCESS)); + } +} +``` + +### Multi-module projects + +By default, the `tools.refinery.settings` plugin will apply our `tools.refinery.java` plugin to all Java projects in your build and configure them for use with Refinery. This is sufficient for single-module Java projects, and multi-module projects where all of your Java modules use Refinery. + +If you wish to use Refinery in only some modules in your multi-module project, you can disable this behavior by adding + +```ini title="gradle.properties" +tools.refinery.gradle.auto-apply=false +``` + +to the `gradle.properties` file in the root directory of your project. + +If you use this setting, you'll need to add the `tools.refinery.java` plugin manually to any Java projects where you want to use Refinery like this: + + + + ```kotlin title="build.gradle.kts" + plugins { + id("tools.refinery.java") + } + ``` + + + ```groovy title="build.gradle" + plugins { + id 'tools.refinery.java' + } + ``` + + + +Do *not* attempt to set a `version` for this plugin, because versioning is already managed by the `tools.refinery.settings` plugin. Trying to set a version for the `tools.refinery.java` plugin separately will result in a Gradle error. + +## Working with Maven {#maven} + +You may also develop applications based on Refiney using [Apache Maven](https://maven.apache.org/) as the build system. +Although we don't provide a Maven plugin for simplified configuration, you can still use our [platform](https://docs.gradle.org/current/userguide/platforms.html#sub:using-platform-to-control-transitive-deps) (Maven BOM) to lock the versions of Refinery and its dependencies to tested versions. + +You should add the following configuration to your `pom.xml` file. If you use multi-module projects, we recommend that you add this to your parent POM. + +```xml title="pom.xml" + + ... + + + + tools.refinery + refinery-bom + 0.1.0 + pom + import + + + + ... + +``` + +You'll be able to add dependencies to Refinery components without an explicit reference to the dependency version, since version numbers are managed by the BOM: + +```xml title="pom.xml" + + ... + + + tools.refinery + refinery-generator + + + ... + +``` + +However, since the Maven BOM doesn't offer additional configuration, you'll have to take care of tasks such as configuring logging and testing, as well as building applications yourself. diff --git a/subprojects/docs/versioned_docs/version-0.1.0/develop/javadoc.md b/subprojects/docs/versioned_docs/version-0.1.0/develop/javadoc.md new file mode 100644 index 000000000..dd165c007 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/develop/javadoc.md @@ -0,0 +1,41 @@ +--- +SPDX-FileCopyrightText: 2024 The Refinery Authors +SPDX-License-Identifier: EPL-2.0 +description: API documentation for Refinery components automatically generated by Javadoc +sidebar_position: 998 +--- + +# Javadoc + +Here you can find API documentation for Refinery components automatically generated by Javadoc. We recommend reading the [Programming guide](/develop/java/) first to understand how to use these components. + +# Refinery + +* [`tools.refinery:refinery-generator:0.1.0`](pathname://refinery-generator/) +* [`tools.refinery:refinery-gradle-plugins:0.1.0`](pathname://refinery-gradle-plugins/) +* [`tools.refinery:refinery-language:0.1.0`](pathname://refinery-language/) +* [`tools.refinery:refinery-language-ide:0.1.0`](pathname://refinery-language-ide/) +* [`tools.refinery:refinery-language-model:0.1.0`](pathname://refinery-language-model/) +* [`tools.refinery:refinery-language-semantics:0.1.0`](pathname://refinery-language-semantics/) +* [`tools.refinery:refinery-logic:0.1.0`](pathname://refinery-logic/) +* [`tools.refinery:refinery-store:0.1.0`](pathname://refinery-store/) +* [`tools.refinery:refinery-store-dse:0.1.0`](pathname://refinery-store-dse/) +* [`tools.refinery:refinery-store-dse-visualization:0.1.0`](pathname://refinery-store-dse-visualization/) +* [`tools.refinery:refinery-store-query:0.1.0`](pathname://refinery-store-query/) +* [`tools.refinery:refinery-store-query-interpreter:0.1.0`](pathname://refinery-store-query-interpreter/) +* [`tools.refinery:refinery-store-reasoning:0.1.0`](pathname://refinery-store-reasoning/) +* [`tools.refinery:refinery-store-reasoning-scope:0.1.0`](pathname://refinery-store-reasoning-scope/) +* [`tools.refinery:refinery-store-reasoning-smt:0.1.0`](pathname://refinery-store-reasoning-smt/) + +# Interpreter + +:::note + +The _Refinery Interpreter_ is modified version of [VIATRA™](https://eclipse.dev/viatra/) specifically for use in Refinery. If you're interested in learning about [VIATRA™](https://eclipse.dev/viatra/), we recommend the [VIATRA™ documentation](https://eclipse.dev/viatra/documentation/index.html) and [source code](https://github.com/eclipse-viatra/org.eclipse.viatra) instead. Eclipse®, VIATRA™ and ‘Eclipse VIATRA™’ are trademarks of Eclipse Foundation, Inc. + +::: + +* [`tools.refinery.interpreter:refinery-interpreter:0.28.1`](pathname://refinery-interpreter/) +* [`tools.refinery.interpreter:refinery-interpreter-localsearch:0.28.1`](pathname://refinery-interpreter-localsearch/) +* [`tools.refinery.interpreter:refinery-interpreter-rete:0.28.1`](pathname://refinery-interpreter-rete/) +* [`tools.refinery.interpreter:refinery-interpreter-rete-recipes:0.28.1`](pathname://refinery-interpreter-rete-recipes/) diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/docker/cli.md b/subprojects/docs/versioned_docs/version-0.1.0/learn/docker/cli.md new file mode 100644 index 000000000..325ae7e7a --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/docker/cli.md @@ -0,0 +1,145 @@ +--- +SPDX-FileCopyrightText: 2024 The Refinery Authors +SPDX-License-Identifier: EPL-2.0 +sidebar_position: 1 +sidebar_label: CLI +--- + +# Command-line interface + +You can run Refinery as a command-line applications via our [Docker container](https://github.com/graphs4value/refinery/pkgs/container/refinery-cli) on either `amd64` or `arm64` machines: + +```shell +docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:0.1.0 +``` + +This will let you read input files and generate models in the current directory (`${PWD}`) of your terminal session. +Module imports (e.g., `import some::module.` to import `some/module.refinery`) relative to the current directory are also supported. + +For example, to generate a model based on the file named `input.problem` in the current directory and write the results into the file named `output.refinery`, you may run the [`generate` subcommand](#generate) with + +```shell +docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:0.1.0 generate -o output.refinery input.problem +``` + +If you want Refinery CLI to print its documentation, run + +```shell +docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:0.1.0 -help +``` + +## The `generate` subcommand {#generate} + +The `generate` subcommand generates a consistent concrete model from a partial model. + +```shell +docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:0.1.0 generate [options] input path +``` + +The `input path` should be a path to a `.problem` file relative to the current directory. +Due to Docker containerization, paths _outside_ the current directory (e.g., `../input.problem`) are not supported. + +Passing `-` as the `input path` will read a partial model from the standard input. + +By default, the generator is _deterministic_ and always outputs the same concrete model. See the [`-random-seed`](#generate-random-seed) option to customize this behavior. + +See below for the list of supported `[options]`. + +### `-output`, `-o` {#generate-output} + +The output path for the generated model. +Passing `-o -` will write the generated model to the standard output. + +When generating multiple models with [`-solution-number`](#generate-solution-number), the value `-` is not supported and individual solutions will be saved to numbered files. +For example, if you pass `-o output.refinery -n 10`, solutions will be saved as `output_001.refinery`, `output_002.refinery`, ..., `output_010.refinery`. + +**Default value:** `-`, i.e., the solution is written to the standard output. + +### `-random-seed`, `-r` {#generate-random-seed} + +Random seed to control the behavior of model generation. + +The same random seed value and Refinery release will produce the same output model for an input problem. +Models generated with different values of `-random-seed` are highly likely (but are not guaranteed) to be _substantially_ different. + +**Default value:** `1` + +### `-scope`, `-s` {#generate-scope} + +Add [scope constraints](../../language/logic#type-scopes) to the input problem. + +This option is especially useful if you want to generate models of multiple sizes from the same partial model. + +For example, the command + +```shell +docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:0.1.0 generate -s File=20..25 input.problem +``` + +is equivalent to appending + +```refinery title="input.problem" +scope File = 20..25. +``` + +to `input.problem`. +The syntax of the argument is equivalent to the [`scope`](../../language/logic#type-scopes) declaration, but you be careful with the handling of spaces in your shell. +Any number of `-s` arguments are supported. For example, the following argument lists are equivalent: + +```shell +-scope File=20..25,Directory=3 +-s File=20..25,Directory=3 +-s File=20..25 -s Directory=3 +-s "File = 20..25, Directory = 3" +-s "File = 20..25" -s "Directory = 3" +``` + +The `*` opeator also has to be quoted to avoid shell expansion: + +```shell +-s "File=20..*" +``` + +### `-scope-override`, `-S` {#generate-scope-override} + +Override [scope constraints](../../language/logic#type-scopes) to the input problem. + +This argument is similar to [`-scope`](#generate-scope), but has higher precedence than the [`scope`](../../language/logic#type-scopes) declarations already present in the input file. +However, you can't override `scope` declarations in modules imported in the input file using the `import` statement. + +For example, if we have + +```refinery title="input.problem" +scope File = 20..25, Directory = 3. +``` + +in the input file, the arguments `-s File=10..12 input.problem` will be interpreted as + +```refinery +scope File = 20..25, Directory = 3. +scope File = 10..12. +``` + +which results in an _unsatisfiable_ problem. If the use `-S File=10..12 input.problem` instead, the type scope for `File` is overridden as + +```refinery +scope Directory = 3. +scope File = 10..12. +``` + +and model generation can proceed as requested. Since we had specified no override for `Directory`, its type scope declared in `input.problem` was preserved. + +Scope overrides do not override additional scopes, i.e., `-s File=20..30 -S File=10..25` is interpreted as `-S File=20..25`. + +### `-solution-number`, `-n` {#generate-solution-number} + +The number of distinct solutions to generate. + +Generated solutions are always different, but are frequently not _substantially_ different, i.e., the differences between generated solutions comprise only a few model elements. +You'll likely generate substantially different models by calling the generator multiple times with different [`-random-seed`](#generate-random-seed) values instead. + +The generator will create [numbered output files](#generate-output) for each solution found. +The generation is considered successful if it finds at least one solution, but may find less than the requested number of solutions if no more exist. +In this case, there will be fewer output files than requested. + +**Default value:** `1` diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/docker/index.md b/subprojects/docs/versioned_docs/version-0.1.0/learn/docker/index.md new file mode 100644 index 000000000..5120095da --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/docker/index.md @@ -0,0 +1,174 @@ +--- +SPDX-FileCopyrightText: 2024 The Refinery Authors +SPDX-License-Identifier: EPL-2.0 +autogenerated_sidebar_hidden: true +sidebar_position: 100 +sidebar_label: Docker +--- + +# Running in Docker + +:::note + +Refinery can run as a cloud-based _Graph Solver as a Service_ without local installation. +If you're just looking to try Refinery, our [online demo](https://refinery.services/) provides a seamless experience without installation. + +::: + +:::info + +Installing Refinery as a Docker container can support more advanced use cases, such as when generating models with more resources or a longer timeout. + +::: + +To generate larger models with a longer timeout, you can use our [Docker container](https://github.com/graphs4value/refinery/pkgs/container/refinery) on either `amd64` or `arm64` machines: + +```shell +docker run --rm -it -p 8888:8888 ghcr.io/graphs4value/refinery:0.1.0 +``` + +Once Docker pulls and starts the container, you can navigate to http://localhost:8888 to open the model generation interface and start editing. + +A [command-line interface (CLI)](cli) version of Refinery is also available as a Docker container. + +Alternatively, you can follow the [instructions to set up a local development environment](/develop/contributing) and compile and run Refinery from source. + +## Environmental variables + +The Docker container supports the following environmental variables to customize its behavior. +Customizing these variables should only be needed if you want to _increase resource limits_ or _expose your Refinery instance over the network_ for others. + +Notes for **local-only instances** are highlighted with the :arrow_right: arrow emoji. + +Important security notices for **public instances** are highlighted with the :warning: warning emoji. + +### Networking + +#### `REFINERY_LISTEN_HOST` + +Hostname to listen at for incoming HTTP connections. + +**Default value:** `0.0.0.0` (accepts connections on any IP address) + +#### `REFINERY_LISTEN_PORT` + +TCP port to listen at for incoming HTTP connections. + +Refinery doesn't support HTTPS connections out of the box, so there's no point in setting this to `443`. Use a [reverse proxy](https://en.wikipedia.org/wiki/Reverse_proxy) instead if you wish to expose Refinery to encrypted connections. + +If you change this value, don't forget to adjust the `-p 8888:8888` option of the `docker run` command to [expose](https://docs.docker.com/reference/cli/docker/container/run/#publish) the selected port. + +**Default value:** `8888` + +#### `REFINERY_PUBLIC_HOST` + +Publicly visible hostname of the Refinery instance. + +:arrow_right: For installations only accessed locally (i.e., `localhost:8888`) without any reverse proxy, you can safely leave this empty. + +:warning: You should set this to the publicly visible hostname of your Refinery instance if you wish to expose Refinery over the network. Most likely, this will be the hostname of a reverse proxy that terminates TLS connections. Our online demo sets this to [refinery.services](https://refinery.services/). + +**Default value:** _empty_ + +#### `REFINERY_PUBLIC_PORT` + +Publicly visible port of the Refinery instance. + +:arrow_right: For installations only accessed locally (i.e., `localhost:8888`), this value is ignored because `REFINERY_PUBLC_HOST` is not set. + +**Default value:** `443` + +#### `REFINERY_ALLOWED_ORIGINS` + +Comma-separated list of allowed origins for incoming WebSocket connections. If this variable is empty, all incoming WebSocket connections are accepted. + +:arrow_right: For installations only accessed locally (i.e., `localhost:8888`) without any reverse proxy, you can safely leave this empty. + +:warning: The value inferred from `REFINERY_PUBLIC_HOST` and `REFINERY_PUBLIC_PORT` should be suitable for instances exposed over the network. For security reasons, public instances should never leave this empty. + +**Default value:** equal to `REFINERY_PUBLIC_HOST:REFINERY_PUBLIC_PORT` if they are both set, _empty_ otherwise + +### Timeouts + +#### `REFINERY_SEMANTICS_TIMEOUT_MS` + +Timeout for partial model semantics calculation in milliseconds. + +:arrow_right: Increase this if you have a slower machine and the editor times out before showing a preview of your partial model in the _Graph_ or _Table_ views. + +:warning: Increasing this timeout may increase server load. Excessively large timeout may allow users to overload you server by entering extremely complex partial models. + +**Default value:** `1000` + +#### `REFINERY_SEMANTICS_WARMUP_TIMEOUT_MS` + +Timeout for partial model semantics calculation in milliseconds when the server first start. + +Due to various initialization tasks, the first partial model semantics generation may take longer the `REFINERY_SEMANTICS_TIMEOUT_MS` and display a timeout error. This setting increases the timeout for the first generation, leading to seamless use even after server start (especially in auto-scaling setups). + +**Default value:** equal to 2 × `REFINERY_SEMANTICS_TIMEOUT` + +#### `REFINERY_MODEL_GENERATION_TIMEOUT_SEC` + +Timeout for model generation in seconds. + +:arrow_right: Adjust this value if you're generating very large models (> 10000 nodes) and need more time to complete a generation. Note that some _unsatisfiable_ model generation problems cannot be detected by Refinery and will result in model generation running for an arbitrarily long time without producing any solution. + +:warning: Long running model generation will block a [_model generation thread_](#refinery_model_generation_thread_count). Try to balance the number of threads and the timeout to avoid exhausting system resources, but keep the wait time for a free model generation thread for users reasonably short. Auto-scaling to multiple instances may help with bursty demand. + +**Default value:** `600` (10 minutes) + +### Threading + +:arrow_right: If you only run a single model generation task at a time, you don't need to adjust these settings. + +:warning: Excessively large thread counts may overload the server. Make sure that _all_ Refinery threads can run at the same time to avoid thread starvation. + +#### `REFINERY_XTEXT_THREAD_COUNT` + +Number of threads used for non-blocking text editing operations. A value of `0` allows an _unlimited_ number of threads by running each semantics calculation in a new thread. + +**Default value:** `1` + +#### `REFINERY_XTEXT_LOCKING_THREAD_COUNT` + +Number of threads used for text editing operations that lock the document. A value of `0` allows an _unlimited_ number of threads by running each semantics calculation in a new thread. + +**Default value:** equal to `REFINERY_XTEXT_THREAD_COUNT` + +#### `REFINERY_XTEXT_SEMANTICS_THREAD_COUNT` + +Number of threads used for model semantics calculation. A value of `0` allows an _unlimited_ number of threads by running each semantics calculation in a new thread. + +Must be at least as large as `REFINERY_XTEXT_THREAD_COUNT`. + +**Default value:** equal to `REFINERY_XTEXT_THREAD_COUNT` + +#### `REFINERY_MODEL_GENERATION_THREAD_COUNT` + +Number of threads used for model semantics calculation. A value of `0` allows an _unlimited_ number of threads by running each semantics calculation in a new thread. + +:warning: Each model generation task may also demand a large amount of memory in addition to CPU time. + +**Default value:** equal to `REFINERY_XTEXT_THREAD_COUNT` + +### Libraries + +#### `REFINERY_LIBRARY_PATH` + +Modules (`.refinery` files) in this directory or colon-separated list of directories will be exposed to user via Refinery's `import` mechanism. + +:arrow_right: Use this in conjunction with the [mount volume (-v)](https://docs.docker.com/reference/cli/docker/container/run/#volume) option of `docker run` to work with multi-file projects in Refinery. + +:warning: Only expose files that you want to make public. It's best to expose a directory that contains nothing other than `.refinery` files to minimize potential information leaks. + +**Default value:** _empty_ (no directories are exposed) + +## Pre-release versions + +You can take advantage of the most recent code submitted to our repository by using the `latest` tag instead. + + +```shell +docker run --pull always --rm -it -p 8888:8888 ghcr.io/graphs4value/refinery:latest +``` diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/index.md b/subprojects/docs/versioned_docs/version-0.1.0/learn/index.md new file mode 100644 index 000000000..7f67fd863 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/index.md @@ -0,0 +1,11 @@ +--- +SPDX-FileCopyrightText: 2024 The Refinery Authors +SPDX-License-Identifier: EPL-2.0 +sidebar_position: 0 +--- + +# Introduction + +Various software and systems engineering scenarios rely on the systematic construction of consistent graph models. However, **automatically generating a diverse set of consistent graph models** for complex domain specifications is challenging. First, the graph generation problem must be specified with mathematical precision. Moreover, graph generation is a computationally complex task, which necessitates specialized logic solvers. + +**Refinery is an open-source software framework** for the automated synthesis of a diverse set of consistent domain-specific graph models. The framework offers an expressive high-level specification language using partial models to succinctly formulate a wide range of graph generation challenges. It also provides a modern cloud-based architecture for a scalable _Graph Solver as a Service,_ which uses logic reasoning rules to efficiently synthesize a diverse set of solutions to graph generation problems by partial model refinement. Applications include system-level architecture synthesis, test generation for modeling tools or traffic scenario synthesis for autonomous vehicles. diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/_category_.yml b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/_category_.yml new file mode 100644 index 000000000..a261ebf65 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/_category_.yml @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: 2024 The Refinery Authors +# +# SPDX-License-Identifier: EPL-2.0 + +position: 2 +label: Language reference +link: + type: generated-index + slug: /learn/language + description: Learn more about the Refinery partial modeling language! diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg new file mode 100644 index 000000000..197f4b48c --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg @@ -0,0 +1,227 @@ + + + + + + + + +v1 + +Vertex + + + + + + + + + +r1 + +Region + + + + + + + + + +region + + + + + + +t1 + +Transition + + + + + + + + + +outgoingTransition + + + + + + + + +t2 + +Transition + + + + + + + + + +outgoingTransition + + + + +incomingTransition + + + + + + + + +t3 + +Transition + + + + + + + + + + + +vertices + + + + + + +v2 + +Vertex + + + + + + + + + +vertices + + + + + + +region + + + + + + +incomingTransition + + + + + + + + + + +v3 + +Vertex + + + + + + + +incomingTransition + + + + + + +r2 + +Region + + + + + + + + + +region + + + + + + + + + + +target + + + + + + + + +vertices + + + + +outgoingTransition + + + + +target + + + + + +source + + + + +target + + + + +source + + + + +source + + \ No newline at end of file diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg new file mode 100644 index 000000000..fb9dd37de --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg @@ -0,0 +1,20 @@ + + + + + + + + + +invalid + +Region + + +State + + + + + \ No newline at end of file diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg new file mode 100644 index 000000000..b28c295a7 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + +v1 + +Vertex + + + + + + + + + +outgoingTransition + + + + + + +source + + + + + +t1 + +Transition + + + + + + + +source + + + + +outgoingTransition + + + + +t2 + +Transition + + + + + + + + +v2 + +Vertex + + +outgoingTransition::invalidMultiplicity + + + + + + + +t3 + +Transition + + + + + + + + + + + +source + + + + + + +outgoingTransition + + + + + + +t4 + +Transition + + + + + + + + + +v3 + +Vertex + + + +outgoingTransition::invalidMultiplicity + + + + + + + + +source + + + + + + +outgoingTransition + + + + + + +t5 + +Transition + + + + + + + + + +outgoingTransition + + + + + + +t6 + +Transition + + + + + + + + + +outgoingTransition + + + + + + +t7 + +Transition + + + + + + + + + +outgoingTransition + + + + + + +source + + + + + + +source + + + + + + +source + + + \ No newline at end of file diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg new file mode 100644 index 000000000..95ba8def7 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg @@ -0,0 +1,29 @@ + + + + + + + + +Region::new + +Region + + + + + + + + + + +State::new + + + + +State + + \ No newline at end of file diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg new file mode 100644 index 000000000..cdf365f0b --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg @@ -0,0 +1,38 @@ + + + + + + + + +Region::new + +Region + + + + + + + + + +State::new + +CompositeElement + + +Vertex + + +RegularState + + +State + + + + + + \ No newline at end of file diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg new file mode 100644 index 000000000..56a4d956c --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + +v1 + +Vertex + + + + + + + + +source + + + + +v2 + +Vertex + + + + + + + +t1 + +Transition + + + + + + + +outgoingTransition + + + + +target + + + + +incomingTransition + + \ No newline at end of file diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg new file mode 100644 index 000000000..81ab4a0cb --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg @@ -0,0 +1,24 @@ + + + + + + + + +Person::new + +Person + + + + + + + + + +friend + + + \ No newline at end of file diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg new file mode 100644 index 000000000..fac748159 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg @@ -0,0 +1,43 @@ + + + + + + + + +Vertex::new + +Vertex + + + + + + + + + +Transition::new + +Transition + + + + + + + + + +source + + + + + + +target + + + \ No newline at end of file diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/index.md b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/index.md new file mode 100644 index 000000000..18cbbf9f8 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/index.md @@ -0,0 +1,213 @@ +--- +SPDX-FileCopyrightText: 2024 The Refinery Authors +SPDX-License-Identifier: EPL-2.0 +description: Metamodeling in Refinery +sidebar_position: 0 +--- + +# Classes and references + +Refinery supports _metamodeling_ to describe the desired structure of generated models. + +The metamodeling facilities are inspired by object-oriented software and the [Eclipse Modeling Foundation](https://eclipse.dev/modeling/emf/) (EMF) Core, a lightweight framework for data models. +The textual syntax in Refinery for defining metamodels is largely compatible with [Xcore](https://wiki.eclipse.org/Xcore), a textual syntax for EMF metamodels. + +## Classes + +Classes are declared with the `class` keyword. + +Like in many programming languages, class members are specified between curly braces `{}`. +If a class has no members, the declaration may be terminated with a `.` instead. + +```refinery +% Class with no members. +class Region {} + +% Alternative syntax without curly braces. +class State. +``` + +By default, a _new object_ is added to the partial model to represent the instances of a class. +For example, the new objects `Region::new` and `State::new` represent potential instances of the classes `Region` and `State`, respectively: + +import NewObjectsSimple from './NewObjectsSimple.svg'; + + + +As you can see, no new objects represent potential nodes that are instanceof of both `Region` and `State`. +In fact, such instances are not permitted at all. +Each node must the instance of a _single most-specific class:_ + +import InvalidInstance from './InvalidInstance.svg'; + + + +### Inheritance + +Like in object-oriented programming languages, classes may declare _superclasses_ with the `extends` keyword. +The inheritance hierarchy may not contain any cycles (a class cannot be a superclass of itself), but _multiple inheritance_ is allowed. + +Classes that can't be instantiated directly (i.e., a subclass must be instantiated instead) can be marked with the `abstract` keyword. +Such classes do not have a _new object,_ since there are no direct instances to represent. + +```refinery +abstract class CompositeElement. +class Region. +abstract class Vertex. +abstract class RegularState extends Vertex. +class State extends RegularState, CompositeElement. +``` + +Notice that the new object `State::new` is an instance of `CompositeElement`, `Vertex`, `RegularState`, and `State` as well. + +import NewObjectsWithInheritance from './NewObjectsWithInheritance.svg'; + + + +## References + +The graph structure of model generated by Refinery is determined by the _references_ of the metamodel, which will appear as labeled edges between nodes (class instances). + +References are declared as class members by providing the _target type,_ and optional _multiplicity,_ and the name of the reference: + +```refinery +class Vertex. +class Transition { + Vertex[1] source + Vertex[1] target +} +``` + +import ReferencesSimple from './ReferencesSimple.svg'; + + + +You may add the `refers` keyword for compatibility with [Xcore](https://wiki.eclipse.org/Xcore). The following specification is equivalent: + +```refinery +class Vertex. +class Transition { + refers Vertex[1] source + refers Vertex[1] target +} +``` + +### Opposite constraints + +The `opposite` keywords specifies that two references are in an _opposite_ relationship, i.e., if one reference is present in a direction, the other must be present between the same nodes in the opposite direction. + +``` +class Vertex { + Transition[] outgoingTransition opposite source + Transition[] incomingTransition opposite target +} +class Transition { + Vertex[1] source opposite outgoingTransition + Vertex[1] target opposite incomingTransition +} +``` + +import ReferencesOppositeInstance from './ReferencesOppositeInstance.svg'; + + + +Opposites must be declared in pairs: it is a specification error to declare the `opposite` for one direction but not the other. + +Unlike in EMF, references that are the `opposite` of themselves are also supported. +These must always be present in both directions between two nodes. +Thus, they correspond to undirected graph edges. + +```refinery +class Person { + Person[] friend opposite friend +} +``` + +import ReferencesOppositeSelf from './ReferencesOppositeSelf.svg'; + + + +### Multiplicity + +_Multiplicity constraints_ can be provided after the reference type in square braces. +They specify how many _outgoing_ references should exist for any given instance of the class. + +:::info + +To control the number of _incoming_ references, add an `opposite` reference with multiplicity constraint. + +::: + +A multiplicity constraint is of the form `[n..m]`, where the non-negative integer `n` is the _lower_ bound of outgoing references, +and `m` is a positive integer or `*` corresponding to the _upper_ bound of outgoing references. +The value of `*` represent a reference with _unbounded_ upper multiplicity. + +If `n` = `m`, the shorter form `[n]` may be used. +The bound `[0..*]` may be abbreviated as `[]`. +If the multiplicity constraint is omitted, the bound `[0..1]` is assumed. + +--- + +In the following model, the node `v1` satisfies all multiplicity constraints of `outgoingTransition`. +The node `v2` violates the lower bound constraint, while `v3` violates the upper bound constraint. +All `Transition` instances satisfy the multiplicity constraints associated with `source`. + +```refinery +class Vertex { + Transition[2..3] outgoingTransition opposite source +} +class Transition { + Vertex[1] source opposite outgoingTransition +} +``` + +import MultiplicityConstraintsInstance from './MultiplicityConstraintsInstance.svg'; + + + +### Containment hierarchy + +To structure models and ensure their connectedness, Refinery supports _containment_ constraints. + +References may be marked as _containment_ references with the `contains` keyword. + +Classes that are the _target type_ of at least one _containment_ reference are considered `contained`. +An instance of a `contained` class must have exactly 1 incoming containment reference. +Instances of classes that are not `contained` must _not_ have any incoming containment references. + +Containment references have to form a _forest_, i.e., they must not contain any cycles. +The _roots_ of the forest are instances of classes that are not `contained`, while `contained` classes for the internal nodes and leaves of the trees. + +Opposites of _containment_ references have to be marked with the `container` keyword. +They must not specify any multiplicity constraint, since the multiplicity is already implied by the containment hierarchy. + +--- + +In the following model, the instances of `Region` are the roots of the containment hierarchy. +The classes `Vertex` are `Transition` are both considered `contained`. + +```refinery +class Region { + contains Vertex[] vertices opposite region +} + +class Vertex { + container Region region opposite vertices + contains Transition[] outgoingTransition opposite source + Transition[] incomingTransition opposite target +} + +class Transition { + container Vertex source opposite outgoingTransition + Vertex[1] target opposite incomingTransition +} +``` + +Containment edges are show with **thick** lines: + +import ContainmentInstance from './ContainmentInstance.svg'; + + + +Containment edges form must form a forest. +In contrast, non-containment references, such as `target`, may cross the containment hierarchy. diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg new file mode 100644 index 000000000..8ddc65f30 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg @@ -0,0 +1,20 @@ + + + + + + + + +v1 + + + +Vertex + + +State + + + + \ No newline at end of file diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg new file mode 100644 index 000000000..26b3d1fff --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg @@ -0,0 +1,99 @@ + + + + + + + + +Region::new + +Region + + + + + + + + + +State::new + +Vertex + + +State + + + + + + + + + +vertices + + + + + + + +v1 + +Vertex + + +State + + + + + + + + +r1 + +Region + + + + + + + +v2 + +Vertex + + + + + + + + +vertices + + + + + + + + + + + +vertices + + + + + +vertices + + \ No newline at end of file diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg new file mode 100644 index 000000000..2ab002bf5 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg @@ -0,0 +1,129 @@ + + + + + + + + + + +State::new + +Vertex + + +State + + + + + + + + + + + +r1 + +Region + + + + + + + + + +vertices + + + + + + +v1 + +Vertex + + +State + + + + + + + + + +vertices + + + + + + +r2 + +Region + + + + + + + + + +v2 + +Vertex + + +State + + + + + + + + + +vertices + + + + +v3 + +Vertex + + +State + + + + + + + + +r3 + +Region + + + + + + + + +vertices + + + \ No newline at end of file diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg new file mode 100644 index 000000000..a52325755 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg @@ -0,0 +1,81 @@ + + + + + + + + +node [1] + + + +exists + + + + + + + +equals + + + + + + +removable [0..1] + + + +exists + + + + + + + +equals + + + + + + +multi [1..*] + +exists + + + + + + + + + +equals + + + + + + +removableMulti [0..*] + +exists + + + + + + + + + +equals + + + \ No newline at end of file diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg new file mode 100644 index 000000000..440dfb192 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg @@ -0,0 +1,58 @@ + + + + + + + + +Region::new [0..70] + +Region + + + + + + + + + +State::new [0..120] + +Vertex + + +State + + + + + + + +Vertex::new [0..120] + +Vertex + + + + + + + + + +vertices + + + + + + + + +vertices + + + \ No newline at end of file diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg new file mode 100644 index 000000000..6f9880652 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg @@ -0,0 +1,58 @@ + + + + + + + + +Region::new [0..70] + +Region + + + + + + + + + +State::new [20] + +Vertex + + +State + + + + + + + +Vertex::new [30..100] + +Vertex + + + + + + + + + +vertices + + + + + + + + +vertices + + + \ No newline at end of file diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/index.md b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/index.md new file mode 100644 index 000000000..e366e9b81 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/index.md @@ -0,0 +1,256 @@ +--- +SPDX-FileCopyrightText: 2024 The Refinery Authors +SPDX-License-Identifier: EPL-2.0 +description: Four-valued logic abstraction +sidebar_position: 1 +--- + +# Partial modeling + +Refinery allow precisely expressing _unknown,_ _uncertain_ or even _contradictory_ information using [four-valued logic](https://en.wikipedia.org/wiki/Four-valued_logic#Belnap). +During model generation, unknown aspects of the partial model get _refined_ into concrete (true or false) facts until the generated model is completed, or a contradiction is reached. + +The _Belnap--Dunn four-valued logic_ supports the following truth values: + +* `true` values correspond to facts known about the model, e.g., that a node is the instance of a given class or there is a reference between two nodes. +* `false` values correspond to facts that are known not to hold, e.g., that a node is _not_ an instance of a given class or there is _no_ reference between two nodes. +* `unknown` values express uncertain properties and design decisions yet to be made. During model refinement, `unknown` values are gradually replaced with `true` and `false` values until a consistent and concrete model is derived. +* `error` values represent contradictions and validation failures in the model. One a model contains an error value, it can't be refined into a consistent model anymore. + +## Assertions + +_Assertions_ express facts about a partial model. An assertion is formed by a _symbol_ and an _argument list_ of _nodes_ in parentheses. +Possible symbols include [classes](../classes/#classes), [references](../classes/#references), and [predicates](../predicates). +Nodes appearing in the argument list are automatically added to the model. + +A _negative_ assertion with a `false` truth value is indicated by prefixing it with `!`. + +--- + +Consider the following metamodel: + +```refinery +class Region { + contains Vertex[] vertices +} +class Vertex. +class State extends Vertex. +``` + +Along with the following set of assertions: + +```refinery +Region(r1). +Vertex(v1). +Vertex(v2). +!State(v2). +vertices(r1, v1). +vertices(r1, v2). +!vertices(Region::new, v1). +!vertices(Region::new, v2). +``` + +import AssertionsExample from './AssertionsExample.svg'; + + + +It is `true` that `r1` is an instance of the class `Region`, while `v1` and `v2` are instances of the class `Vertex`. +We also assert that `v2` is _not_ an instance of the class `State`, but it is unknown whether `v1` is an instance of the class `State`. +Types that are `unknown` are shown in a lighter color and with an outlined icon. + +It is `true` that there is a `vertices` reference between `r1` and `v1`, as well as `r1` and `v2`, but there is no such reference from `Region::new` to the same vertices. +As no information is provided, it is `unknown` whether `State::new` is a vertex of any `Region` instance. +References that are `unknown` are shown in a lighter color and with a dashed line. + +### Propagation + +Refinery can automatically infer some facts about the partial model based on the provided assertions by information _propagation._ +The set of assertions in the [example above](#assertions) is equivalent to the following: + +```refinery +vertices(r1, v1). +vertices(r1, v2). +!State(v2). +``` + +By the type constraints of the `vertices` reference, Refinery can infer that `r1` is a `Region` instance and `v1` and `v2` are `Vertex` instances. +Since `State` is a subclass of `Vertex`, it is still unknown whether `v1` is a `State` instance, +but `v2` is explicitly forbidden from being such by the negative assertion `!State(v2)`. +We may omit `!vertices(Region::new, v1)` and `!vertices(Region::new, v2)`, since `v1` and `v2` may be a target of only one [containment](../classes/#containment-hierarchy) reference. + +Contradictory assertions lead to `error` values in the partial model: + +```refinery +State(v1). +!Vertex(v1). +``` + +import AssertionsError from './AssertionsError.svg'; + + + +### Default assertions + +Assertions marked with the `default` keyword have _lower priority_ that other assertions. +They may contain wildcard arguments `*` to specify information about _all_ nodes in the graph. +However, they can be overridden by more specific assertions that are not marked with the `default` keyword. + +--- + +To make sure that the reference `vertices` is `false` everywhere except where explicitly asserted, we may add a `default` assertion: + +```refinery +default !vertices(*, *). +vertices(r1, v1). +vertices(r2, v2). +vertices(r3, v3). +?vertices(r1, State::new). +``` + +import DefaultAssertions from './DefaultAssertions.svg'; + + + +We can prefix an assertion with `?` to explicitly assert that some fact about the partial model is `unknown`. +This is useful for overriding negative `default` assertions. + +## Multi-objects + +The special symbols `exists` and `equals` control the _number of graph nodes_ represented by an object in a partial model. + +By default, `exists` is `true` for all objects. +An object `o` with `?exists(o)` (i.e., `exists(o)` explicitly set to `unknown`) may be _removed_ from the partial model. +Therefore, it represents _at least 0_ graph nodes. + +By default, `equals` is `true` for its _diagonal_, i.e., we have `equals(o, o)` for all object `o`. +For off-diagonal pairs, i.e., `(p, q)` with `p` not equal to `q`, we always have `!equals(p, q)`: distinct objects can never be _merged._ +If we set a _diagonal_ entry to `unknown` by writing `?equals(o, o)`, the object `o` becomes a **multi-object:** it can be freely _split_ into multiple graph nodes. +Therefore, multi-objects represent _possibly more than 1_ graph nodes. + +| `exists(o)` | `equals(o, o)` | Number of nodes | Description | +|:-:|:-:|-:|:-| +| `true` | `true` | `1` | graph node | +| `unknown` | `true` | `0..1` | removable graph node | +| `true` | `unknown` | `1..*` | multi-object | +| `unknown` | `unknown` | `0..*` | removable multi-object | + +In the Refinery web UI, `?exists(o)` is represented with a _dashed_ border, while `?equals(o, o)` + +```refinery +node(node). + +node(removable). +?exists(removable). + +node(multi). +?equals(multi, multi). + +node(removableMulti). +?exists(removableMulti). +?equals(removableMulti, removableMulti). +``` + +import MultiObjects from './MultiObjects.svg'; + + + +import TuneIcon from '@material-icons/svg/svg/tune/baseline.svg'; +import LabelIcon from '@material-icons/svg/svg/label/baseline.svg'; +import LabelOutlineIcon from '@material-icons/svg/svg/label/outline.svg'; + +:::info + +You may use the  _filter panel_ icon in Refinery to toggle the visibility of special symbols like `exists` and `equals`. +You may either show  _both true and unknown_ values or  _just true_ values. +The _object scopes_ toggle will also show the number of graph nodes represented by an object in square brackets after its name, like in the figure above. +::: + +By default, a **new object** `C::new` is added for each non-`abstract` [class](../classes#classes) `C` with `?exists(C::new)` and `?equals(C::new, C::new)`. +This multi-object represents all potential instances of the class. +To assert that no new instances of `C` should be added to the generated model, you may write `!exists(C::new)`. + +You may use the `multi` keyword to quickly defined a (removable) multi-object: + +```refinery +multi removableMulti. +% This is equivalent to: +% ?exists(removableMulti). +% ?equals(removableMulti, removableMulti). +``` + +## Type scopes + +_Type scopes_ offer finer-grained control over the number of graph nodes in the generated model (as represented by the multi-objects) that `exists` or `equals` assertions. + +A _type scope constraint_ is formed by a unary symbol (a [class](../classes/#classes) or a [predicate](../predicates) with a single parameter) and _scope range._ +Ranges have a form similar to [multiplicity constraints](../classes#multiplicity): a range `n..m` indicates a lower bound of `n` and an upper bound of `m`. +While an upper bound of `*` indicates a possibly unbounded number of objects, generated models will always be finite. +Like for multiplicity constraints, the case `n..n` can be abbreviated as `n`. + +The number of nodes in the generated model can be controlled using the `node` special symbol. +For example, we may write the following to generate a model with at least 100 at and most 120 nodes: + +```refinery +scope node = 100..200. +``` + +A `scope` declaration may prescribe type scope constraint for any number of symbols, separated by `,`. +Multiple `scope` declarations are also permitted. +Multiple ranges provided for the same symbol will be intersected, i.e., they influence the generated model simultaneously. + +In other words, +``` +scope Region = 10, State = 80..120. +scope State = 100..150. +% Equivalent to: +scope Region = 10, State = 100..120. +``` + +The _object scopes_ option in the  _filter panel_ may help in exploring the effects of object scopes. + +--- + +Consider the example + +```refinery +class Region { + contains Vertex[] vertices +} +class Vertex. +class State extends Vertex. +scope node = 100..120, Vertex = 50..*. +``` + +import ObjectScopes from './ObjectScopes.svg'; + + + +Notice that Refinery could determine that there can be no more than 70 `Region` instances in the generated model, since at least 50 of the `100..120` nodes in the model must be `Vertex` instances. +However, since `State` is a subclass of `Vertex` (i.e., `State::new` is also an instance of `Vertex`), the range `50..*` is shared between both `Vertex::new` and `State::new`, resulting in both representing `0..120` nodes. +Nevertheless, every generated model will obey the scope constraint exactly, i.e., will have between 100 and 120 node, at least 50 of which are `Vertex` instances. + +By providing more information, Refinery can determine more precise ranges for multi-objects. +For example, we may strengthen the scope constraints as follows: + +```refinery +scope node = 100..120, Vertex = 50..*, State = 20. +``` + +import StrongerObjectScopes from './StrongerObjectScopes.svg'; + + + +### Incremental scopes + +We may specify an _incremental_ object scope with the `+=` operator to determine the number of new instances to be added to the model. +This is only allowed for symbol that are classes with no subclasses, as it directly influences the number of nodes represented by the corresponding `::new` object. + +For example, to ensure that between 5 and 7 `State` instances are added to the model, we may write: + +```refinery +State(s1). +State(s2). +scope State += 5..7. +``` + +Since `s1` and `s2` are also instances of the `State` class, the generated concrete model will have between 7 and 9 `State` instances altogether. diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg new file mode 100644 index 000000000..be9465b87 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg @@ -0,0 +1,76 @@ + + + + + + + + +transition1 + +Transition + + + + + + + + + +vertex1 + +Vertex + + + + + + + + + +source + + + + + + +vertex2 + +Vertex + + + + + + + + + +target + + + + + + +outgoingTransition + + + + + + + +incomingTransition + + + + +neighbors + + + + \ No newline at end of file diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/index.md b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/index.md new file mode 100644 index 000000000..261054c1d --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/index.md @@ -0,0 +1,284 @@ +--- +SPDX-FileCopyrightText: 2024 The Refinery Authors +SPDX-License-Identifier: EPL-2.0 +description: Model queries and model validation +sidebar_position: 2 +--- + +# Graph predicates + +Graph predicates are logic expressions that can be used to query for interesting model fragments, as well as for validating the consistency of models. They are evaluated on partial models according to [four-valued logic](../logic) semantics. + +Predicates in Refinery are written in [Disjunctive Normal Form](https://en.wikipedia.org/wiki/Disjunctive_normal_form) (DNF) as an _OR_ of _ANDs_, i.e., a _disjunction_ of _clauses_ formed as a _conjunction_ of positive or negated logic _literals._ +This matches the syntax and semantics of logical query languages, such as [Datalog](https://en.wikipedia.org/wiki/Datalog), and logical programming languages, such as [Prolog](https://en.wikipedia.org/wiki/Prolog). + +import Link from '@docusaurus/Link'; + +
+Example metamodel + +In the examples on this page, we will use the following metamodel as illustration: + +```refinery +abstract class CompositeElement { + contains Region[] regions +} + +class Region { + contains Vertex[] vertices opposite region +} + +abstract class Vertex { + container Region region opposite vertices + contains Transition[] outgoingTransition opposite source + Transition[] incomingTransition opposite target +} + +class Transition { + container Vertex source opposite outgoingTransition + Vertex[1] target opposite incomingTransition +} + +abstract class Pseudostate extends Vertex. + +abstract class RegularState extends Vertex. + +class Entry extends Pseudostate. + +class Exit extends Pseudostate. + +class Choice extends Pseudostate. + +class FinalState extends RegularState. + +class State extends RegularState, CompositeElement. + +class Statechart extends CompositeElement. +``` + +

+ Try in Refinery +

+ +
+ +[Assertions](../logic/#assertions) about graph predicates can prescribe where the predicate should (for positive assertions) or should not (for negative assertions) hold. +When generating consistent models + +## Atoms + +An _atom_ is formed by a _symbol_ and _argument list_ of variables. +Possible symbols include [classes](../classes/#classes), [references](../classes/#references), and [predicates](../predicates). +We may write a basic graph query as a conjunction (AND) of atoms. + +The `pred` keyword defines a graph predicate. After the _predicate name_, a _parameter list_ of variables is provided. The atoms of the graph predicate are written after the `<->` operator, and a full stop `.` terminates the predicate definition. + +The following predicate `entryInRegion` will match pairs of `Region` instances `r` and `Entry` instances `e` such that `e` is a vertex in `r`. + +```refinery +pred entryInRegion(r, e) <-> + Region(r), + vertices(r, e), + Entry(e). +``` + +We may write unary symbols that act as _parameter types_ directly in the parameter list. The following definition is equivalent to the previous one: + +```refinery +pred entryInRegion(Region r, Entry e) <-> + vertices(r, e). +``` + +import TableIcon from '@material-icons/svg/svg/table_chart/baseline.svg'; + +:::info + +You may display the result of graph predicate matching in the  _table view_ of the Refinery web UI. + +::: + +## Quantification + +Variables not appearing in the parameter list are _existentially quantified._ + +The following predicate matches `Region` instances with two entries: + +```refinery +pred multipleEntriesInRegion(Region r) <-> + entryInRegion(r, e1), + entryInRegion(r, e2), + e1 != e2. +``` + +Existentially quantified variables that appear only once in the predicate should be prefixed with `_`. This shows that the variable is intentionally used only once (as opposite to the second reference to the variable being omitted by mistake). + +```refinery +pred regionWithEntry(Region r) <-> + entryInRegion(r, _e). +``` + +Alternatively, you may use a single `_` whenever a variable occurring only once is desired. Different occurrences of `_` are considered distinct variables. + +```refinery +pred regionWithEntry(Region r) <-> + entryInRegion(r, _). +``` + +## Negation + +Negative literals are written by prefixing the corresponding atom with `!`. + +Inside negative literals, quantification is _universal:_ the literal matches if there is no assignment of the variables solely appearing in it that satisfies the corresponding atom. + +The following predicate matches `Region` instances that have no `Entry`: + +```refinery +pred regionWithoutEntry(Region r) <-> + !entryInRegion(r, _). +``` + +In a graph predicate, all parameter variables must be _positively bound,_ i.e., appear in at least one positive literal (atom). +Negative literals may further constrain the predicate match one it has been established by the positive literals. + +## Object equality + +The operators `a == b` and `a != b` correspond to the literals `equals(a, b)` and `!equals(a, b)`, respectively. +See the section about [multi-objects](../logic/#multi-objects) for more information about the `equals` symbol. + +## Transitive closure + +The `+` operator forms the [transitive closure](https://en.wikipedia.org/wiki/Transitive_closure) of symbols with exactly 2 parameters. +The transitive closure `r+(a, b)` holds if either `r(a, b)` is `true`, or there is a sequence of objects `c1`, `c2`, …, `cn` such that `r(a, c1)`, `r(c1, c2)`, `r(c2, c3)`, …, `r(cn, b)`. +In other words, there is a path labelled with `r` in the graph from `a` to `b`. + +Transitive closure may express queries about graph reachability: + +```refinery +pred neighbors(Vertex v1, Vertex v2) <-> + Transition(t), + source(t, v1), + target(t, v2). + +pred cycle(Vertex v) <-> + neighbors+(v, v). +``` + +## Disjunction + +Disjunction (OR) of _clauses_ formed by a conjunction (AND) of literals is denoted by `;`. + +```refinery +pred regionWithInvalidNumberOfEntries(Region r) <-> + !entryInRegion(r, _) +; + entryInRegion(r, e1), + entryInRegion(r, e2), + e1 != e2. +``` + +Every clause of a disjunction must bind every parameter variable of the graph predicate _positively._ +_Type annotations_ on parameter are applied in all clauses. +Therefore, the previous graph pattern is equivalent to the following: + +```refinery +pred regionWithInvalidNumberOfEntries(r) <-> + Region(r), + !entryInRegion(r, _) +; + Region(r), + entryInRegion(r, e1), + entryInRegion(r, e2), + e1 != e2. +``` + +## Derived features + +Graph predicates may act as _derived types_ and _references_ in metamodel. + +A graph predicate with exactly 1 parameters can be use as if it was a class: you may use it as a [_parameter type_](#atoms) in other graph patterns, as a _target type_ of a (non-containment) [reference](../classes/#references), or in a [_scope constraint_](../logic#type-scopes). + +_Derived references_ are graph predicates with exactly 2 parameters, which correspond the source and target node of the reference. + +import TuneIcon from '@material-icons/svg/svg/tune/baseline.svg'; +import LabelIcon from '@material-icons/svg/svg/label/baseline.svg'; +import LabelOutlineIcon from '@material-icons/svg/svg/label/outline.svg'; + +:::info + +You may use the  _filter panel_ icon in Refinery to toggle the visibility of graph predicates with 1 or 2 parameters. +You may either show  _both true and unknown_ values or  _just true_ values. + +::: + +--- + +For example, we may replace the reference `neighbors` in the class `Vertex`: + +```refinery +class Vertex { + Vertex[] neighbors +} +``` + +with the graph predicate `neighbors` as follows: + + +```refinery +class Vertex { + contains Transition[] outgoingTransition opposite source + Transition[] incomingTransition opposite target +} + +class Transition { + container Vertex source opposite outgoingTransition + Vertex[1] target opposite incomingTransition +} + +pred neighbors(Vertex v1, Vertex v2) <-> + Transition(t), + source(t, v1), + target(t, v2). +``` + +Since `neighbors` is now computed based on the `Transition` instances and their `source` and `target` references present in the model, the assertion + +```refinery +neighbors(vertex1, vertex2). +``` + +will only be satisfied if a corresponding node `transition1` is present in the generated model that also satisfies + +```refinery +Transition(transition1). +source(transition1, vertex1). +target(transition1, vertex2). +``` + +import DerivedFeature from './DerivedFeature.svg'; + + + +## Error predicates + +A common use-case for graph predicates is _model validation_, where a predicate highlights _errors_ in the model. +Such predicates are called _error predicates._ +In a consistent generated model, an error predicates should have no matches. + +You can declare error predicates with the `error` keyword: + +```refinery +error regionWithoutEntry(Region r) <-> + !entryInRegion(r, _). +``` + +This is equivalent to asserting that the error predicate is `false` everywhere: + +```refinery +pred regionWithoutEntry(Region r) <-> + !entryInRegion(r, _). + +!regionWithoutEntry(*). +``` diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/_category_.yml b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/_category_.yml new file mode 100644 index 000000000..fd563704e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/_category_.yml @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2024 The Refinery Authors +# +# SPDX-License-Identifier: EPL-2.0 + +position: 1 +label: Tutorials +link: + type: generated-index + slug: /learn/tutorials + title: Tutorial overview + description: Try Refinery in practical partial modeling challenges! diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig1.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig1.svg new file mode 100644 index 000000000..1e20393a0 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig1.svg @@ -0,0 +1,72 @@ + + + + + + + + +FileSystem::new + +FileSystem + + + + + + + + + +File::new + +File + + + + + + + + + +root + + + + + + +Dir::new + +File + + +Dir + + + + + + + + + +root + + + + + + +element + + + + + + +element + + + diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig1.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig1.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig1.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig2.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig2.svg new file mode 100644 index 000000000..6375bfd60 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig2.svg @@ -0,0 +1,145 @@ + + + + + + + + +FileSystem::new + +FileSystem + + + + + + + + + +File::new + +File + + + + + + + + + +root + + + + + + +Dir::new + +File + + +Dir + + + + + + + + + +root + + + + + + + +element + + + + +resources + +File + + +Dir + + + + + + + + + + + +element + + + + +root + + + + + + + + +element + + + + + + +element + + + + + + +img + +File + + +Dir + + + + + + + + + +element + + + + + + +element + + + + + + +element + + + diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig2.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig2.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig2.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig3.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig3.svg new file mode 100644 index 000000000..0d020a71f --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig3.svg @@ -0,0 +1,124 @@ + + + + + + + + +FileSystem::new + +FileSystem +exists + + + + + + + + + + + +File::new + +File +exists + + + + + + + + + +equals + + + + + + +Dir::new + +File +exists + + + + +Dir + + + + + + + + + + +equals + + + + + + +resources + +File +exists + + + + +Dir + + + + + + + +equals + + + + + + + + +equals + + + + + + +img + +File +exists + + + + +Dir + + + + + + + + + + +equals + + + diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig3.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig3.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig3.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig4.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig4.svg new file mode 100644 index 000000000..d6701bdde --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig4.svg @@ -0,0 +1,131 @@ + + + + + + + + +FileSystem::new + +FileSystem + + + + + + + + + +File::new + +File + + + + + + + + + +Dir::new + +File + + + +Dir + + + + + + +root + + + + + + + + + +resources + +File + + + +Dir + + + + + + + + +root + + + + + + +element + + + + + + + +element + + + + + + +img + +File +invalidContainer + + + + + + + + + +root + + + + + +element + + + + + + + +element + + + + + + + +element + + + diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig4.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig4.svg.license new file mode 100644 index 000000000..b80566a0e --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig4.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/index.md b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/index.md new file mode 100644 index 000000000..365d0fba2 --- /dev/null +++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/index.md @@ -0,0 +1,209 @@ +--- +SPDX-FileCopyrightText: 2023-2024 The Refinery Authors +SPDX-License-Identifier: EPL-2.0 +description: Introduction to classes, references, and error predicates +sidebar_position: 0 +sidebar_label: File system +--- + +# File system tutorial + +The goal of this tutorial is to give a brief overview of the partial modeling and model generation features of the Refinery framework. The running example will be the modeling of files, directories, and repositories. + +## Partial models + +### Types and relations + +- First, let us introduce some basic types: `Dir`, `File`, and `FileSystem`, along with the relations between them: `element` and `root`. There is a `scope` expression at the end, which we will ignore for now. + +```refinery +class FileSystem { + contains File[1] root +} + +class File. + +class Dir extends File { + contains File[] element +} + +scope node = 10. +``` + +import Link from '@docusaurus/Link'; + +

+ Try in Refinery +

+ +- Notice that the syntax is essentially identical to [Xcore](https://wiki.eclipse.org/Xcore). +- Review the partial model visualization. You should get something like this: + +import Fig1 from './fig1.svg'; + + + +- Add some statements about a partial model: + +```refinery +class FileSystem { + contains File[1] root +} + +class File. + +class Dir extends File { + contains File[] element +} + +Dir(resources). +element(resources, img). +File(img). + +scope node = 10. +``` + +import Fig2 from './fig2.svg'; + + + +### Partial models + +- Notice that the instance model elements are coexisting with ```::new``` nodes representing the prototypes of newly created objects. + +- Check the disabled `equals` and `exist` predicates. check the visual annotation of those predicates in the visualization (dashed line, shadow). + +import Fig3 from './fig3.svg'; + + + +### Information merging + +- For the object `img`, we didn't specify if it is a directory or not. Therefore, it will typically be a folder. + +- If we want to state that img is not a directory, we need to a negative statement: + +```refinery +!Dir(img). +``` + +- Statements are merged with respect to the refinement relation of 4-valued logic. + +- If we add, a statement both negatively and positively, it will create an inconsistency: + +```refinery +element(resources, img). +!element(resources, img). +``` + +- Inconsistent models parts in a partial model typically make the problem trivially unsatisfiable. + +import Fig4 from './fig4.svg'; + + + +- However, the model can be saved if the inconsistent part may not exist... + +```refinery +!File(File::new). +``` + +### Default values + +- A large amount of statements can be expressed by using `*`. +- The `default` keyword defines lower priority statements that need to be considered unless other statement specifies otherwise. No information merging is happening. + +## Constraints + +Let's extend the metamodel with a new class `SymLink`: + +```refinery +class FileSystem { + contains File[1] root +} + +class File. + +class Dir extends File { + contains File[0..10] element +} + +class SymLink extends File { + File[1] target +} + +Dir(resources). +element(resources, img). +element(resources, link). +target(link, img). + +scope node = 10. +``` + +- Add some simple constraints: + +```refinery +% Simple constraints: +pred hasReference(f) <-> target(_, f). +error pred selfLoop(s) <-> target(s, s). +target(x,x). +``` + +- There are no empty directories in a git repository, so let's forbid them! + +```refinery +error pred emptyDir(d) <-> Dir(d), !element(d,_). +``` + +- End result: + +```refinery +class FileSystem { + contains File[1] root +} + +class File. + +class Dir extends File { + contains File[0..10] element +} + +class SymLink extends File { + File[1] target +} + +Dir(resources). +element(resources, img). +!Dir(img). +element(resources, link). +target(link,img). + +% Simple constraints: +pred hasReference(f) <-> target(_, f). +error pred selfLoop(s) <-> target(s, s). + +% Object equality with ==: +error pred emptyDir(d) <-> Dir(d), !element(d, _). +pred importantFile(f) <-> target(l1, f), target(l2, f), l1 != l2. + +% Transitive closure, and +pred containsFile(fs, file) <-> + FileSystem(fs), + root(fs, file) +; + FileSystem(fs), + root(fs, rootDir), + element+(rootDir, file). + +% Predicate reuse +error conflictBetweenTwoFileSystem(fs1, fs2, l, t) <-> + containsFile(fs1, l), + containsFile(fs2, t), + fs1 != fs2, + target(l, t). + +scope node = 40..50, FileSystem = 2, importantFile = 1..*. +``` diff --git a/subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json b/subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json new file mode 100644 index 000000000..2f70ab5e2 --- /dev/null +++ b/subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json @@ -0,0 +1,14 @@ +{ + "learnSidebar": [ + { + "type": "autogenerated", + "dirName": "learn" + } + ], + "developSidebar": [ + { + "type": "autogenerated", + "dirName": "develop" + } + ] +} diff --git a/subprojects/docs/versions.json b/subprojects/docs/versions.json new file mode 100644 index 000000000..7b999c750 --- /dev/null +++ b/subprojects/docs/versions.json @@ -0,0 +1,3 @@ +[ + "0.1.0" +] From 8ae860a12a320ce24ff7c6128115291f85c5aa69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20Marussy?= Date: Sat, 27 Jul 2024 02:55:05 +0200 Subject: [PATCH 7/9] refactor(docs): no logo in header on small screens The logo visually clashes with the hamburger menu button. Now the logo only appears in the hamburger menu and in the landing page hero title. --- subprojects/docs/src/css/custom.css | 6 ++++++ subprojects/docs/src/pages/index.module.css | 22 +++++++++++++++++++++ subprojects/docs/src/pages/index.tsx | 12 ++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/subprojects/docs/src/css/custom.css b/subprojects/docs/src/css/custom.css index 62369e496..58fd7cd9a 100644 --- a/subprojects/docs/src/css/custom.css +++ b/subprojects/docs/src/css/custom.css @@ -80,6 +80,12 @@ code { --ifm-navbar-shadow: var(--ifm-global-shadow-lw) !important; } +@media (max-width: 996px) { + .navbar__inner .navbar__logo { + display: none; + } +} + .button, .navbar__link, .footer__link-item { text-transform: uppercase; font-variation-settings: 'wdth' 87.5; diff --git a/subprojects/docs/src/pages/index.module.css b/subprojects/docs/src/pages/index.module.css index 367b78ed4..653d96e4f 100644 --- a/subprojects/docs/src/pages/index.module.css +++ b/subprojects/docs/src/pages/index.module.css @@ -39,3 +39,25 @@ padding: 4rem 0; background: var(--ifm-background-surface-color); } + +.title { + display: flex; + align-items: center; +} + +.title__text { + display: block; +} + +.logo { + display: none; + height: 1.25em; + width: 1.25em; + margin-right: 0.5rem; +} + +@media (max-width: 996px) { + .logo { + display: block; + } +} diff --git a/subprojects/docs/src/pages/index.tsx b/subprojects/docs/src/pages/index.tsx index ff0da38ba..5eb994f10 100644 --- a/subprojects/docs/src/pages/index.tsx +++ b/subprojects/docs/src/pages/index.tsx @@ -5,6 +5,7 @@ */ import Link from '@docusaurus/Link'; +import { useColorMode } from '@docusaurus/theme-common'; import Layout from '@theme/Layout'; import clsx from 'clsx'; @@ -14,11 +15,20 @@ import Features from '@site/src/components/Features'; import UseCases from '@site/src/components/UseCases'; import Video from '@site/src/components/Video'; +function Logo() { + const { colorMode } = useColorMode(); + const logoPath = colorMode === 'dark' ? '/logo-dark.svg' : '/logo.svg'; + return ; +} + function Hero() { return (
-

Refinery

+

+ + Refinery +

An efficient graph solver for generating well-formed models

From 6112c8d8633dc467fe4fa30077751d75690369d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20Marussy?= Date: Mon, 29 Jul 2024 17:11:41 +0200 Subject: [PATCH 8/9] docs: @InjectWithRefinery --- subprojects/docs/src/docs/develop/java.md | 13 +++++-------- subprojects/docs/src/docs/develop/javadoc.md | 2 +- .../versioned_docs/version-0.1.0/develop/javadoc.md | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/subprojects/docs/src/docs/develop/java.md b/subprojects/docs/src/docs/develop/java.md index d19306e62..8bf796a59 100644 --- a/subprojects/docs/src/docs/develop/java.md +++ b/subprojects/docs/src/docs/develop/java.md @@ -286,29 +286,26 @@ Instead, you should use Xtext's [dependency injection](https://eclipse.dev/Xtext -Afterwards, you can use the `@ExtendWith`, `@InjectWith`, and `@Inject` annotations to set up your unit test. +The test fixtures for `refinery-language` include the `@InjectWithRefinery` [composed annotation](https://junit.org/junit5/docs/current/user-guide/#writing-tests-meta-annotations) to simplify Xtext injector configuration. +You can use this annotation in conjunction with `@Inject` annotations to set up your unit test. ```java package org.example; import com.google.inject.Inject; -import org.eclipse.xtext.testing.InjectWith; -import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import tools.refinery.generator.GeneratorResult; import tools.refinery.generator.ModelGeneratorFactory; import tools.refinery.generator.ProblemLoader; -import tools.refinery.language.tests.ProblemInjectorProvider; +import tools.refinery.language.tests.InjectWithRefinery; import java.io.IOException; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.*; // highlight-start -@ExtendWith(InjectionExtension.class) -@InjectWith(ProblemInjectorProvider.class) +@InjectWithRefinery // highlight-end class ExampleTest { // highlight-start diff --git a/subprojects/docs/src/docs/develop/javadoc.md b/subprojects/docs/src/docs/develop/javadoc.md index 97a44d36b..b85825b58 100644 --- a/subprojects/docs/src/docs/develop/javadoc.md +++ b/subprojects/docs/src/docs/develop/javadoc.md @@ -7,7 +7,7 @@ sidebar_position: 998 # Javadoc -Here you can find API documentation for Refinery components automatically generated by Javadoc. We recommend reading the [Programming guide](/develop/java/) first to understand how to use these components. +Here you can find API documentation for Refinery components automatically generated by Javadoc. We recommend reading the [Programming guide](../java/) first to understand how to use these components. # Refinery diff --git a/subprojects/docs/versioned_docs/version-0.1.0/develop/javadoc.md b/subprojects/docs/versioned_docs/version-0.1.0/develop/javadoc.md index dd165c007..9a488bd7e 100644 --- a/subprojects/docs/versioned_docs/version-0.1.0/develop/javadoc.md +++ b/subprojects/docs/versioned_docs/version-0.1.0/develop/javadoc.md @@ -7,7 +7,7 @@ sidebar_position: 998 # Javadoc -Here you can find API documentation for Refinery components automatically generated by Javadoc. We recommend reading the [Programming guide](/develop/java/) first to understand how to use these components. +Here you can find API documentation for Refinery components automatically generated by Javadoc. We recommend reading the [Programming guide](../java/) first to understand how to use these components. # Refinery From 9fdd5e02e91c34691541bf8b9f6994007a49ef50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20Marussy?= Date: Mon, 29 Jul 2024 17:19:57 +0200 Subject: [PATCH 9/9] chore(docs): fix versions license --- subprojects/docs/sidebars.ts | 6 ++++++ .../versioned_sidebars/version-0.1.0-sidebars.json.license | 3 +++ subprojects/docs/versions.json.license | 3 +++ 3 files changed, 12 insertions(+) create mode 100644 subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json.license create mode 100644 subprojects/docs/versions.json.license diff --git a/subprojects/docs/sidebars.ts b/subprojects/docs/sidebars.ts index ddd838b3a..293487677 100644 --- a/subprojects/docs/sidebars.ts +++ b/subprojects/docs/sidebars.ts @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { SidebarsConfig } from '@docusaurus/plugin-content-docs'; export default { diff --git a/subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json.license b/subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json.license new file mode 100644 index 000000000..cfe957067 --- /dev/null +++ b/subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json.license @@ -0,0 +1,3 @@ +Copyright (c) 2024 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/docs/versions.json.license b/subprojects/docs/versions.json.license new file mode 100644 index 000000000..2891afa31 --- /dev/null +++ b/subprojects/docs/versions.json.license @@ -0,0 +1,3 @@ +Copyright (c) 2024 The Refinery Authors + +SPDX-License-Identifier: CC0-1.0