Skip to content
Snippets Groups Projects
Commit 48db4dcf authored by René Schöne's avatar René Schöne
Browse files

Resolve "Inherited components of a type can not be chosen as port targets"

parent dcc63fc3
Branches
No related tags found
2 merge requests!39Version 1.1.0,!37Resolve "Inherited components of a type can not be chosen as port targets"
Showing
with 304 additions and 63 deletions
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
### Development Changes ### 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: "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 ## 1.0.0
......
...@@ -75,8 +75,9 @@ However, depending on the selected protocols and/or used features, additional de ...@@ -75,8 +75,9 @@ However, depending on the selected protocols and/or used features, additional de
- Required runtime dependencies: _none_ - Required runtime dependencies: _none_
- Required options for RelAST compiler: _none_ - Required options for RelAST compiler: _none_
- Required options for JastAdd: - Required options for JastAdd:
- `--incremental` - `--incremental=param` (enable incremental evaluation)
- `--tracing=flush` - `--tracing=flush` (enable tracing of events)
- `--cache=all` (set all attributes to be cached)
- Remarks: - 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 (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` - Other values besides `flush` can be added to `--tracing`
......
...@@ -98,10 +98,22 @@ aspect Analysis { ...@@ -98,10 +98,22 @@ aspect Analysis {
eq ContextFreeTypePortTarget.hasAttributeResetMethod() = false; eq ContextFreeTypePortTarget.hasAttributeResetMethod() = false;
// --- needProxyToken --- // --- needProxyToken ---
syn boolean TokenComponent.needProxyToken() = !getDependencySourceDefinitionList().isEmpty() || syn boolean TokenComponent.needProxyToken() {
getTokenPortTargetList().stream() for (Component comp : meOwnedByOthers()) {
.map(PortTarget::containingPortDefinition) TokenComponent tokenComp = comp.asTokenComponent();
.anyMatch(PortDefinition::shouldNotResetValue); if (tokenComp.directNeedProxyToken()) {
return true;
}
}
return directNeedProxyToken();
}
syn boolean TokenComponent.directNeedProxyToken() {
return !getDependencySourceDefinitionList().isEmpty() ||
getTokenPortTargetList().stream()
.map(PortTarget::containingPortDefinition)
.anyMatch(PortDefinition::shouldNotResetValue);
}
// --- effectiveUsedAt --- // --- effectiveUsedAt ---
coll Set<PortDefinition> MappingDefinition.effectiveUsedAt() coll Set<PortDefinition> MappingDefinition.effectiveUsedAt()
......
...@@ -358,7 +358,14 @@ aspect MustacheRagConnect { ...@@ -358,7 +358,14 @@ aspect MustacheRagConnect {
eq ContextFreeTypePortTarget.impliedPortDefinitions() { eq ContextFreeTypePortTarget.impliedPortDefinitions() {
JastAddList<PortDefinition> result = super.impliedPortDefinitions(); JastAddList<PortDefinition> result = super.impliedPortDefinitions();
PortDefinition containingDef = containingPortDefinition(); PortDefinition containingDef = containingPortDefinition();
Set<TypeComponent> seenTypeComponents = new HashSet<>();
for (TypeComponent typeComponent : getTypeDecl().occurencesInProductionRules()) { for (TypeComponent typeComponent : getTypeDecl().occurencesInProductionRules()) {
// only process each once
if (seenTypeComponents.contains(typeComponent)) {
continue;
}
seenTypeComponents.add(typeComponent);
List<PortDefinition> defsForTypeComponent = lookupGivenTypePortDefinitions(typeComponent); List<PortDefinition> defsForTypeComponent = lookupGivenTypePortDefinitions(typeComponent);
if (!defsForTypeComponent.stream().anyMatch(containingDef::matchesType)) { if (!defsForTypeComponent.stream().anyMatch(containingDef::matchesType)) {
// there is no user-defined port definition for this typeComponent yet // there is no user-defined port definition for this typeComponent yet
...@@ -398,7 +405,7 @@ aspect MustacheReceiveAndSendAndHandleUri { ...@@ -398,7 +405,7 @@ aspect MustacheReceiveAndSendAndHandleUri {
syn String PortDefinition.connectParameterName() = "uriString"; syn String PortDefinition.connectParameterName() = "uriString";
syn String PortDefinition.disconnectMethodName() { 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; String extra;
if (getPortTarget().isTokenPortTarget()) { if (getPortTarget().isTokenPortTarget()) {
extra = lookupTokenPortDefinitions(token()).size() > 1 ? uniqueSuffix() : ""; extra = lookupTokenPortDefinitions(token()).size() > 1 ? uniqueSuffix() : "";
...@@ -625,17 +632,27 @@ containingPortDefinition().getIndexBasedListAccess()); ...@@ -625,17 +632,27 @@ containingPortDefinition().getIndexBasedListAccess());
aspect MustacheTokenComponent { aspect MustacheTokenComponent {
// === TokenComponent === // === 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.internalName() = needProxyToken() ? ragconnect().internalRagConnectPrefix() + getName() : getName();
syn String TokenComponent.javaType() = effectiveJavaTypeUse().prettyPrint(); syn String TokenComponent.javaType() = effectiveJavaTypeUse().prettyPrint();
syn PortDefinition TokenComponent.normalTokenSendDef() { syn PortDefinition TokenComponent.normalTokenSendDef() {
for (PortTarget target : getTokenPortTargetList()) { for (Component comp : meOwnedByOthers()) {
if (target.isTokenPortTarget() && target.containingPortDefinition().shouldNotResetValue()) { PortDefinition maybeResult = comp.asTokenComponent().directNormalTokenSendDef();
return target.containingPortDefinition(); if (maybeResult != null) {
return maybeResult;
} }
} }
return null; return directNormalTokenSendDef();
} }
syn String TokenComponent.parentTypeName() = containingTypeDecl().getName(); syn String TokenComponent.parentTypeName() = containingTypeDecl().getName();
...@@ -663,6 +680,16 @@ aspect MustacheTokenComponent { ...@@ -663,6 +680,16 @@ aspect MustacheTokenComponent {
} }
// > see MustacheSend for updateMethodName, writeMethodName // > 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 { aspect MustacheTypeDecl {
...@@ -670,6 +697,10 @@ aspect MustacheTypeDecl { ...@@ -670,6 +697,10 @@ aspect MustacheTypeDecl {
syn String TypeComponent.parentTypeName() = containingTypeDecl().getName(); syn String TypeComponent.parentTypeName() = containingTypeDecl().getName();
syn String TypeComponent.disconnectMethodName() { syn String TypeComponent.disconnectMethodName() {
List<TypePortTarget> typePortTargets = getTypePortTargets(); 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()) { if (typePortTargets.isEmpty()) {
return "MISSING_PORT"; return "MISSING_PORT";
} else { } else {
...@@ -681,7 +712,7 @@ aspect MustacheTypeDecl { ...@@ -681,7 +712,7 @@ aspect MustacheTypeDecl {
syn List<TypeComponent> TypeDecl.occurencesInProductionRules() { syn List<TypeComponent> TypeDecl.occurencesInProductionRules() {
List<TypeComponent> result = new ArrayList<>(); List<TypeComponent> result = new ArrayList<>();
for (TypeDecl typeDecl : program().typeDecls()) { for (TypeDecl typeDecl : program().typeDecls()) {
for (Component comp : typeDecl.getComponentList()) { for (Component comp : typeDecl.allComponentsAsOwnedByMe()) {
if (comp.isTypeComponent() && comp.asTypeComponent().getTypeDecl().equals(this)) { if (comp.isTypeComponent() && comp.asTypeComponent().getTypeDecl().equals(this)) {
result.add(comp.asTypeComponent()); result.add(comp.asTypeComponent());
} }
......
...@@ -181,7 +181,8 @@ aspect IntermediateToYAML { ...@@ -181,7 +181,8 @@ aspect IntermediateToYAML {
result.put("DependencySourceDefinitions" , dependencySourceDefinitions); result.put("DependencySourceDefinitions" , dependencySourceDefinitions);
result.put("javaType" , javaType()); result.put("javaType" , javaType());
result.put("normalTokenSendDef" , normalTokenSendDef().toYAML()); result.put("normalTokenSendDef" , ASTNode.<PortDefinition,MappingElement>safeCall(
normalTokenSendDef(), def -> def.toYAML()));
result.put("parentTypeName" , parentTypeName()); result.put("parentTypeName" , parentTypeName());
return result; return result;
} }
...@@ -209,6 +210,29 @@ aspect IntermediateToYAML { ...@@ -209,6 +210,29 @@ aspect IntermediateToYAML {
protected StringElement ASTNode.sanitizeValueForYAML(String value) { protected StringElement ASTNode.sanitizeValueForYAML(String value) {
return StringElement.of(value.replace("\"" , "\\\"").replace("\n" , "\\n")); 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 { aspect Navigation {
......
...@@ -27,7 +27,7 @@ aspect RagConnectNameResolution { ...@@ -27,7 +27,7 @@ aspect RagConnectNameResolution {
java.util.List<PortDefinition> result = new java.util.ArrayList<>(); java.util.List<PortDefinition> result = new java.util.ArrayList<>();
for (PortDefinition def : onlyGiven ? givenPortDefinitionList() : allPortDefinitionList()) { for (PortDefinition def : onlyGiven ? givenPortDefinitionList() : allPortDefinitionList()) {
PortTarget target = def.getPortTarget(); 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); result.add(def);
} }
} }
...@@ -91,7 +91,7 @@ aspect RagConnectNameResolution { ...@@ -91,7 +91,7 @@ aspect RagConnectNameResolution {
String childTypeName = id.substring(dotIndex + 1); String childTypeName = id.substring(dotIndex + 1);
TypeDecl type = program().resolveTypeDecl(parentTypeName); TypeDecl type = program().resolveTypeDecl(parentTypeName);
// iterate over components and find the matching typeComponent // 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)) { if (comp.isTypeComponent() && comp.getName().equals(childTypeName)) {
return comp.asTypeComponent(); return comp.asTypeComponent();
} }
...@@ -114,7 +114,7 @@ aspect RagConnectNameResolution { ...@@ -114,7 +114,7 @@ aspect RagConnectNameResolution {
String childTypeName = id.substring(dotIndex + 1); String childTypeName = id.substring(dotIndex + 1);
TypeDecl type = program().resolveTypeDecl(parentTypeName); TypeDecl type = program().resolveTypeDecl(parentTypeName);
// iterate over components and find the matching typeComponent // iterate over components and find the matching typeComponent
for (Component comp : type.getComponentList()) { for (Component comp : type.allComponentsAsOwnedByMe()) {
if (comp.getName().equals(childTypeName)) { if (comp.getName().equals(childTypeName)) {
return comp; return comp;
} }
...@@ -138,7 +138,7 @@ aspect RagConnectNameResolution { ...@@ -138,7 +138,7 @@ aspect RagConnectNameResolution {
String tokenName = id.substring(dotIndex + 1); String tokenName = id.substring(dotIndex + 1);
TypeDecl type = program().resolveTypeDecl(typeName); TypeDecl type = program().resolveTypeDecl(typeName);
// iterate over components and find the matching tokenComponent // 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)) { if (comp.isTokenComponent() && comp.getName().equals(tokenName)) {
return comp.asTokenComponent(); return comp.asTokenComponent();
} }
...@@ -175,10 +175,63 @@ aspect RagConnectNameResolution { ...@@ -175,10 +175,63 @@ aspect RagConnectNameResolution {
} }
return null; return null;
} }
}
aspect RelastNameResolution {
syn boolean Role.matches(String typeName, String roleName) = false; syn boolean Role.matches(String typeName, String roleName) = false;
eq NavigableRole.matches(String typeName, String roleName) { eq NavigableRole.matches(String typeName, String roleName) {
return getType().getName().equals(typeName) && getName().equals(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());
}
} }
...@@ -175,4 +175,25 @@ aspect RagConnectNavigation { ...@@ -175,4 +175,25 @@ aspect RagConnectNavigation {
// --- isListComponent --- (defined in PP, but only on TypeComponent) // --- isListComponent --- (defined in PP, but only on TypeComponent)
syn boolean Component.isListComponent() = false; 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();
} }
...@@ -47,3 +47,5 @@ Configuration ::= ...@@ -47,3 +47,5 @@ Configuration ::=
<EvaluationCounter:boolean> <EvaluationCounter:boolean>
<ExperimentalJastAdd329:boolean>; <ExperimentalJastAdd329:boolean>;
rel Configuration.RootNode -> TypeDecl ; rel Configuration.RootNode -> TypeDecl ;
rel Component.RealComponent? -> Component ;
...@@ -4,6 +4,9 @@ aspect Util { ...@@ -4,6 +4,9 @@ aspect Util {
if (s.isEmpty()) return ""; if (s.isEmpty()) return "";
return Character.toUpperCase(s.charAt(0)) + s.substring(1); 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.firstChild() { return getChild(0); }
protected T JastAddList.lastChild() { return getChild(getNumChild() - 1); } protected T JastAddList.lastChild() { return getChild(getNumChild() - 1); }
......
...@@ -119,8 +119,8 @@ aspect RagConnectObserver { ...@@ -119,8 +119,8 @@ aspect RagConnectObserver {
} }
RagConnectObserverStartEntry startEntry = startEntries.peekFirst(); RagConnectObserverStartEntry startEntry = startEntries.peekFirst();
if (node == startEntry.node && if (node == startEntry.node &&
attribute == startEntry.attributeString && java.util.Objects.equals(attribute, startEntry.attributeString) &&
value == startEntry.flushIncToken) { java.util.Objects.equals(value, startEntry.flushIncToken)) {
// create a copy of the queue to avoid entering this again causing an endless recursion // create a copy of the queue to avoid entering this again causing an endless recursion
RagConnectObserverEntry[] entriesToProcess = entryQueue.toArray(new RagConnectObserverEntry[entryQueue.size()]); RagConnectObserverEntry[] entriesToProcess = entryQueue.toArray(new RagConnectObserverEntry[entryQueue.size()]);
entryQueue.clear(); entryQueue.clear();
......
...@@ -91,6 +91,7 @@ aspect RagConnect { ...@@ -91,6 +91,7 @@ aspect RagConnect {
mayHaveRewrite(); mayHaveRewrite();
// check if --incremental is active // check if --incremental is active
Object checkIncremental = inc_throwAway_visited; Object checkIncremental = inc_throwAway_visited;
{{! TODO maybe check for something like _ragconnect_mqttHandler_computed to see if --cache=all }}
{{/configIncrementalOptionActive}} {{/configIncrementalOptionActive}}
} }
} }
......
public {{parentTypeName}} {{parentTypeName}}.set{{Name}}({{javaType}} value) { public {{parentTypeName}} {{parentTypeName}}.set{{Name}}({{javaType}} value) {
set{{internalName}}(value); set{{internalName}}(value);
{{#DependencySourceDefinitions}} {{#dependencySourceDefinitionsOwnedByMe}}
for ({{targetParentTypeName}} target : get{{internalRelationPrefix}}TargetList()) { for ({{targetParentTypeName}} target : get{{internalRelationPrefix}}TargetList()) {
{{#targetPortDefinition}} {{#targetPortDefinition}}
if (target.{{updateMethodName}}()) { if (target.{{updateMethodName}}()) {
...@@ -8,7 +8,7 @@ public {{parentTypeName}} {{parentTypeName}}.set{{Name}}({{javaType}} value) { ...@@ -8,7 +8,7 @@ public {{parentTypeName}} {{parentTypeName}}.set{{Name}}({{javaType}} value) {
} }
{{/targetPortDefinition}} {{/targetPortDefinition}}
} }
{{/DependencySourceDefinitions}} {{/dependencySourceDefinitionsOwnedByMe}}
{{#normalTokenSendDef}} {{#normalTokenSendDef}}
if ({{updateMethodName}}()) { if ({{updateMethodName}}()) {
{{writeMethodName}}(); {{writeMethodName}}();
......
# Passing
This directory contains use case for RagConnect, that just need to pass compiling (no dedicated Java test).
// 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 ;
Root ::= A ;
A ::= <Input:String> Many:B* [Maybe:B] B ;
SpecialA1 : A ;
SpecialA2 : A ;
B ::= ;
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);
}
}
package org.jastadd.ragconnect.tests; 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 org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException; 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. * Test error messages.
* *
* @author rschoene - Initial contribution * @author rschoene - Initial contribution
*/ */
public class ErrorsTest extends RagConnectTest { public class ErrorsTest extends AbstractCompilerTest {
private static final String ERROR_DIRECTORY = "errors/";
private static final String OUTPUT_DIRECTORY = TestUtils.OUTPUT_DIRECTORY_PREFIX + ERROR_DIRECTORY;
private static final String DEFAULT_GRAMMAR_NAME = "Errors"; @Override
protected String getDirectoryName() {
return "errors";
}
@BeforeAll @Override
public static void createOutputDirectory() { protected String getDefaultGrammarName() {
File outputDirectory = new File(OUTPUT_DIRECTORY); return "Errors";
assertTrue((outputDirectory.exists() && outputDirectory.isDirectory()) || outputDirectory.mkdir());
} }
@Test @Test
void testStandardErrors() throws IOException { void testStandardErrors() throws IOException {
test("Standard", "A", "Standard"); testAndCompare(getDirectoryName(), "Standard", "A", "Standard");
} }
@Test @Test
void testTwoPartsErrors() throws IOException { 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);
}
} }
...@@ -150,7 +150,10 @@ public class JavaTest extends RagConnectTest { ...@@ -150,7 +150,10 @@ public class JavaTest extends RagConnectTest {
model.ragconnectJavaPush(TOPIC_RECEIVE_NTA, ExposingASTNode.INSTANCE.aToBytes(createA("12"))); model.ragconnectJavaPush(TOPIC_RECEIVE_NTA, ExposingASTNode.INSTANCE.aToBytes(createA("12")));
checker.put(TOPIC_RECEIVE_NTA, "12").check(); checker.put(TOPIC_RECEIVE_NTA, "12").check();
}
@AfterEach
public void printEvaluationSummary() {
System.out.println(model.ragconnectEvaluationCounterSummary()); System.out.println(model.ragconnectEvaluationCounterSummary());
} }
......
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");
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment