diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/LinguaFrancaValidationTest.java b/org.lflang.tests/src/org/lflang/tests/compiler/LinguaFrancaValidationTest.java index 4c0d5dee08..67df93ed30 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1,29 +1,30 @@ /* Scoping unit tests. */ /************* -Copyright (c) 2019, The University of California at Berkeley. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***************/ + Copyright (c) 2019, The University of California at Berkeley. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ***************/ + package org.lflang.tests.compiler; import java.util.LinkedList; @@ -63,7 +64,7 @@ /** * Collection of unit tests to ensure validation is done correctly. - * + * * @author Edward A. Lee * @author Marten Lohstroh * @author Matt Weber @@ -71,7 +72,8 @@ * @author Alexander Schulz-Rosengarten */ public class LinguaFrancaValidationTest { - @Inject + + @Inject ParseHelper parser; @Inject @@ -79,6 +81,7 @@ public class LinguaFrancaValidationTest { /** * Helper function to parse a Lingua Franca program and expect no errors. + * * @return A model representing the parsed string. */ private Model parseWithoutError(String s) throws Exception { @@ -92,6 +95,7 @@ private Model parseWithoutError(String s) throws Exception { /** * Helper function to parse a Lingua Franca program and expect errors. + * * @return A model representing the parsed string. */ private Model parseWithError(String s) throws Exception { @@ -99,105 +103,72 @@ private Model parseWithError(String s) throws Exception { Assertions.assertNotNull(model); Assertions.assertFalse(model.eResource().getErrors().isEmpty()); return model; - } + } /** * Ensure that duplicate identifiers for actions reported. */ @Test public void duplicateVariable() throws Exception { -// Java 17: -// String testCase = """ -// target TypeScript; -// main reactor Foo { -// logical action bar; -// physical action bar; -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target TypeScript;", - "main reactor Foo {", - " logical action bar;", - " physical action bar;", - "}"); - validator.assertError(parseWithoutError(testCase), - LfPackage.eINSTANCE.getAction(), - null, - "Duplicate Variable 'bar' in Reactor 'Foo'"); + String testCase = """ + target TypeScript; + main reactor Foo { + logical action bar; + physical action bar; + } + """; + validator.assertError(parseWithoutError(testCase), + LfPackage.eINSTANCE.getAction(), + null, + "Duplicate Variable 'bar' in Reactor 'Foo'"); } /** - * Check that reactors in C++ cannot be named preamble + * Check that reactors in C++ cannot be named preamble */ @Test public void disallowReactorCalledPreamble() throws Exception { -// Java 17: -// Model model_no_errors = """ -// target Cpp; -// main reactor { -// } -// """ -// Java 11: - Model model_no_errors = parser.parse(String.join( - System.getProperty("line.separator"), - "target Cpp;", - "main reactor {", - "}" - )); - -// Java 17: -// Model model_error_1 = """ -// target Cpp; -// main reactor Preamble { -// } -// """ -// Java 11: - Model model_error_1 = parser.parse(String.join( - System.getProperty("line.separator"), - "target Cpp;", - "main reactor Preamble {", - "}" - )); - -// Java 17: -// Model model_error_2 = """ -// target Cpp; -// reactor Preamble { -// } -// main reactor Main { -// } -// """ -// Java 11: - Model model_error_2 = parser.parse(String.join( - System.getProperty("line.separator"), - "target Cpp;", - "reactor Preamble {", - "}", - "main reactor Main {", - "}" - )); - + Model model_no_errors = parser.parse(""" + target Cpp; + main reactor { + } + """); + + Model model_error_1 = parser.parse(""" + target Cpp; + main reactor Preamble { + } + """); + + Model model_error_2 = parser.parse(""" + target Cpp; + reactor Preamble { + } + main reactor Main { + } + """); + Assertions.assertNotNull(model_no_errors); Assertions.assertNotNull(model_error_1); Assertions.assertNotNull(model_error_2); - Assertions.assertTrue(model_no_errors.eResource().getErrors().isEmpty(), - "Encountered unexpected error while parsing: " + model_no_errors.eResource().getErrors()); - Assertions.assertTrue(model_error_1.eResource().getErrors().isEmpty(), + Assertions.assertTrue(model_no_errors.eResource().getErrors().isEmpty(), + "Encountered unexpected error while parsing: " + + model_no_errors.eResource().getErrors()); + Assertions.assertTrue(model_error_1.eResource().getErrors().isEmpty(), "Encountered unexpected error while parsing: " + model_error_1.eResource().getErrors()); - Assertions.assertTrue(model_error_2.eResource().getErrors().isEmpty(), + Assertions.assertTrue(model_error_2.eResource().getErrors().isEmpty(), "Encountered unexpected error while parsing: " + model_error_2.eResource().getErrors()); validator.assertNoIssues(model_no_errors); - validator.assertError(model_error_1, - LfPackage.eINSTANCE.getReactor(), - null, - "Reactor cannot be named 'Preamble'"); - validator.assertError(model_error_2, - LfPackage.eINSTANCE.getReactor(), - null, - "Reactor cannot be named 'Preamble'"); + validator.assertError(model_error_1, + LfPackage.eINSTANCE.getReactor(), + null, + "Reactor cannot be named 'Preamble'"); + validator.assertError(model_error_2, + LfPackage.eINSTANCE.getReactor(), + null, + "Reactor cannot be named 'Preamble'"); } @@ -206,59 +177,39 @@ public void disallowReactorCalledPreamble() throws Exception { */ @Test public void disallowUnderscoreInputs() throws Exception { -// Java 17: -// String testCase = """ -// target TypeScript; -// main reactor { -// input __bar; -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target TypeScript;", - "main reactor {", - " input __bar;", - "}"); + String testCase = """ + target TypeScript; + main reactor { + input __bar; + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getInput(), null, "Names of objects (inputs, outputs, actions, timers, parameters, state, reactor definitions, and reactor instantiation) may not start with \"__\": __bar"); } - + @Test public void disallowMainWithDifferentNameThanFile() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// main reactor Foo {} -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor Foo {}" - ); + String testCase = """ + target C; + main reactor Foo {} + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getReactor(), null, "Name of main reactor must match the file name (or be omitted)"); } - + /** * Ensure that "__" is not allowed at the start of an output name. */ @Test public void disallowUnderscoreOutputs() throws Exception { -// Java 17: -// String testCase = """ -// target TypeScript; -// main reactor Foo { -// output __bar; -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target TypeScript;", - "main reactor Foo {", - " output __bar;", - "}"); + String testCase = """ + target TypeScript; + main reactor Foo { + output __bar; + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getOutput(), null, "Names of objects (inputs, outputs, actions, timers, parameters, state, reactor definitions, and reactor instantiation) may not start with \"__\": __bar"); @@ -269,324 +220,207 @@ public void disallowUnderscoreOutputs() throws Exception { */ @Test public void disallowUnderscoreActions() throws Exception { -// Java 17: -// String testCase = """ -// target TypeScript; -// main reactor Foo { -// logical action __bar; -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target TypeScript;", - "main reactor Foo {", - " logical action __bar;", - "}"); + String testCase = """ + target TypeScript; + main reactor Foo { + logical action __bar; + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getAction(), null, - "Names of objects (inputs, outputs, actions, timers, parameters, state, reactor definitions, and reactor instantiation) may not start with \"__\": __bar"); + "Names of objects (inputs, outputs, actions, timers, parameters, state, reactor definitions, and reactor instantiation) may not start with \"__\": __bar"); } - + /** * Ensure that "__" is not allowed at the start of a timer name. */ @Test public void disallowUnderscoreTimers() throws Exception { -// Java 17: -// String testCase = """ -// target TypeScript; -// main reactor Foo { -// timer __bar(0); -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target TypeScript;", - "main reactor Foo {", - " timer __bar(0);", - "}"); + String testCase = """ + target TypeScript; + main reactor Foo { + timer __bar(0); + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getTimer(), null, - "Names of objects (inputs, outputs, actions, timers, parameters, state, reactor definitions, and reactor instantiation) may not start with \"__\": __bar"); + "Names of objects (inputs, outputs, actions, timers, parameters, state, reactor definitions, and reactor instantiation) may not start with \"__\": __bar"); } - + /** * Ensure that "__" is not allowed at the start of a parameter name. */ @Test public void disallowUnderscoreParameters() throws Exception { -// Java 17: -// String testCase = """ -// target TypeScript; -// main reactor Foo(__bar) { -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target TypeScript;", - "main reactor Foo(__bar) {", - "}"); + String testCase = """ + target TypeScript; + main reactor Foo(__bar) { + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getParameter(), null, "Names of objects (inputs, outputs, actions, timers, parameters, state, reactor definitions, and reactor instantiation) may not start with \"__\": __bar"); } - + /** * Ensure that "__" is not allowed at the start of an state name. */ @Test public void disallowUnderscoreStates() throws Exception { -// Java 17: -// String testCase = """ -// target TypeScript; -// main reactor Foo { -// state __bar; -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target TypeScript;", - "main reactor Foo {", - " state __bar;", - "}"); + String testCase = """ + target TypeScript; + main reactor Foo { + state __bar; + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getStateVar(), null, "Names of objects (inputs, outputs, actions, timers, parameters, state, reactor definitions, and reactor instantiation) may not start with \"__\": __bar"); } - + /** * Ensure that "__" is not allowed at the start of a reactor definition name. */ @Test public void disallowUnderscoreReactorDef() throws Exception { -// Java 17: -// String testCase = """ -// target TypeScript; -// main reactor __Foo { -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target TypeScript;", - "main reactor __Foo {", - "}"); + String testCase = """ + target TypeScript; + main reactor __Foo { + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getReactor(), null, "Names of objects (inputs, outputs, actions, timers, parameters, state, reactor definitions, and reactor instantiation) may not start with \"__\": __Foo"); } - + /** * Ensure that "__" is not allowed at the start of a reactor instantiation name. */ @Test public void disallowUnderscoreReactorInstantiation() throws Exception { -// Java 17: -// String testCase = """ -// target TypeScript; -// reactor Foo { -// } -// main reactor Bar { -// __x = new Foo(); -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target TypeScript;", - "reactor Foo {", - "}", - "main reactor Bar {", - " __x = new Foo();", - "}"); + String testCase = """ + target TypeScript; + reactor Foo { + } + main reactor Bar { + __x = new Foo(); + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getInstantiation(), null, "Names of objects (inputs, outputs, actions, timers, parameters, state, reactor definitions, and reactor instantiation) may not start with \"__\": __x"); } - + /** * Disallow connection to port that is effect of reaction. */ @Test public void connectionToEffectPort() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// reactor Foo { -// output out:int; -// } -// main reactor Bar { -// output out:int; -// x = new Foo(); -// x.out -> out; -// reaction(startup) -> out {= -// =} -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "reactor Foo {", - " output out:int;", - "}", - "main reactor Bar {", - " output out:int;", - " x = new Foo();", - " x.out -> out;", - " reaction(startup) -> out {=", - " =}", - "}"); + String testCase = """ + target C; + reactor Foo { + output out:int; + } + main reactor Bar { + output out:int; + x = new Foo(); + x.out -> out; + reaction(startup) -> out {= + =} + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getConnection(), null, "Cannot connect: Port named 'out' is already effect of a reaction."); } - + /** * Disallow connection to port that is effect of reaction. */ @Test public void connectionToEffectPort2() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// reactor Foo { -// input inp:int; -// output out:int; -// } -// main reactor { -// output out:int; -// x = new Foo(); -// y = new Foo(); -// -// y.out -> x.inp; -// reaction(startup) -> x.inp {= -// =} -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "reactor Foo {", - " input inp:int;", - " output out:int;", - "}", - "main reactor {", - " output out:int;", - " x = new Foo();", - " y = new Foo();", - "", - " y.out -> x.inp;", - " reaction(startup) -> x.inp {=", - " =}", - "}"); + String testCase = """ + target C; + reactor Foo { + input inp:int; + output out:int; + } + main reactor { + output out:int; + x = new Foo(); + y = new Foo(); + + y.out -> x.inp; + reaction(startup) -> x.inp {= + =} + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getConnection(), null, "Cannot connect: Port named 'inp' is already effect of a reaction."); } - + /** - * Allow connection to the port of a contained reactor if another port with same name is effect of a reaction. + * Allow connection to the port of a contained reactor if another port with same name is effect + * of a reaction. */ @Test public void connectionToEffectPort3() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// -// reactor Foo { -// input in:int; -// } -// reactor Bar { -// input in:int; -// x1 = new Foo(); -// x2 = new Foo(); -// in -> x1.in; -// reaction(startup) -> x2.in {= -// =} -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "", - "reactor Foo {", - " input in:int;", - "}", - "reactor Bar {", - " input in:int;", - " x1 = new Foo();", - " x2 = new Foo();", - " in -> x1.in;", - " reaction(startup) -> x2.in {=", - " =}", - "}"); + String testCase = """ + target C; + + reactor Foo { + input in:int; + } + reactor Bar { + input in:int; + x1 = new Foo(); + x2 = new Foo(); + in -> x1.in; + reaction(startup) -> x2.in {= + =} + } + """; validator.assertNoErrors(parseWithoutError(testCase)); } /** - * Allow connection to the port of a contained reactor if another port with same name is effect of a reaction. + * Allow connection to the port of a contained reactor if another port with same name is effect + * of a reaction. */ @Test public void connectionToEffectPort3_5() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// -// reactor Foo { -// input in:int; -// } -// main reactor { -// input in:int; -// x1 = new Foo(); -// x2 = new Foo(); -// in -> x1.in; -// reaction(startup) -> x2.in {= -// =} -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "", - "reactor Foo {", - " input in:int;", - "}", - "main reactor {", - " input in:int;", - " x1 = new Foo();", - " x2 = new Foo();", - " in -> x1.in;", - " reaction(startup) -> x2.in {=", - " =}", - "}"); + String testCase = """ + target C; + + reactor Foo { + input in:int; + } + main reactor { + input in:int; + x1 = new Foo(); + x2 = new Foo(); + in -> x1.in; + reaction(startup) -> x2.in {= + =} + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getVariable(), null, - "Main reactor cannot have inputs."); + "Main reactor cannot have inputs."); } /** - * Disallow connection to the port of a contained reactor if the same port is effect of a reaction. + * Disallow connection to the port of a contained reactor if the same port is effect of a + * reaction. */ @Test public void connectionToEffectPort4() throws Exception { -// Java 17: -// String testCase = """ -// target C; - -// reactor Foo { -// input in:int; -// } -// main reactor { -// input in:int; -// x1 = new Foo(); -// in -> x1.in; -// reaction(startup) -> x1.in {= -// =} -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "", - "reactor Foo {", - " input in:int;", - "}", - "main reactor {", - " input in:int;", - " x1 = new Foo();", - " in -> x1.in;", - " reaction(startup) -> x1.in {=", - " =}", - "}"); + String testCase = """ + target C; + + reactor Foo { + input in:int; + } + main reactor { + input in:int; + x1 = new Foo(); + in -> x1.in; + reaction(startup) -> x1.in {= + =} + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getConnection(), null, "Cannot connect: Port named 'in' is already effect of a reaction."); } @@ -596,39 +430,22 @@ public void connectionToEffectPort4() throws Exception { */ @Test public void multipleConnectionsToInputTest() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// reactor Source { -// output out:int; -// } -// reactor Sink { -// input in:int; -// } -// main reactor { -// input in:int; -// src = new Source(); -// sink = new Sink(); -// in -> sink.in; -// src.out -> sink.in; -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "reactor Source {", - " output out:int;", - "}", - "reactor Sink {", - " input in:int;", - "}", - "main reactor {", - " input in:int;", - " src = new Source();", - " sink = new Sink();", - " in -> sink.in;", - " src.out -> sink.in;", - "}"); + String testCase = """ + target C; + reactor Source { + output out:int; + } + reactor Sink { + input in:int; + } + main reactor { + input in:int; + src = new Source(); + sink = new Sink(); + in -> sink.in; + src.out -> sink.in; + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getConnection(), null, "Cannot connect: Port named 'in' may only appear once on the right side of a connection."); } @@ -638,146 +455,92 @@ public void multipleConnectionsToInputTest() throws Exception { */ @Test public void detectInstantiationCycle() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// reactor Contained { -// x = new Contained(); -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "reactor Contained {", - " x = new Contained();", - "}"); + String testCase = """ + target C; + reactor Contained { + x = new Contained(); + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getInstantiation(), null, "Instantiation is part of a cycle: Contained"); } - - + + /** * Detect cycles in the instantiation graph. */ @Test public void detectInstantiationCycle2() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// reactor Intermediate { -// x = new Contained(); -// } -// -// reactor Contained { -// x = new Intermediate(); -// } -// """ -// Java 11: - Model model = parseWithoutError(String.join( - System.getProperty("line.separator"), - "target C;", - "reactor Intermediate {", - " x = new Contained();", - "}", - "", - "reactor Contained {", - " x = new Intermediate();", - "}" - )); + String testCase = """ + target C; + reactor Intermediate { + x = new Contained(); + } + reactor Contained { + x = new Intermediate(); + } + """; + + Model model = parseWithoutError(testCase); validator.assertError(model, LfPackage.eINSTANCE.getInstantiation(), null, "Instantiation is part of a cycle: Intermediate, Contained."); validator.assertError(model, LfPackage.eINSTANCE.getInstantiation(), null, "Instantiation is part of a cycle: Intermediate, Contained."); } - + /** * Detect causality loop. */ @Test public void detectCausalityLoop() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// -// reactor X { -// input x:int; -// output y:int; -// reaction(x) -> y {= -// =} -// } -// -// main reactor { -// a = new X() -// b = new X() -// a.y -> b.x -// b.y -> a.x -// } -// """ -// Java 11: - Model model = parseWithoutError(String.join( - System.getProperty("line.separator"), - "target C;", - "", - "reactor X {", - " input x:int;", - " output y:int;", - " reaction(x) -> y {=", - " =}", - "}", - "", - "main reactor {", - " a = new X()", - " b = new X()", - " a.y -> b.x", - " b.y -> a.x", - "}" - )); + + String testCase = """ + target C; + + reactor X { + input x:int; + output y:int; + reaction(x) -> y {= + =} + } + + main reactor { + a = new X() + b = new X() + a.y -> b.x + b.y -> a.x + } + """; + Model model = parseWithoutError(testCase); validator.assertError(model, LfPackage.eINSTANCE.getReaction(), null, "Reaction triggers involved in cyclic dependency in reactor X: x."); validator.assertError(model, LfPackage.eINSTANCE.getReaction(), - null, "Reaction effects involved in cyclic dependency in reactor X: y."); + null, "Reaction effects involved in cyclic dependency in reactor X: y."); } - + /** * Let cyclic dependencies be broken by "after" clauses. */ @Test public void afterBreaksCycle() throws Exception { -// Java 17: -// String testCase = """ -// target C -// -// reactor X { -// input x:int; -// output y:int; -// reaction(x) -> y {= -// =} -// } -// -// main reactor { -// a = new X() -// b = new X() -// a.y -> b.x after 5 msec -// b.y -> a.x -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C", - " ", - "reactor X {", - " input x:int;", - " output y:int;", - " reaction(x) -> y {=", - " =}", - "}", - "", - "main reactor {", - " a = new X()", - " b = new X()", - " a.y -> b.x after 5 msec", - " b.y -> a.x", - "}"); + String testCase = """ + target C + + reactor X { + input x:int; + output y:int; + reaction(x) -> y {= + =} + } + + main reactor { + a = new X() + b = new X() + a.y -> b.x after 5 msec + b.y -> a.x + } + """; + validator.assertNoErrors(parseWithoutError(testCase)); } @@ -787,42 +550,23 @@ public void afterBreaksCycle() throws Exception { */ @Test public void afterBreaksCycle2() throws Exception { -// Java 17: -// String testCase = """ -// target C -// -// reactor X { -// input x:int; -// output y:int; -// reaction(x) -> y {= -// =} -// } -// -// main reactor { -// a = new X() -// b = new X() -// a.y -> b.x after 0 sec -// b.y -> a.x -// } -// """ -// Java 11: - - String testCase = String.join(System.getProperty("line.separator"), - "target C", - " ", - "reactor X {", - " input x:int;", - " output y:int;", - " reaction(x) -> y {=", - " =}", - "}", - "", - "main reactor {", - " a = new X()", - " b = new X()", - " a.y -> b.x after 0 sec", - " b.y -> a.x", - "}"); + String testCase = """ + target C + + reactor X { + input x:int; + output y:int; + reaction(x) -> y {= + =} + } + + main reactor { + a = new X() + b = new X() + a.y -> b.x after 0 sec + b.y -> a.x + } + """; validator.assertNoErrors(parseWithoutError(testCase)); } @@ -832,41 +576,23 @@ public void afterBreaksCycle2() throws Exception { */ @Test public void afterBreaksCycle3() throws Exception { -// Java 17: -// String testCase = """ -// target C -// -// reactor X { -// input x:int; -// output y:int; -// reaction(x) -> y {= -// =} -// } -// -// main reactor { -// a = new X() -// b = new X() -// a.y -> b.x after 0 -// b.y -> a.x -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C", - " ", - "reactor X {", - " input x:int;", - " output y:int;", - " reaction(x) -> y {=", - " =}", - "}", - "", - "main reactor {", - " a = new X()", - " b = new X()", - " a.y -> b.x after 0", - " b.y -> a.x", - "}"); + String testCase = """ + target C + + reactor X { + input x:int; + output y:int; + reaction(x) -> y {= + =} + } + + main reactor { + a = new X() + b = new X() + a.y -> b.x after 0 + b.y -> a.x + } + """; validator.assertNoErrors(parseWithoutError(testCase)); } @@ -875,311 +601,198 @@ public void afterBreaksCycle3() throws Exception { */ @Test public void nonzeroAfterMustHaveUnits() throws Exception { -// Java 17: -// String testCase = """ -// target C -// -// reactor X { -// input x:int; -// output y:int; -// reaction(x) -> y {= -// =} -// } -// -// main reactor { -// a = new X() -// b = new X() -// a.y -> b.x after 1 -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C", - " ", - "reactor X {", - " input x:int;", - " output y:int;", - " reaction(x) -> y {=", - " =}", - "}", - "", - "main reactor {", - " a = new X()", - " b = new X()", - " a.y -> b.x after 1", - "}"); + String testCase = """ + target C + + reactor X { + input x:int; + output y:int; + reaction(x) -> y {= + =} + } + + main reactor { + a = new X() + b = new X() + a.y -> b.x after 1 + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getConnection(), null, "Missing time unit."); } - /** * Report non-zero time value without units. */ @Test public void nonZeroTimeValueWithoutUnits() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// main reactor { -// timer t(42, 1 sec); -// reaction(t) {= -// printf("Hello World.\\n"); -// =} -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor {", - " timer t(42, 1 sec);", - " reaction(t) {=", - " printf(\"Hello World.\\n\");", - " =}", - "}"); + String testCase = """ + target C; + main reactor { + timer t(42, 1 sec); + reaction(t) {= + printf("Hello World.\\n"); + =} + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getTimer(), null, "Missing time unit."); - } - + } + /** * Report reference to non-time parameter in time argument. */ @Test public void parameterTypeMismatch() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// main reactor (p:int(0)) { -// timer t(p, 1 sec); -// reaction(t) {= -// printf("Hello World.\\n"); -// =} -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor (p:int(0)) {", - " timer t(p, 1 sec);", - " reaction(t) {=", - " printf(\"Hello World.\\n\");", - " =}", - "}"); + String testCase = """ + target C; + main reactor (p:int(0)) { + timer t(p, 1 sec); + reaction(t) {= + printf("Hello World.\\n"); + =} + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getTimer(), null, "Referenced parameter is not of time type."); } - + /** * Report inappropriate literal in time argument. */ @Test public void targetCodeInTimeArgument() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// main reactor { -// timer t({=foo()=}, 1 sec); -// reaction(t) {= -// printf("Hello World.\\n"); -// =} -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor {", - " timer t({=foo()=}, 1 sec);", - " reaction(t) {=", - " printf(\"Hello World.\\n\");", - " =}", - "}"); + String testCase = """ + target C; + main reactor { + timer t({=foo()=}, 1 sec); + reaction(t) {= + printf("Hello World.\\n"); + =} + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getTimer(), null, "Invalid time value."); - } - + } + /** * Report overflowing deadline. */ @Test public void overflowingDeadlineC() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// main reactor { -// timer t; -// reaction(t) {= -// printf("Hello World.\\n"); -// =} deadline (40 hours) {= -// =} -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor {", - "timer t;", - " reaction(t) {=", - " printf(\"Hello World.\\n\");", - " =} deadline (40 hours) {=", - " =}", - "}"); + String testCase = """ + target C; + main reactor { + timer t; + reaction(t) {= + printf("Hello World.\\n"); + =} deadline (40 hours) {= + =} + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getDeadline(), null, "Deadline exceeds the maximum of " + TimeValue.MAX_LONG_DEADLINE + - " nanoseconds."); - } + " nanoseconds."); + } + - /** * Report overflowing parameter. */ @Test public void overflowingParameterC() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// main reactor(d:time(40 hours)) { -// timer t; -// reaction(t) {= -// printf("Hello World.\\n"); -// =} deadline (d) {= -// =} -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor(d:time(40 hours)) {", - "timer t;", - " reaction(t) {=", - " printf(\"Hello World.\\n\");", - " =} deadline (d) {=", - " =}", - "}"); + String testCase = """ + target C; + main reactor(d:time(40 hours)) { + timer t; + reaction(t) {= + printf("Hello World.\\n"); + =} deadline (d) {= + =} + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getParameter(), null, "Time value used to specify a deadline exceeds the maximum of " + - TimeValue.MAX_LONG_DEADLINE + " nanoseconds."); - } - - + TimeValue.MAX_LONG_DEADLINE + " nanoseconds."); + } + + /** * Report overflowing assignment. */ @Test public void overflowingAssignmentC() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// reactor Print(d:time(39 hours)) { -// timer t; -// reaction(t) {= -// printf("Hello World.\\n"); -// =} deadline (d) {= -// =} -// } -// main reactor { -// p = new Print(d=40 hours); -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "reactor Print(d:time(39 hours)) {", - " timer t;", - " reaction(t) {=", - " printf(\"Hello World.\\n\");", - " =} deadline (d) {=", - " =}", - "}", - "main reactor {", - " p = new Print(d=40 hours);", - "}"); + String testCase = """ + target C; + reactor Print(d:time(39 hours)) { + timer t; + reaction(t) {= + printf("Hello World.\\n"); + =} deadline (d) {= + =} + } + main reactor { + p = new Print(d=40 hours); + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getAssignment(), null, "Time value used to specify a deadline exceeds the maximum of " + - TimeValue.MAX_LONG_DEADLINE + " nanoseconds."); - } + TimeValue.MAX_LONG_DEADLINE + " nanoseconds."); + } /** * Report missing trigger. */ @Test public void missingTrigger() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// reactor X { -// reaction() {= -// // -// =} -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "reactor X {", - " reaction() {=", - " //", - " =}", - "}"); + String testCase = """ + target C; + reactor X { + reaction() {= + // + =} + } + """; validator.assertWarning(parseWithoutError(testCase), LfPackage.eINSTANCE.getReaction(), null, "Reaction has no trigger."); } - + /** - * Test warnings and errors for the target dependent preamble visibility qualifiers + * Test warnings and errors for the target dependent preamble visibility qualifiers */ @Test public void testPreambleVisibility() throws Exception { for (Target target : Target.values()) { for (Visibility visibility : Visibility.values()) { -// Java 17: -// Model model_reactor_scope = """ -// target %s; -// reactor Foo { -// %spreamble {==} -// } -// """.formatted(target, visibility != java.beans.Visibility.NONE ? visibility + " " : ""); -// Java 11: - Model model_reactor_scope = parseWithoutError(String.join(System.getProperty("line.separator"), - String.format("target %s;", target), - "reactor Foo {", - String.format(" %spreamble {==}", visibility != Visibility.NONE ? visibility + " " : ""), - "}")); - -// Java 17: -// Model model_file_scope = """ -// target %s; -// %spreamble {==} -// reactor Foo { -// } -// """.formatted(target, visibility != java.beans.Visibility.NONE ? visibility + " " : ""); -// Java 11: - Model model_file_scope = parseWithoutError(String.join(System.getProperty("line.separator"), - String.format("target %s;", target), - String.format(" %spreamble {==}", visibility != Visibility.NONE ? visibility + " " : ""), - "reactor Foo {", - "}")); - -// Java 17: -// Model model_no_preamble = """ -// target %s; -// reactor Foo { -// } -// """.formatted(target); -// Java 11: - Model model_no_preamble = parseWithoutError(String.join(System.getProperty("line.separator"), - String.format("target %s;", target), - "reactor Foo {", - "}")); - + Model model_reactor_scope = parseWithoutError(""" + target %s; + reactor Foo { + %spreamble {==} + } + """.formatted(target, visibility != Visibility.NONE ? visibility + " " : "")); + + Model model_file_scope = parseWithoutError(""" + target %s; + %spreamble {==} + reactor Foo { + } + """.formatted(target, visibility != Visibility.NONE ? visibility + " " : "")); + + Model model_no_preamble = parseWithoutError(""" + target %s; + reactor Foo { + } + """.formatted(target)); + validator.assertNoIssues(model_no_preamble); - + if (target == Target.CPP) { if (visibility == Visibility.NONE) { validator.assertError(model_file_scope, LfPackage.eINSTANCE.getPreamble(), null, "Preambles for the C++ target need a visibility qualifier (private or public)!"); validator.assertError(model_reactor_scope, LfPackage.eINSTANCE.getPreamble(), null, - "Preambles for the C++ target need a visibility qualifier (private or public)!"); + "Preambles for the C++ target need a visibility qualifier (private or public)!"); } else { validator.assertNoIssues(model_file_scope); validator.assertNoIssues(model_reactor_scope); @@ -1198,46 +811,30 @@ public void testPreambleVisibility() throws Exception { } } } - - + + /** * Tests for state and parameter declarations, including native lists. */ @Test public void stateAndParameterDeclarationsInC() throws Exception { -// Java 17: -// String testCase = """ -// target C; -// reactor Bar(a(0), // ERROR: type missing -// b:int, // ERROR: uninitialized -// t:time(42), // ERROR: units missing -// x:int(0), -// h:time("bla"), // ERROR: not a type -// q:time(1 msec, 2 msec), // ERROR: not a list -// y:int(t) // ERROR: init using parameter -// ) { -// state offset:time(42); // ERROR: units missing -// state w:time(x); // ERROR: parameter is not a time -// state foo:time("bla"); // ERROR: assigned value not a time; -// timer tick(1); // ERROR: not a time -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "reactor Bar(a(0), // ERROR: type missing", - " b:int, // ERROR: uninitialized", - " t:time(42), // ERROR: units missing", - " x:int(0),", - " h:time(\"bla\"), // ERROR: not a type ", - " q:time(1 msec, 2 msec), // ERROR: not a list", - " y:int(t) // ERROR: init using parameter", - ") {", - " state offset:time(45); // ERROR: units missing", - " state w:time(x); // ERROR: parameter is not a time", - " state foo:time(\"bla\"); // ERROR: assigned value not a time", - " timer tick(1); // ERROR: not a time", - "}"); + String testCase = """ + target C; + reactor Bar(a(0), // ERROR: type missing + b:int, // ERROR: uninitialized + t:time = 42, // ERROR: units missing + x:int = 0, + h:time = "bla", // ERROR: not a type + q:time(1 msec, 2 msec), // ERROR: not a list + y:int = t // ERROR: init using parameter + ) { + state offset:time = 42; // ERROR: units missing + state w:time = x; // ERROR: parameter is not a time + state foo:time = "bla"; // ERROR: assigned value not a time; + timer tick(1); // ERROR: not a time + } + """; + Model model = parseWithoutError(testCase); @@ -1261,9 +858,9 @@ public void stateAndParameterDeclarationsInC() throws Exception { "Invalid time value."); validator.assertError(model, LfPackage.eINSTANCE.getTimer(), null, "Missing time unit."); - } - - + } + + /** * Recognize valid IPV4 addresses, report invalid ones. */ @@ -1275,69 +872,44 @@ public void recognizeIPV4() throws Exception { // Correct IP addresses. for (String addr : correct) { -// Java 17: -// String testCase = """ -// target C; -// reactor Y {} -// federated reactor X at foo@%s:4242 { -// y = new Y() at %s:2424; -// } -// """.formatted(addr, addr); -// Java 11: + + String testCase = """ + target C; + reactor Y {} + federated reactor X at foo@%s:4242 { + y = new Y() at %s:2424; + } + """.formatted(addr, addr); parseWithoutError( - String.join(System.getProperty("line.separator"), - "target C;", - "reactor Y {}", - String.format("federated reactor X at foo@%s:4242 {", addr), - String.format(" y = new Y() at %s:2424; ", addr), - "}") + testCase ); } // IP addresses that don't parse. for (String addr : parseError) { -// Java 17: -// String testCase = """ -// target C; -// reactor Y {} -// federated reactor X at foo@%s:4242 { -// y = new Y() at %s:2424; -// } -// """.formatted(addr, addr); -// Java 11: - parseWithError( - String.join(System.getProperty("line.separator"), - "target C;", - "reactor Y {}", - String.format("federated reactor X at foo@%s:4242 {", addr), - String.format(" y = new Y() at %s:2424; ", addr), - "}") - ); + String testCase = """ + target C; + reactor Y {} + federated reactor X at foo@%s:4242 { + y = new Y() at %s:2424; + } + """.formatted(addr, addr); + parseWithError(testCase); } // IP addresses that parse but are invalid. for (String addr : validationError) { -// Java 17: -// Model model = """ -// target C; -// reactor Y {} -// federated reactor X at foo@%s:4242 { -// y = new Y() at %s:2424; -// } -// """.formatted(addr, addr); -// Java 11: - Model model = parseWithoutError( - String.join(System.getProperty("line.separator"), - "target C;", - "reactor Y {}", - String.format("federated reactor X at foo@%s:4242 {", addr), - String.format(" y = new Y() at %s:2424; ", addr), - "}") - ); + Model model = parseWithoutError(""" + target C; + reactor Y {} + federated reactor X at foo@%s:4242 { + y = new Y() at %s:2424; + } + """.formatted(addr, addr)); validator.assertWarning(model, LfPackage.eINSTANCE.getHost(), null, "Invalid IP address."); } } - + /** * Recognize valid IPV6 addresses, report invalid ones. */ @@ -1355,160 +927,114 @@ public void recognizeIPV6() throws Exception { "::ffff:0.0.0.0", "::ffff:1.2.3.4", "::ffff:10.0.0.1", "1:2:3:4:5:6:77:88", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "2001:db8:3:4::192.0.2.33", "64:ff9b::192.0.2.33", "0:0:0:0:0:0:10.0.0.1"); - + List validationError = List.of("1:2:3:4:5:6:7:8:9", "1:2:3:4:5:6::7:8", "1:2:3:4:5:6:7:8:", "::1:2:3:4:5:6:7:8", "1:2:3:4:5:6:7:8::", "1:2:3:4:5:6:7:88888", "2001:db8:3:4:5::192.0.2.33", "fe08::7:8interface", "fe08::7:8interface", "fe08::7:8i"); - + List parseError = List.of("fe08::7:8%", ":1:2:3:4:5:6:7:8"); - + // Correct IP addresses. for (String addr : correct) { -// Java 17: -// String testCase = """ -// target C; -// reactor Y {} -// federated reactor X at [foo@%s]:4242 { -// y = new Y() at [%s]:2424; -// } -// """.formatted(addr, addr); -// Java 11: - Model model = parseWithoutError( - String.join(System.getProperty("line.separator"), - "target C;", - "reactor Y {}", - String.format("federated reactor at [foo@%s]:4242 {", addr), - String.format(" y = new Y() at [%s]:2424; ", addr), - "}") - ); + String testCase = """ + target C; + reactor Y {} + federated reactor at [foo@%s]:4242 { + y = new Y() at [%s]:2424; + } + """.formatted(addr, addr); + Model model = parseWithoutError(testCase); validator.assertNoIssues(model); } - + // IP addresses that don't parse. for (String addr : parseError) { -// Java 17: -// String testCase = """ -// target C; -// reactor Y {} -// federated reactor X at [foo@%s]:4242 { -// y = new Y() at [%s]:2424; -// } -// """.formatted(addr, addr); -// Java 11: - parseWithError( - String.join(System.getProperty("line.separator"), - "target C;", - "reactor Y {}", - String.format("federated reactor X at [foo@%s]:4242 {", addr), - String.format(" y = new Y() at [%s]:2424; ", addr), - "}") - ); + String testCase = """ + target C; + reactor Y {} + federated reactor X at [foo@%s]:4242 { + y = new Y() at [%s]:2424; + } + """.formatted(addr, addr); + parseWithError(testCase); } // IP addresses that parse but are invalid. for (String addr : validationError) { -// Java 17: -// String testCase = """ -// target C; -// reactor Y {} -// federated reactor X at [foo@%s]:4242 { -// y = new Y() at [%s]:2424; -// } -// """.formatted(addr, addr); -// Java 11: + String testCase = """ + target C; + reactor Y {} + federated reactor X at [foo@%s]:4242 { + y = new Y() at [%s]:2424; + } + """.formatted(addr, addr); Model model = parseWithoutError( - String.join(System.getProperty("line.separator"), - "target C;", - "reactor Y {}", - String.format("federated reactor X at [foo@%s]:4242 {", addr), - String.format(" y = new Y() at [%s]:2424; ", addr), - "}") + testCase ); validator.assertWarning(model, LfPackage.eINSTANCE.getHost(), null, "Invalid IP address."); } } - + /** * Recognize valid host names and fully qualified names, report invalid ones. */ @Test public void recognizeHostNames() throws Exception { - + List correct = List.of("localhost"); // FIXME: add more - + List validationError = List.of("x.y.z"); // FIXME: add more - + List parseError = List.of("..xyz"); // FIXME: add more // Correct names. for (String addr : correct) { -// Java 17: -// String testCase = """ -// target C; -// reactor Y {} -// federated reactor X at foo@%s:4242 { -// y = new Y() at %s:2424; -// } -// """.formatted(addr, addr); -// Java 11: + String testCase = """ + target C; + reactor Y {} + federated reactor X at foo@%s:4242 { + y = new Y() at %s:2424; + } + """.formatted(addr, addr); parseWithoutError( - String.join(System.getProperty("line.separator"), - "target C;", - "reactor Y {}", - String.format("federated reactor X at foo@%s:4242 {", addr), - String.format(" y = new Y() at %s:2424; ", addr), - "}") + testCase ); } - + // Names that don't parse. for (String addr : parseError) { -// Java 17: -// String testCase = """ -// target C; -// reactor Y {} -// federated reactor X at foo@%s:4242 { -// y = new Y() at %s:2424; -// } -// """.formatted(addr, addr); -// Java 11: + String testCase = """ + target C; + reactor Y {} + federated reactor X at foo@%s:4242 { + y = new Y() at %s:2424; + } + """.formatted(addr, addr); parseWithError( - String.join(System.getProperty("line.separator"), - "target C;", - "reactor Y {}", - String.format("federated reactor X at foo@%s:4242 {", addr), - String.format(" y = new Y() at %s:2424; ", addr), - "}") + testCase ); } - + // Names that parse but are invalid. for (String addr : validationError) { -// Java 17: -// String testCase = """ -// target C; -// reactor Y {} -// federated reactor X at foo@%s:4242 { -// y = new Y() at %s:2424; -// } -// """.formatted(addr, addr); -// Java 11: + String testCase = """ + target C; + reactor Y {} + federated reactor X at foo@%s:4242 { + y = new Y() at %s:2424; + } + """.formatted(addr, addr); Model model = parseWithoutError( - String.join(System.getProperty("line.separator"), - "target C;", - "reactor Y {}", - String.format("federated reactor X at foo@%s:4242 {", addr), - String.format(" y = new Y() at %s:2424; ", addr), - "}") + testCase ); - validator.assertWarning(model, LfPackage.eINSTANCE.getHost(), null, + validator.assertWarning(model, LfPackage.eINSTANCE.getHost(), null, "Invalid host name or fully qualified domain name."); } } - + /** * Maps a type to a list of known good values. */ @@ -1533,7 +1059,7 @@ public void recognizeHostNames() throws Exception { ); /** - * Maps a type to a list, each entry of which represents a list with + * Maps a type to a list, each entry of which represents a list with * three entries: a known wrong value, the suffix to add to the reported * name, and the type that it should be. */ @@ -1575,13 +1101,14 @@ public void recognizeHostNames() throws Exception { List.of("{trace-file-name: [1, 2, 3]}", ".trace-file-name", PrimitiveType.STRING) ) ); - + /** - * Given an array type, return a list of good or bad examples, + * Given an array type, return a list of good or bad examples, * depending on the value of the second parameter. */ private List synthesizeExamples(ArrayType type, boolean correct) { - Map> values = correct ? primitiveTypeToKnownGood : primitiveTypeToKnownBad; + Map> values = correct ? primitiveTypeToKnownGood + : primitiveTypeToKnownBad; List examples = new LinkedList<>(); if (correct) { // Produce an array that has an entry for each value. @@ -1592,9 +1119,9 @@ private List synthesizeExamples(ArrayType type, boolean correct) { } return examples; } - + /** - * Given an union type, return a list of good or bad examples, + * Given an union type, return a list of good or bad examples, * depending on the value of the second parameter. */ private List synthesizeExamples(UnionType type, boolean correct) { @@ -1610,15 +1137,15 @@ private List synthesizeExamples(UnionType type, boolean correct) { } else { // Return some obviously bad examples for the common // case where the options are from an ordinary Enum. - if (!type.options.stream().anyMatch(it -> (it instanceof TargetPropertyType))) { + if (!type.options.stream().anyMatch(it -> it instanceof TargetPropertyType)) { return List.of("foo", "\"bar\"", "1", "-1", "{x: 42}", "[1, 2, 3]"); } } return examples; } - + /** - * Given an union type, return a list of good or bad examples, + * Given an union type, return a list of good or bad examples, * depending on the value of the second parameter. */ private List synthesizeExamples(DictionaryType type, boolean correct) { @@ -1626,7 +1153,8 @@ private List synthesizeExamples(DictionaryType type, boolean correct) { // Produce a set of singleton dictionaries. // If incorrect examples are wanted, garble the key. for (DictionaryElement option : type.options) { - synthesizeExamples(option.getType(), correct).forEach(it -> examples.add("{" + option + (!correct ? "iamwrong: " : ": ") + it + "}")); + synthesizeExamples(option.getType(), correct).forEach(it -> examples.add( + "{" + option + (!correct ? "iamwrong: " : ": ") + it + "}")); } return examples; } @@ -1649,23 +1177,24 @@ private List synthesizeExamples(StringDictionaryType type, boolean corre } return examples; } - + /** * Synthesize a list of values that either conform to the given type or * do not, depending on whether the second argument 'correct' is true. - * Return an empty set if it is too complicated to generate examples + * Return an empty set if it is too complicated to generate examples * (e.g., because the resulting errors are more sophisticated). - * + *

* Not all cases are covered by this function. Currently, the only cases not * covered are known bad examples for composite types, which should be added * to the compositeTypeToKnownBad map. - * + * * @param correct True to synthesize correct examples automatically, otherwise - * synthesize incorrect examples. + * synthesize incorrect examples. */ private List synthesizeExamples(TargetPropertyType type, boolean correct) { if (type instanceof PrimitiveType) { - Map> values = correct ? primitiveTypeToKnownGood : primitiveTypeToKnownBad; + Map> values = correct ? primitiveTypeToKnownGood + : primitiveTypeToKnownBad; List examples = values.get(type); Assertions.assertNotNull(examples); return examples; @@ -1684,29 +1213,21 @@ private List synthesizeExamples(TargetPropertyType type, boolean correct } return new LinkedList<>(); } - + /** * Create an LF program with the given key and value as a target property, * parse it, and return the resulting model. */ private Model createModel(TargetProperty key, String value) throws Exception { String target = key.supportedBy.get(0).getDisplayName(); - System.out.println(String.format("%s: %s", key, value)); -// Java 17: -// Model model = """ -// target %s {%s: %s}; -// reactor Y {} -// main reactor { -// y = new Y() -// } -// """.formatted(target, key, value); -// Java 11: - return parseWithoutError(String.join(System.getProperty("line.separator"), - String.format("target %s {%s: %s};", target, key, value), - "reactor Y {}", - "main reactor {", - " y = new Y() ", - "}")); + System.out.printf("%s: %s%n", key, value); + return parseWithoutError(""" + target %s {%s: %s}; + reactor Y {} + main reactor { + y = new Y() + } + """.formatted(target, key, value)); } /** @@ -1719,21 +1240,21 @@ public void checkTargetProperties() throws Exception { // we test that separately as it has better error messages return; } - System.out.println(String.format("Testing target property %s which is %s", prop, prop.type)); + System.out.printf("Testing target property %s which is %s%n", prop, prop.type); System.out.println("===="); System.out.println("Known good assignments:"); List knownCorrect = synthesizeExamples(prop.type, true); - + for (String it : knownCorrect) { Model model = createModel(prop, it); validator.assertNoErrors(model); // Also make sure warnings are produced when files are not present. if (prop.type == PrimitiveType.FILE) { validator.assertWarning(model, LfPackage.eINSTANCE.getKeyValuePair(), - null, String.format("Could not find file: '%s'.", StringUtil.removeQuotes(it))); + null, String.format("Could not find file: '%s'.", StringUtil.removeQuotes(it))); } } - + // Extra checks for filenames. (This piece of code was commented out in the original xtend file) // Temporarily disabled because we need a more sophisticated check that looks for files in different places. // if (prop.type == prop.type == ArrayType.FILE_ARRAY || @@ -1746,35 +1267,35 @@ public void checkTargetProperties() throws Exception { // null, '''Could not find file: '«it.withoutQuotes»'.''') // ] // } - + System.out.println("Known bad assignments:"); List knownIncorrect = synthesizeExamples(prop.type, false); if (!(knownIncorrect == null || knownIncorrect.isEmpty())) { for (String it : knownIncorrect) { if (prop.type instanceof StringDictionaryType) { validator.assertError(createModel(prop, it), - LfPackage.eINSTANCE.getKeyValuePair(), null, - String.format("Target property '%s.", prop), "' is required to be a string."); + LfPackage.eINSTANCE.getKeyValuePair(), null, + String.format("Target property '%s.", prop), "' is required to be a string."); } else { validator.assertError(createModel(prop, it), - LfPackage.eINSTANCE.getKeyValuePair(), null, - String.format("Target property '%s' is required to be %s.", prop.toString(), prop.type)); + LfPackage.eINSTANCE.getKeyValuePair(), null, + String.format("Target property '%s' is required to be %s.", prop, prop.type)); } } } else { // No type was synthesized. It must be a composite type. List> list = compositeTypeToKnownBad.get(prop.type); if (list == null) { - System.out.println(String.format("No known incorrect values provided for target property '%s'. Aborting test.", prop)); - Assertions.assertTrue(false); + System.out.printf("No known incorrect values provided for target property '%s'. Aborting test.%n", prop); + Assertions.fail(); } else { for (List it : list) { validator.assertError(createModel(prop, it.get(0).toString()), LfPackage.eINSTANCE.getKeyValuePair(), null, - String.format("Target property '%s%s' is required to be %s.", prop.toString(), it.get(1), it.get(2))); + String.format("Target property '%s%s' is required to be %s.", prop, it.get(1), it.get(2))); } } - } + } System.out.println("===="); } System.out.println("Done!"); @@ -1793,7 +1314,7 @@ public void checkCargoDependencyProperty() throws Exception { validator.assertError(createModel(prop, "{ dep: {/*empty*/} }"), LfPackage.eINSTANCE.getKeyValuePairs(), null, "Must specify one of 'version', 'path', or 'git'" ); - + // vvvvvvvvvvv validator.assertError(createModel(prop, "{ dep: { unknown_key: \"\"} }"), LfPackage.eINSTANCE.getKeyValuePair(), null, "Unknown key: 'unknown_key'" @@ -1884,358 +1405,228 @@ public void testUnusedImport() throws Exception { @Test public void testMissingInputType() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // main reactor { - // input i; - // } - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor {", - " input i;", - "}" - ); + String testCase = """ + target C; + main reactor { + input i; + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getInput(), null, "Input must have a type."); } @Test public void testMissingOutputType() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // main reactor { - // output i; - // } - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor {", - " output i;", - "}" - ); + String testCase = """ + target C; + main reactor { + output i; + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getOutput(), null, "Output must have a type."); } @Test public void testMissingStateType() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // main reactor { - // state i; - // } - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor {", - " state i;", - "}" - ); + String testCase = """ + target C; + main reactor { + state i; + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getStateVar(), null, "State must have a type."); } @Test public void testListWithParam() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // main reactor (A:int(1)) { state i:int(A, 2, 3) } - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor (A:int(1)) { state i:int(A, 2, 3) }" - ); + String testCase = """ + target C; + main reactor (A:int(1)) { state i:int(A, 2, 3) } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getStateVar(), null, "List items cannot refer to a parameter."); } @Test public void testCppMutableInput() throws Exception { - // Java 17: - // String testCase = """ - // target Cpp; - // main reactor { - // mutable input i:int; - // } - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target Cpp;", - "main reactor {", - " mutable input i:int;", - "}" - ); + String testCase = """ + target Cpp; + main reactor { + mutable input i:int; + } + """; validator.assertWarning(parseWithoutError(testCase), LfPackage.eINSTANCE.getInput(), null, "The mutable qualifier has no meaning for the C++ target and should be removed. " + - "In C++, any value can be made mutable by calling get_mutable_copy()."); + "In C++, any value can be made mutable by calling get_mutable_copy()."); } @Test public void testOverflowingSTP() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // main reactor { - // reaction(startup) {==} STP(2147483648) {==} - // } - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor {", - " reaction(startup) {==} STP(2147483648) {==}", - "}" - ); + String testCase = """ + target C; + main reactor { + reaction(startup) {==} STP(2147483648) {==} + } + """; // TODO: Uncomment and fix failing test. See issue #903 on Github. // validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getSTP(), null, - // "STP offset exceeds the maximum of " + TimeValue.MAX_LONG_DEADLINE + " nanoseconds."); + // "STP offset exceeds the maximum of " + TimeValue.MAX_LONG_DEADLINE + " nanoseconds."); } @Test public void testOverflowingDeadline() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // main reactor { - // reaction(startup) {==} STP(2147483648) {==} - // } - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor {", - " reaction(startup) {==} deadline(2147483648) {==}", - "}" - ); + String testCase = """ + target C; + main reactor { + reaction(startup) {==} STP(2147483648) {==} + } + """; // TODO: Uncomment and fix failing test. See issue #903 on Github. // validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getDeadline(), null, - // "Deadline exceeds the maximum of " + TimeValue.MAX_LONG_DEADLINE + " nanoseconds."); + // "Deadline exceeds the maximum of " + TimeValue.MAX_LONG_DEADLINE + " nanoseconds."); } @Test public void testInvalidTargetParam() throws Exception { - // Java 17: - // String testCase = """ - // target C { beefyDesktop: true } - // main reactor {} - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C { beefyDesktop: true }", - "main reactor {}" - ); + String testCase = """ + target C { beefyDesktop: true } + main reactor {} + """; List issues = validator.validate(parseWithoutError(testCase)); - Assertions.assertTrue(issues.size() == 1 && issues.get(0).getMessage().contains("Unrecognized target parameter: beefyDesktop")); + Assertions.assertTrue(issues.size() == 1 + && issues.get(0).getMessage().contains("Unrecognized target parameter: beefyDesktop")); } @Test public void testTargetParamNotSupportedForTarget() throws Exception { - // Java 17: - // String testCase = """ - // target Python { build: "" } - // main reactor {} - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target Python { build: \"\" }", - "main reactor {}" - ); + String testCase = """ + target Python { build: "" } + main reactor {} + """; List issues = validator.validate(parseWithoutError(testCase)); - Assertions.assertTrue(issues.size() == 1 && issues.get(0).getMessage().contains("The target parameter: build" + - " is not supported by the Python target and will thus be ignored.")); + Assertions.assertTrue(issues.size() == 1 && issues.get(0).getMessage().contains( + "The target parameter: build" + + " is not supported by the Python target and will thus be ignored.")); } @Test public void testUnnamedReactor() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // reactor {} - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "reactor {}" - ); + String testCase = """ + target C; + reactor {} + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getReactor(), null, "Reactor must be named."); } @Test public void testMainHasInput() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // main reactor { - // input x:int; - // } - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor {", - " input x:int;", - "}" - ); + String testCase = """ + target C; + main reactor { + input x:int; + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getInput(), null, "Main reactor cannot have inputs."); } @Test public void testFederatedHasInput() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // federated reactor { - // input x:int; - // } - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "federated reactor {", - " input x:int;", - "}" - ); + + String testCase = """ + target C; + federated reactor { + input x:int; + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getInput(), null, "Main reactor cannot have inputs."); } @Test public void testMainHasOutput() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // main reactor { - // output x:int; - // } - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor {", - " output x:int;", - "}" - ); + + String testCase = """ + target C; + main reactor { + output x:int; + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getOutput(), null, "Main reactor cannot have outputs."); } @Test public void testFederatedHasOutput() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // federated reactor { - // output x:int; - // } - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "federated reactor {", - " output x:int;", - "}" - ); + + String testCase = """ + target C; + federated reactor { + output x:int; + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getOutput(), null, "Main reactor cannot have outputs."); } @Test public void testMultipleMainReactor() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // main reactor A {} - // main reactor A {} - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor A {}", - "main reactor A {}" - ); + + String testCase = """ + target C; + main reactor A {} + main reactor A {} + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getReactor(), null, "Multiple definitions of main or federated reactor."); } @Test public void testMultipleMainReactorUnnamed() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // main reactor {} - // main reactor {} - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor {}", - "main reactor {}" - ); + + String testCase = """ + target C; + main reactor {} + main reactor {} + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getReactor(), null, "Multiple definitions of main or federated reactor."); } @Test public void testMultipleFederatedReactor() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // federated reactor A {} - // federated reactor A {} - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "federated reactor A {}", - "federated reactor A {}" - ); + String testCase = """ + target C; + federated reactor A {} + federated reactor A {} + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getReactor(), null, "Multiple definitions of main or federated reactor."); } @Test public void testMultipleMainOrFederatedReactor() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // federated reactor A {} - // federated reactor A {} - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor A {}", - "federated reactor A {}" - ); + + String testCase = """ + target C; + federated reactor A {} + federated reactor A {} + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getReactor(), null, "Multiple definitions of main or federated reactor."); } @Test public void testMainReactorHasHost() throws Exception { - // Java 17: - // String testCase = """ - // target C; - // main reactor at 127.0.0.1{} - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target C;", - "main reactor at 127.0.0.1{}" - ); + String testCase = """ + target C; + main reactor at 127.0.0.1{} + """; // TODO: Uncomment and fix test // List issues = validator.validate(parseWithoutError(testCase)); // Assertions.assertTrue(issues.size() == 1 && @@ -2245,16 +1636,11 @@ public void testMainReactorHasHost() throws Exception { @Test public void testUnrecognizedTarget() throws Exception { - // Java 17: - // String testCase = """ - // target Pjthon; - // main reactor {} - // """ - // Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "target Pjthon;", - "main reactor {}" - ); + + String testCase = """ + target Pjthon; + main reactor {} + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getTargetDecl(), null, "Unrecognized target: Pjthon"); } @@ -2296,132 +1682,132 @@ public void testWrongParamType() throws Exception { @Test public void testInitialMode() throws Exception { String testCase = """ - target C; - main reactor { - mode M {} - } - """; + target C; + main reactor { + mode M {} + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getReactor(), null, - "Every modal reactor requires one initial mode."); + "Every modal reactor requires one initial mode."); } @Test public void testInitialModes() throws Exception { String testCase = """ - target C; - main reactor { - initial mode IM1 {} - initial mode IM2 {} - } - """; + target C; + main reactor { + initial mode IM1 {} + initial mode IM2 {} + } + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getReactor(), null, - "A modal reactor can only have one initial mode."); + "A modal reactor can only have one initial mode."); } @Test public void testModeStateNamespace() throws Exception { String testCase = """ - target C; - main reactor { - initial mode IM { - state s:int; - } - mode M { - state s:int; + target C; + main reactor { + initial mode IM { + state s:int; + } + mode M { + state s:int; + } } - } - """; + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getStateVar(), null, - "Duplicate state variable 's'. (State variables are currently scoped on reactor level not modes)"); + "Duplicate state variable 's'. (State variables are currently scoped on reactor level not modes)"); } @Test public void testModeTimerNamespace() throws Exception { String testCase = """ - target C; - main reactor { - initial mode IM { - timer t; - } - mode M { - timer t; + target C; + main reactor { + initial mode IM { + timer t; + } + mode M { + timer t; + } } - } - """; + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getTimer(), null, - "Duplicate Timer 't'. (Timers are currently scoped on reactor level not modes)"); + "Duplicate Timer 't'. (Timers are currently scoped on reactor level not modes)"); } @Test public void testModeActionNamespace() throws Exception { String testCase = """ - target C; - main reactor { - initial mode IM { - logical action a; - } - mode M { - logical action a; + target C; + main reactor { + initial mode IM { + logical action a; + } + mode M { + logical action a; + } } - } - """; + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getAction(), null, - "Duplicate Action 'a'. (Actions are currently scoped on reactor level not modes)"); + "Duplicate Action 'a'. (Actions are currently scoped on reactor level not modes)"); } @Test public void testModeInstanceNamespace() throws Exception { String testCase = """ - target C; - reactor R {} - main reactor { - initial mode IM { - r = new R(); - } - mode M { - r = new R(); + target C; + reactor R {} + main reactor { + initial mode IM { + r = new R(); + } + mode M { + r = new R(); + } } - } - """; + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getInstantiation(), null, - "Duplicate Instantiation 'r'. (Instantiations are currently scoped on reactor level not modes)"); + "Duplicate Instantiation 'r'. (Instantiations are currently scoped on reactor level not modes)"); } @Test public void testMissingModeStateReset() throws Exception { String testCase = """ - target C; - main reactor { - initial mode IM { - reaction(startup) -> M {==} - } - mode M { - state s:int(0); + target C; + main reactor { + initial mode IM { + reaction(startup) -> M {==} + } + mode M { + state s:int(0); + } } - } - """; + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getMode(), null, - "State variable is not reset upon mode entry. It is neither marked for automatic reset nor is there a reset reaction."); + "State variable is not reset upon mode entry. It is neither marked for automatic reset nor is there a reset reaction."); } @Test public void testMissingModeStateResetInstance() throws Exception { String testCase = """ - target C; - reactor R { - state s:int(0); - } - main reactor { - initial mode IM { - reaction(startup) -> M {==} + target C; + reactor R { + state s:int(0); } - mode M { - r = new R(); + main reactor { + initial mode IM { + reaction(startup) -> M {==} + } + mode M { + r = new R(); + } } - } - """; + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getMode(), null, - "This reactor contains state variables that are not reset upon mode entry: " + "This reactor contains state variables that are not reset upon mode entry: " + "s in R" + ".\nThe state variables are neither marked for automatic reset nor have a dedicated reset reaction. " + "It is usafe to instatiate this reactor inside a mode entered with reset."); @@ -2430,13 +1816,13 @@ public void testMissingModeStateResetInstance() throws Exception { @Test public void testModeStateResetWithoutInitialValue() throws Exception { String testCase = """ - target C; - main reactor { - initial mode IM { - reset state s:int; + target C; + main reactor { + initial mode IM { + reset state s:int; + } } - } - """; + """; validator.assertError(parseWithoutError(testCase), LfPackage.eINSTANCE.getStateVar(), null, "The state variable can not be automatically reset without an initial value."); } @@ -2444,18 +1830,18 @@ public void testModeStateResetWithoutInitialValue() throws Exception { @Test public void testUnspecifiedTransitionType() throws Exception { String testCase = """ - target C; - main reactor { - initial mode IM { - reaction(startup) -> M {==} - } - mode M { - reset state s:int(0); + target C; + main reactor { + initial mode IM { + reaction(startup) -> M {==} + } + mode M { + reset state s:int(0); + } } - } - """; + """; validator.assertWarning(parseWithoutError(testCase), LfPackage.eINSTANCE.getReaction(), null, - "You should specifiy a transition type! " + "You should specifiy a transition type! " + "Reset and history transitions have different effects on this target mode. " + "Currently, a reset type is implicitly assumed."); }