diff --git a/pages/docs/changelog.md b/pages/docs/changelog.md index 138ad9b2fae4140e8d172635202a089d12d7e4b6..1fcc26bc7052a700a13b934b0e4c2ee32bb2b6d9 100644 --- a/pages/docs/changelog.md +++ b/pages/docs/changelog.md @@ -7,6 +7,7 @@ ### Development Changes - Bugfix: "error: variable handler is already defined" when using multiple protocols [#58](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/58) +- Bugfix: Inherited components of a type can not be chosen as port targets [#59](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/59) ## 1.0.0 diff --git a/pages/docs/compiler.md b/pages/docs/compiler.md index 130020ad63b878c254bfa8f8fc6db82e71a3414d..ccff6d6c05f7544ff75caeda4f19a6f87c765ad9 100644 --- a/pages/docs/compiler.md +++ b/pages/docs/compiler.md @@ -75,8 +75,9 @@ However, depending on the selected protocols and/or used features, additional de - Required runtime dependencies: _none_ - Required options for RelAST compiler: _none_ - Required options for JastAdd: - - `--incremental` - - `--tracing=flush` + - `--incremental=param` (enable incremental evaluation) + - `--tracing=flush` (enable tracing of events) + - `--cache=all` (set all attributes to be cached) - Remarks: - Other (additional) values passed to those two options must be equal (e.g., `--incremental=param` passed to RagConnect must be also passed to JastAdd) - Other values besides `flush` can be added to `--tracing` diff --git a/ragconnect.base/src/main/jastadd/Analysis.jrag b/ragconnect.base/src/main/jastadd/Analysis.jrag index 79f37b38b3839982f784f1dd79b094a663aaa921..e1ec0f28977748a6b2d896c0c82c58c116f0081c 100644 --- a/ragconnect.base/src/main/jastadd/Analysis.jrag +++ b/ragconnect.base/src/main/jastadd/Analysis.jrag @@ -98,10 +98,22 @@ aspect Analysis { eq ContextFreeTypePortTarget.hasAttributeResetMethod() = false; // --- needProxyToken --- - syn boolean TokenComponent.needProxyToken() = !getDependencySourceDefinitionList().isEmpty() || - getTokenPortTargetList().stream() - .map(PortTarget::containingPortDefinition) - .anyMatch(PortDefinition::shouldNotResetValue); + syn boolean TokenComponent.needProxyToken() { + for (Component comp : meOwnedByOthers()) { + TokenComponent tokenComp = comp.asTokenComponent(); + if (tokenComp.directNeedProxyToken()) { + return true; + } + } + return directNeedProxyToken(); + } + + syn boolean TokenComponent.directNeedProxyToken() { + return !getDependencySourceDefinitionList().isEmpty() || + getTokenPortTargetList().stream() + .map(PortTarget::containingPortDefinition) + .anyMatch(PortDefinition::shouldNotResetValue); + } // --- effectiveUsedAt --- coll Set<PortDefinition> MappingDefinition.effectiveUsedAt() diff --git a/ragconnect.base/src/main/jastadd/Intermediate.jadd b/ragconnect.base/src/main/jastadd/Intermediate.jadd index 97cc5148e9e6901d8a1b23cc965adbd57a7c0d44..60fe493797256563e7bfca17a6c35d341acfb8c0 100644 --- a/ragconnect.base/src/main/jastadd/Intermediate.jadd +++ b/ragconnect.base/src/main/jastadd/Intermediate.jadd @@ -358,7 +358,14 @@ aspect MustacheRagConnect { eq ContextFreeTypePortTarget.impliedPortDefinitions() { JastAddList<PortDefinition> result = super.impliedPortDefinitions(); PortDefinition containingDef = containingPortDefinition(); + Set<TypeComponent> seenTypeComponents = new HashSet<>(); for (TypeComponent typeComponent : getTypeDecl().occurencesInProductionRules()) { + // only process each once + if (seenTypeComponents.contains(typeComponent)) { + continue; + } + seenTypeComponents.add(typeComponent); + List<PortDefinition> defsForTypeComponent = lookupGivenTypePortDefinitions(typeComponent); if (!defsForTypeComponent.stream().anyMatch(containingDef::matchesType)) { // there is no user-defined port definition for this typeComponent yet @@ -398,7 +405,7 @@ aspect MustacheReceiveAndSendAndHandleUri { syn String PortDefinition.connectParameterName() = "uriString"; syn String PortDefinition.disconnectMethodName() { - // if both (send and receive) are defined for an port, ensure methods with different names + // if both (send and receive) are defined for a port, ensure methods with different names String extra; if (getPortTarget().isTokenPortTarget()) { extra = lookupTokenPortDefinitions(token()).size() > 1 ? uniqueSuffix() : ""; @@ -625,17 +632,27 @@ containingPortDefinition().getIndexBasedListAccess()); aspect MustacheTokenComponent { // === TokenComponent === + syn java.util.List<DependencyDefinition> TokenComponent.dependencySourceDefinitionsOwnedByMe() { + java.util.List<DependencyDefinition> result = new java.util.ArrayList<>(); + result.addAll(getDependencySourceDefinitions()); + for (Component comp : meOwnedByOthers()) { + result.addAll(comp.asTokenComponent().getDependencySourceDefinitions()); + } + return result; + } + syn String TokenComponent.internalName() = needProxyToken() ? ragconnect().internalRagConnectPrefix() + getName() : getName(); syn String TokenComponent.javaType() = effectiveJavaTypeUse().prettyPrint(); syn PortDefinition TokenComponent.normalTokenSendDef() { - for (PortTarget target : getTokenPortTargetList()) { - if (target.isTokenPortTarget() && target.containingPortDefinition().shouldNotResetValue()) { - return target.containingPortDefinition(); + for (Component comp : meOwnedByOthers()) { + PortDefinition maybeResult = comp.asTokenComponent().directNormalTokenSendDef(); + if (maybeResult != null) { + return maybeResult; } } - return null; + return directNormalTokenSendDef(); } syn String TokenComponent.parentTypeName() = containingTypeDecl().getName(); @@ -663,6 +680,16 @@ aspect MustacheTokenComponent { } // > see MustacheSend for updateMethodName, writeMethodName + + // === attributes needed for computing above ones === + syn PortDefinition TokenComponent.directNormalTokenSendDef() { + for (PortTarget target : getTokenPortTargetList()) { + if (target.isTokenPortTarget() && target.containingPortDefinition().shouldNotResetValue()) { + return target.containingPortDefinition(); + } + } + return null; + } } aspect MustacheTypeDecl { @@ -670,6 +697,10 @@ aspect MustacheTypeDecl { syn String TypeComponent.parentTypeName() = containingTypeDecl().getName(); syn String TypeComponent.disconnectMethodName() { List<TypePortTarget> typePortTargets = getTypePortTargets(); + while (typePortTargets.isEmpty() && getRealComponent() != null) { + // get for "real" typeComponent (of super-type) and use its getTypePortTargets + typePortTargets = getRealComponent().asTypeComponent().getTypePortTargets(); + } if (typePortTargets.isEmpty()) { return "MISSING_PORT"; } else { @@ -681,7 +712,7 @@ aspect MustacheTypeDecl { syn List<TypeComponent> TypeDecl.occurencesInProductionRules() { List<TypeComponent> result = new ArrayList<>(); for (TypeDecl typeDecl : program().typeDecls()) { - for (Component comp : typeDecl.getComponentList()) { + for (Component comp : typeDecl.allComponentsAsOwnedByMe()) { if (comp.isTypeComponent() && comp.asTypeComponent().getTypeDecl().equals(this)) { result.add(comp.asTypeComponent()); } diff --git a/ragconnect.base/src/main/jastadd/IntermediateToYAML.jrag b/ragconnect.base/src/main/jastadd/IntermediateToYAML.jrag index c247d9d0a69b2f548e04fe69adcf35620fd69255..5aa0f8c5fb1d007e6dfaca1b0fd70cf7566d810b 100644 --- a/ragconnect.base/src/main/jastadd/IntermediateToYAML.jrag +++ b/ragconnect.base/src/main/jastadd/IntermediateToYAML.jrag @@ -181,7 +181,8 @@ aspect IntermediateToYAML { result.put("DependencySourceDefinitions" , dependencySourceDefinitions); result.put("javaType" , javaType()); - result.put("normalTokenSendDef" , normalTokenSendDef().toYAML()); + result.put("normalTokenSendDef" , ASTNode.<PortDefinition,MappingElement>safeCall( + normalTokenSendDef(), def -> def.toYAML())); result.put("parentTypeName" , parentTypeName()); return result; } @@ -209,6 +210,29 @@ aspect IntermediateToYAML { protected StringElement ASTNode.sanitizeValueForYAML(String value) { return StringElement.of(value.replace("\"" , "\\\"").replace("\n" , "\\n")); } + + // FIXME: remove refine once fixed in upstream mustache + refine Printing protected StringBuilder KeyValuePair.prettyPrint(StringBuilder sb, boolean printIndent, String indent) { + if (printIndent) sb.append(indent); + if (isCollapsed()) { + sb.append("\""); + } + sb.append(getKey()); + if (isCollapsed()) { + sb.append("\""); + } + sb.append(":"); + if (getValue() == null) { + sb.append(" null"); + } else if (getValue().isComplexElement() && !getValue().isEmpty() && !getValue().isCollapsed()) { + sb.append("\n"); + getValue().prettyPrint(sb, true, indent + PRINT_INDENT); + } else { + sb.append(" "); + getValue().prettyPrint(sb, false, indent); + } + return sb; + } } aspect Navigation { diff --git a/ragconnect.base/src/main/jastadd/NameResolution.jrag b/ragconnect.base/src/main/jastadd/NameResolution.jrag index e470430d8f5d355cd90d4e79503ee431de994a18..18a35f7295b63225f7695c045604df713950fbe0 100644 --- a/ragconnect.base/src/main/jastadd/NameResolution.jrag +++ b/ragconnect.base/src/main/jastadd/NameResolution.jrag @@ -27,7 +27,7 @@ aspect RagConnectNameResolution { java.util.List<PortDefinition> result = new java.util.ArrayList<>(); for (PortDefinition def : onlyGiven ? givenPortDefinitionList() : allPortDefinitionList()) { PortTarget target = def.getPortTarget(); - if (target.isTypePortTarget() && target.asTypePortTarget().getType().equals(type)) { + if (target.isTypePortTarget() && target.asTypePortTarget().getType().matches(type) && target.asTypePortTarget().getType().containingTypeDecl().equals(type.containingTypeDecl())) { result.add(def); } } @@ -91,7 +91,7 @@ aspect RagConnectNameResolution { String childTypeName = id.substring(dotIndex + 1); TypeDecl type = program().resolveTypeDecl(parentTypeName); // iterate over components and find the matching typeComponent - for (Component comp : type.getComponentList()) { + for (Component comp : type.allComponentsAsOwnedByMe()) { if (comp.isTypeComponent() && comp.getName().equals(childTypeName)) { return comp.asTypeComponent(); } @@ -114,7 +114,7 @@ aspect RagConnectNameResolution { String childTypeName = id.substring(dotIndex + 1); TypeDecl type = program().resolveTypeDecl(parentTypeName); // iterate over components and find the matching typeComponent - for (Component comp : type.getComponentList()) { + for (Component comp : type.allComponentsAsOwnedByMe()) { if (comp.getName().equals(childTypeName)) { return comp; } @@ -138,7 +138,7 @@ aspect RagConnectNameResolution { String tokenName = id.substring(dotIndex + 1); TypeDecl type = program().resolveTypeDecl(typeName); // iterate over components and find the matching tokenComponent - for (Component comp : type.getComponentList()) { + for (Component comp : type.allComponentsAsOwnedByMe()) { if (comp.isTokenComponent() && comp.getName().equals(tokenName)) { return comp.asTokenComponent(); } @@ -175,10 +175,63 @@ aspect RagConnectNameResolution { } return null; } +} +aspect RelastNameResolution { syn boolean Role.matches(String typeName, String roleName) = false; eq NavigableRole.matches(String typeName, String roleName) { return getType().getName().equals(typeName) && getName().equals(roleName); } + /** Returns all components including inherited ones */ + syn List<Component> TypeDecl.allComponents() { + List<Component> result = new ArrayList<>(); + getComponentList().forEach(result::add); + if (hasSuperType()) { + mergeComponentLists(result, getSuperType().allComponents()); + } + return result; + } + + /** Returns same as allComponents() but for each component the containingTypeDecl will compute to this component */ + syn nta JastAddList<Component> TypeDecl.allComponentsAsOwnedByMe() { + JastAddList<Component> result = new JastAddList<>(); + for (Component comp : allComponents()) { + Component newComp = comp.treeCopy(); + newComp.setRealComponent(comp); + result.add(newComp); + } + return result; + } + + public static void TypeDecl.mergeComponentLists(List<Component> subTypeResult, List<Component> superTypeResult) { + for (int i = superTypeResult.size() - 1; i >= 0; i--) { + Component superTypeComponent = superTypeResult.get(i); + if (subTypeResult.stream().noneMatch(subTypeComponent -> subTypeComponent.matches(superTypeComponent))) { + subTypeResult.add(0, superTypeComponent); + } + } + } + + syn boolean Component.matches(Component other) = false; + eq TokenComponent.matches(Component other) { + if (!other.isTokenComponent()) { return false; } + return getName().equals(other.getName()) && (getJavaTypeUse() == null && other.asTokenComponent().getJavaTypeUse() == null || getJavaTypeUse().prettyPrint().equals(other.asTokenComponent().getJavaTypeUse().prettyPrint())); + } + eq TypeComponent.matches(Component other) = matchesNameAndType(other); + eq NormalComponent.matches(Component other) { + if (!other.isTypeComponent() || !other.asTypeComponent().isNormalComponent()) { return false; } + return super.matches(other); + } + eq ListComponent.matches(Component other) { + if (!other.isTypeComponent() || !other.asTypeComponent().isListComponent()) { return false; } + return super.matches(other); + } + eq OptComponent.matches(Component other) { + if (!other.isTypeComponent() || !other.asTypeComponent().isOptComponent()) { return false; } + return super.matches(other); + } + syn boolean TypeComponent.matchesNameAndType(Component other) { + return getName().equals(other.getName()) && getTypeDecl().equals(other.asTypeComponent().getTypeDecl()); + } } diff --git a/ragconnect.base/src/main/jastadd/Navigation.jrag b/ragconnect.base/src/main/jastadd/Navigation.jrag index 8b23c000fb8136af504d6dc452a42d5dd6ae82ca..ffa4596e54ca19295c1c886eecf2276e38e16497 100644 --- a/ragconnect.base/src/main/jastadd/Navigation.jrag +++ b/ragconnect.base/src/main/jastadd/Navigation.jrag @@ -175,4 +175,25 @@ aspect RagConnectNavigation { // --- isListComponent --- (defined in PP, but only on TypeComponent) syn boolean Component.isListComponent() = false; + + syn Set<Component> Component.meOwnedByOthers() { + Set<Component> result = new HashSet<>(); + Deque<TypeDecl> todo = new ArrayDeque<>(); + todo.add(containingTypeDecl()); + while (!todo.isEmpty()) { + TypeDecl current = todo.pop(); + todo.addAll(current.getSubTypeList()); + + for (Component comp : current.allComponentsAsOwnedByMe()) { + if (comp.matches(this)) { + result.add(comp); + } + } + } + return result; + } +} +aspect RelastNavigation { + // TODO only token-components from the nta "owned-by-me" must be added to Program.allTokenComponents + //TypeDecl contributes nta allComponentsAsOwnedByMe() to Program.allTokenComponents(); } diff --git a/ragconnect.base/src/main/jastadd/RagConnect.relast b/ragconnect.base/src/main/jastadd/RagConnect.relast index 7282bb3fda5771c3b1ea87a4bfae235c3950b640..60f08491d4ac721c4dedb7a37280b1cdcdd385a3 100644 --- a/ragconnect.base/src/main/jastadd/RagConnect.relast +++ b/ragconnect.base/src/main/jastadd/RagConnect.relast @@ -47,3 +47,5 @@ Configuration ::= <EvaluationCounter:boolean> <ExperimentalJastAdd329:boolean>; rel Configuration.RootNode -> TypeDecl ; + +rel Component.RealComponent? -> Component ; diff --git a/ragconnect.base/src/main/jastadd/Util.jadd b/ragconnect.base/src/main/jastadd/Util.jadd index 174f8cdb9e40db6f3b1edef519b31daade2c1bba..7c8f5e65ac603fdc38a49b1961286b566f097b54 100644 --- a/ragconnect.base/src/main/jastadd/Util.jadd +++ b/ragconnect.base/src/main/jastadd/Util.jadd @@ -4,6 +4,9 @@ aspect Util { if (s.isEmpty()) return ""; return Character.toUpperCase(s.charAt(0)) + s.substring(1); } + static <Input,Result> Result ASTNode.safeCall(Input input, java.util.function.Function<Input, Result> function) { + return input == null ? null : function.apply(input); + } protected T JastAddList.firstChild() { return getChild(0); } protected T JastAddList.lastChild() { return getChild(getNumChild() - 1); } diff --git a/ragconnect.base/src/main/resources/RagConnectObserver.mustache b/ragconnect.base/src/main/resources/RagConnectObserver.mustache index 24ed61c1a2ed6ceabec733b45f76a51eeae5f1e0..4414782b3dd1eb6e3e93ce4fe90fc35462416b79 100644 --- a/ragconnect.base/src/main/resources/RagConnectObserver.mustache +++ b/ragconnect.base/src/main/resources/RagConnectObserver.mustache @@ -119,8 +119,8 @@ aspect RagConnectObserver { } RagConnectObserverStartEntry startEntry = startEntries.peekFirst(); if (node == startEntry.node && - attribute == startEntry.attributeString && - value == startEntry.flushIncToken) { + java.util.Objects.equals(attribute, startEntry.attributeString) && + java.util.Objects.equals(value, startEntry.flushIncToken)) { // create a copy of the queue to avoid entering this again causing an endless recursion RagConnectObserverEntry[] entriesToProcess = entryQueue.toArray(new RagConnectObserverEntry[entryQueue.size()]); entryQueue.clear(); diff --git a/ragconnect.base/src/main/resources/ragconnect.mustache b/ragconnect.base/src/main/resources/ragconnect.mustache index 5bd0166a46bb6f02be2df10a2bfd26b9cc63d508..a38ac9b3151227d92dffb83365eef8a1ab27f49e 100644 --- a/ragconnect.base/src/main/resources/ragconnect.mustache +++ b/ragconnect.base/src/main/resources/ragconnect.mustache @@ -91,6 +91,7 @@ aspect RagConnect { mayHaveRewrite(); // check if --incremental is active Object checkIncremental = inc_throwAway_visited; + {{! TODO maybe check for something like _ragconnect_mqttHandler_computed to see if --cache=all }} {{/configIncrementalOptionActive}} } } diff --git a/ragconnect.base/src/main/resources/tokenComponent.mustache b/ragconnect.base/src/main/resources/tokenComponent.mustache index 12238f4428bf2ef79951015425cf45285cca624b..3d90c34b5ccfd3844972ef535844f8b042e1e3f1 100644 --- a/ragconnect.base/src/main/resources/tokenComponent.mustache +++ b/ragconnect.base/src/main/resources/tokenComponent.mustache @@ -1,6 +1,6 @@ public {{parentTypeName}} {{parentTypeName}}.set{{Name}}({{javaType}} value) { set{{internalName}}(value); - {{#DependencySourceDefinitions}} + {{#dependencySourceDefinitionsOwnedByMe}} for ({{targetParentTypeName}} target : get{{internalRelationPrefix}}TargetList()) { {{#targetPortDefinition}} if (target.{{updateMethodName}}()) { @@ -8,7 +8,7 @@ public {{parentTypeName}} {{parentTypeName}}.set{{Name}}({{javaType}} value) { } {{/targetPortDefinition}} } - {{/DependencySourceDefinitions}} + {{/dependencySourceDefinitionsOwnedByMe}} {{#normalTokenSendDef}} if ({{updateMethodName}}()) { {{writeMethodName}}(); diff --git a/ragconnect.tests/src/test/01-input/passing/README.md b/ragconnect.tests/src/test/01-input/passing/README.md new file mode 100644 index 0000000000000000000000000000000000000000..15afc42285d80e7e205777af6333162100cb36dd --- /dev/null +++ b/ragconnect.tests/src/test/01-input/passing/README.md @@ -0,0 +1,4 @@ +# Passing + +This directory contains use case for RagConnect, that just need to pass compiling (no dedicated Java test). + diff --git a/ragconnect.tests/src/test/01-input/passing/inheritance/Test.connect b/ragconnect.tests/src/test/01-input/passing/inheritance/Test.connect new file mode 100644 index 0000000000000000000000000000000000000000..3b4690cd05838159de6e5c9be0e47808ca25f9ab --- /dev/null +++ b/ragconnect.tests/src/test/01-input/passing/inheritance/Test.connect @@ -0,0 +1,18 @@ +// both directions for SpecialA1 +send SpecialA1.Input ; +receive SpecialA1.Input ; + +send SpecialA1.Many ; +receive SpecialA1.Many ; + +send SpecialA1.Maybe ; +receive SpecialA1.Maybe ; + +send SpecialA1.B ; +receive SpecialA1.B ; + +// only one direction for SpecialA2 +send SpecialA2.Input ; +send SpecialA2.Many ; +send SpecialA2.Maybe ; +send SpecialA2.B ; diff --git a/ragconnect.tests/src/test/01-input/passing/inheritance/Test.relast b/ragconnect.tests/src/test/01-input/passing/inheritance/Test.relast new file mode 100644 index 0000000000000000000000000000000000000000..7de55c8642cbb307c615e7abe78833f7e7ff1a6c --- /dev/null +++ b/ragconnect.tests/src/test/01-input/passing/inheritance/Test.relast @@ -0,0 +1,5 @@ +Root ::= A ; +A ::= <Input:String> Many:B* [Maybe:B] B ; +SpecialA1 : A ; +SpecialA2 : A ; +B ::= ; diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AbstractCompilerTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AbstractCompilerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..002f9815f9eb09b8b41d533c9f01d6dcc5f0e98f --- /dev/null +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AbstractCompilerTest.java @@ -0,0 +1,61 @@ +package org.jastadd.ragconnect.tests; + +import org.jastadd.ragconnect.tests.utils.TestUtils; +import org.junit.jupiter.api.BeforeEach; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.jastadd.ragconnect.tests.utils.TestUtils.readFile; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * TODO: Add description. + * + * @author rschoene - Initial contribution + */ +public abstract class AbstractCompilerTest extends RagConnectTest { + + protected abstract String getDirectoryName(); + + protected String getOutputDirectory() { + return TestUtils.OUTPUT_DIRECTORY_PREFIX + getDirectoryName(); + } + + protected abstract String getDefaultGrammarName(); + + @BeforeEach + public void ensureOutputDirectory() { + File outputDirectory = new File(getOutputDirectory()); + assertTrue((outputDirectory.exists() && outputDirectory.isDirectory()) || outputDirectory.mkdir()); + } + + protected Path test(String inputDirectoryName, int expectedReturnValue, String rootNode, String... connectNames) throws IOException { + String grammarFile = Paths.get(inputDirectoryName, getDefaultGrammarName() + ".relast").toString(); + List<String> connectFiles = Arrays.stream(connectNames) + .map(connectName -> Paths.get(inputDirectoryName,connectName + ".connect").toString()) + .collect(Collectors.toList()); + return TestUtils.runCompiler(grammarFile, connectFiles, rootNode, + getDirectoryName(), expectedReturnValue); + } + + protected void testAndCompare(String inputDirectoryName, String expectedName, String rootNode, String... connectNames) throws IOException { + Path outPath = test(inputDirectoryName, 1, rootNode, connectNames); + + final String startOfErrorsPattern = "Errors:\n"; + String out = readFile(outPath, Charset.defaultCharset()); + assertThat(out).contains(startOfErrorsPattern); + out = out.substring(out.indexOf(startOfErrorsPattern) + startOfErrorsPattern.length()); + + TestUtils.assertLinesMatch(getDirectoryName(), expectedName, out); + + logger.info("ragconnect for " + expectedName + " returned:\n{}", out); + } +} diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ErrorsTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ErrorsTest.java index 4853b6a7e62f6e71878b37700a72fe2515655200..7f7e0cb2fbbaba2f6ce2995d9866ba10142e2039 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ErrorsTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ErrorsTest.java @@ -1,65 +1,33 @@ package org.jastadd.ragconnect.tests; -import org.jastadd.ragconnect.tests.utils.TestUtils; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import java.io.File; import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.jastadd.ragconnect.tests.utils.TestUtils.readFile; -import static org.junit.jupiter.api.Assertions.assertTrue; /** * Test error messages. * * @author rschoene - Initial contribution */ -public class ErrorsTest extends RagConnectTest { - - private static final String ERROR_DIRECTORY = "errors/"; - private static final String OUTPUT_DIRECTORY = TestUtils.OUTPUT_DIRECTORY_PREFIX + ERROR_DIRECTORY; +public class ErrorsTest extends AbstractCompilerTest { - private static final String DEFAULT_GRAMMAR_NAME = "Errors"; + @Override + protected String getDirectoryName() { + return "errors"; + } - @BeforeAll - public static void createOutputDirectory() { - File outputDirectory = new File(OUTPUT_DIRECTORY); - assertTrue((outputDirectory.exists() && outputDirectory.isDirectory()) || outputDirectory.mkdir()); + @Override + protected String getDefaultGrammarName() { + return "Errors"; } @Test void testStandardErrors() throws IOException { - test("Standard", "A", "Standard"); + testAndCompare(getDirectoryName(), "Standard", "A", "Standard"); } @Test void testTwoPartsErrors() throws IOException { - test("Part", "A", "Part1", "Part2"); + testAndCompare(getDirectoryName(), "Part", "A", "Part1", "Part2"); } - - @SuppressWarnings("SameParameterValue") - private void test(String expectedName, String rootNode, String... connectNames) throws IOException { - String grammarFile = ERROR_DIRECTORY + DEFAULT_GRAMMAR_NAME + ".relast"; - List<String> connectFiles = Arrays.stream(connectNames) - .map(connectName -> ERROR_DIRECTORY + connectName + ".connect") - .collect(Collectors.toList()); - Path outPath = TestUtils.runCompiler(grammarFile, connectFiles, rootNode, ERROR_DIRECTORY, 1); - - final String startOfErrorsPattern = "Errors:\n"; - String out = readFile(outPath, Charset.defaultCharset()); - assertThat(out).contains(startOfErrorsPattern); - out = out.substring(out.indexOf(startOfErrorsPattern) + startOfErrorsPattern.length()); - - TestUtils.assertLinesMatch(ERROR_DIRECTORY, expectedName, out); - - logger.info("ragconnect for " + expectedName + " returned:\n{}", out); - } - } diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java index 81d2817c5a1453bb82728edb496d1b41042d31ba..dfac385b2161cf4fff96aad5d05985438a03f242 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java @@ -150,7 +150,10 @@ public class JavaTest extends RagConnectTest { model.ragconnectJavaPush(TOPIC_RECEIVE_NTA, ExposingASTNode.INSTANCE.aToBytes(createA("12"))); checker.put(TOPIC_RECEIVE_NTA, "12").check(); + } + @AfterEach + public void printEvaluationSummary() { System.out.println(model.ragconnectEvaluationCounterSummary()); } diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/PassingTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/PassingTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5829c21d41f8ee0601a5218c33bb3d7165ae457b --- /dev/null +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/PassingTest.java @@ -0,0 +1,33 @@ +package org.jastadd.ragconnect.tests; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Paths; + +/** + * Use cases that just need to compile. + * + * @author rschoene - Initial contribution + */ +public class PassingTest extends AbstractCompilerTest { + @Override + protected String getDirectoryName() { + return "passing"; + } + + @Override + protected String getDefaultGrammarName() { + return "Test"; + } + + protected void run(String inputDirectoryName, String rootNode) throws IOException { + super.test(Paths.get("passing", inputDirectoryName).toString(), + 0, rootNode, getDefaultGrammarName()); + } + + @Test + public void testInheritance() throws IOException { + run("inheritance", "Root"); + } +}