diff --git a/agama/engine/src/test/java/io/jans/agama/test/InexistentFlowTest.java b/agama/engine/src/test/java/io/jans/agama/test/InexistentFlowTest.java
new file mode 100644
index 00000000000..a5d04dfb05c
--- /dev/null
+++ b/agama/engine/src/test/java/io/jans/agama/test/InexistentFlowTest.java
@@ -0,0 +1,17 @@
+package io.jans.agama.test;
+
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+public class InexistentFlowTest extends BaseTest {
+
+ @Test
+ public void test() {
+ HtmlPage page = launch("flow" + Math.random(), null);
+ assertFalse(page.getUrl().toString().endsWith(".fls"));
+ }
+
+}
diff --git a/agama/engine/src/test/java/io/jans/agama/test/MathFlowTest.java b/agama/engine/src/test/java/io/jans/agama/test/MathFlowTest.java
index 1d5ebeead10..7bc90353edf 100644
--- a/agama/engine/src/test/java/io/jans/agama/test/MathFlowTest.java
+++ b/agama/engine/src/test/java/io/jans/agama/test/MathFlowTest.java
@@ -11,7 +11,6 @@
import static org.testng.Assert.*;
-@org.testng.annotations.Ignore
public class MathFlowTest extends BaseTest {
private static final String QNAME = "io.jans.agama.test.math";
diff --git a/agama/engine/src/test/java/io/jans/agama/test/UidOnlyAuthTest.java b/agama/engine/src/test/java/io/jans/agama/test/UidOnlyAuthTest.java
index ef04eb25d94..d4d290e5c78 100644
--- a/agama/engine/src/test/java/io/jans/agama/test/UidOnlyAuthTest.java
+++ b/agama/engine/src/test/java/io/jans/agama/test/UidOnlyAuthTest.java
@@ -1,12 +1,10 @@
package io.jans.agama.test;
+import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
-import java.util.Arrays;
-import java.util.ArrayList;
import java.util.Collections;
-import java.util.List;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Parameters;
@@ -26,27 +24,24 @@ public void enableJS() {
@Test
public void randUid() {
- HtmlPage page = start("" + Math.random());
- page = proceed(page);
- assertOK(page);
+ start("" + Math.random());
+ HtmlPage page = (HtmlPage) currentPageAfter(2000);
+ assertOK(page);
assertTrue(page.getUrl().toString().endsWith("error.htm"));
assertTextContained(page.getVisibleText().toLowerCase(), "failed", "authenticate");
}
-
+
@Test(dependsOnMethods = "randUid", alwaysRun = true)
@Parameters("redirectUri")
public void adminUid(String redirectUri) {
- HtmlPage page = start("admin");
- page = proceed(page);
+ start("admin");
+ Page page = currentPageAfter(2000);
+
assertOK(page);
-
- if (!page.getUrl().toString().startsWith(redirectUri)) {
- //check if this is the consent page
- assertTextContained(page.getVisibleText().toLowerCase(), "permission", "allow");
- }
+ assertTrue(page.getUrl().toString().startsWith(redirectUri));
}
@@ -59,15 +54,15 @@ private HtmlPage start(String uid) {
}
- private HtmlPage proceed(HtmlPage page) {
+ private Page currentPageAfter(long wait) {
try {
//wait for the auto-submitting javascript to execute (see finished.ftlh) and redirections to take place
- Thread.sleep(2000);
- page = (HtmlPage) client.getCurrentWindow().getEnclosedPage();
+ Thread.sleep(wait);
+ Page p = client.getCurrentWindow().getEnclosedPage();
- logger.debug("Landed at {}",page.getUrl());
- return page;
+ logger.debug("Landed at {}", p.getUrl());
+ return p;
} catch (Exception e) {
fail(e.getMessage(), e);
}
diff --git a/agama/engine/src/test/resources/flows/io.jans.agama.test.math b/agama/engine/src/test/resources/flows/io.jans.agama.test.math
index 22df7423929..f9ca23b221f 100644
--- a/agama/engine/src/test/resources/flows/io.jans.agama.test.math
+++ b/agama/engine/src/test/resources/flows/io.jans.agama.test.math
@@ -36,13 +36,11 @@ small = Call java.lang.Math#decrementExact small
Repeat small times max
divisor = Call java.lang.Math#incrementExact divisor
- k = 0
//Try to divide the numbers by 2, 3, ... small+1
- Iterate over numbers using n
+ k = Iterate over numbers using n
modulus = Call java.lang.Math#floorMod n divisor
Quit When modulus is 0
- k = Call java.lang.Math#incrementExact k
Quit When k is numbers.length
diff --git a/agama/engine/src/test/resources/testng.properties b/agama/engine/src/test/resources/testng.properties
index 125373fd648..bfdee1a2710 100644
--- a/agama/engine/src/test/resources/testng.properties
+++ b/agama/engine/src/test/resources/testng.properties
@@ -1,7 +1,7 @@
authzEndpoint=${server}/jans-auth/restv1/authorize
-redirectUri=${server}/admin-ui
+redirectUri=${server}/.well-known/openid-configuration
clientId=${clientId}
diff --git a/agama/engine/src/test/resources/testng.xml b/agama/engine/src/test/resources/testng.xml
index ec431e7e897..9a75f0fb6fb 100644
--- a/agama/engine/src/test/resources/testng.xml
+++ b/agama/engine/src/test/resources/testng.xml
@@ -40,4 +40,10 @@
+
+
+
+
+
+
diff --git a/agama/transpiler/pom.xml b/agama/transpiler/pom.xml
index e6ee15a7a09..4172ec13994 100644
--- a/agama/transpiler/pom.xml
+++ b/agama/transpiler/pom.xml
@@ -17,7 +17,23 @@
+
+
+ src/test/resources
+ true
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.19.1
+
+
+ target/test-classes/testng.xml
+
+
+
org.antlr
antlr4-maven-plugin
@@ -77,6 +93,13 @@
jackson-annotations
+
+
+ org.testng
+ testng
+ test
+
+
\ No newline at end of file
diff --git a/agama/transpiler/src/main/java/io/jans/agama/dsl/Transpiler.java b/agama/transpiler/src/main/java/io/jans/agama/dsl/Transpiler.java
index eb1f554a89b..0748ccfd824 100644
--- a/agama/transpiler/src/main/java/io/jans/agama/dsl/Transpiler.java
+++ b/agama/transpiler/src/main/java/io/jans/agama/dsl/Transpiler.java
@@ -310,9 +310,14 @@ public static TranspilationResult transpile(String flowQname, Set flowQN
public static void runSyntaxCheck(String flowQname, String source)
throws SyntaxException, TranspilerException {
- Transpiler tr = new Transpiler(flowQname, null);
+ Transpiler tr = new Transpiler(flowQname, null);
tr.validateName(tr.getFlowContext(source));
}
+
+ public static void runSyntaxCheck(String source) throws SyntaxException, TranspilerException {
+ Transpiler tr = new Transpiler("", null);
+ tr.getFlowContext(source);
+ }
public static void main(String... args) throws Exception {
diff --git a/agama/transpiler/src/test/java/io/jans/agama/test/FlowUtil.java b/agama/transpiler/src/test/java/io/jans/agama/test/FlowUtil.java
new file mode 100644
index 00000000000..9acafa3e356
--- /dev/null
+++ b/agama/transpiler/src/test/java/io/jans/agama/test/FlowUtil.java
@@ -0,0 +1,48 @@
+package io.jans.agama.test;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.Files;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class FlowUtil {
+
+ private static final String EXT = "txt";
+
+ private static Logger LOG = LogManager.getLogger(FlowUtil.class);
+
+ private FlowUtil() {}
+
+ public static Map sourcesOfFolder(String parent) {
+
+ try {
+ Path path = Paths.get(parent);
+ LOG.debug("Reading files under {}", path.toAbsolutePath());
+
+ return Files.walk(path).filter(p -> p.toString().endsWith("." + EXT))
+ .map(p -> {
+
+ String code = null;
+ try {
+ code = Files.readString(p);
+ } catch (IOException e) {
+ LOG.error("Unable to read contents of {}: {}", p, e.getMessage());
+ }
+ return new SimpleEntry(p.toString(), code);
+
+ }).collect(Collectors.toMap(e -> e.getKey().toString(), e -> e.getValue().toString()));
+
+ } catch (IOException e) {
+ LOG.error(e.getMessage(), e);
+ return null;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/agama/transpiler/src/test/java/io/jans/agama/test/MalformedFlowsTest.java b/agama/transpiler/src/test/java/io/jans/agama/test/MalformedFlowsTest.java
new file mode 100644
index 00000000000..3b2e9f2bd21
--- /dev/null
+++ b/agama/transpiler/src/test/java/io/jans/agama/test/MalformedFlowsTest.java
@@ -0,0 +1,42 @@
+package io.jans.agama.test;
+
+import io.jans.agama.dsl.Transpiler;
+import io.jans.agama.dsl.TranspilerException;
+import io.jans.agama.dsl.error.SyntaxException;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.fail;
+
+public class MalformedFlowsTest {
+
+ private Logger logger = LogManager.getLogger(getClass());
+
+ @Test
+ public void test() {
+
+ Map map = new TreeMap<>(FlowUtil.sourcesOfFolder("target/test-classes/fail"));
+ //Sonar check likes Map.Entry instead of nicer ways to iterate like map.keySet()
+ for (Map.Entry entry: map.entrySet()) {
+ String file = entry.getKey();
+
+ try {
+ logger.info("Checking syntax of '{}'", file);
+ Transpiler.runSyntaxCheck(entry.getValue());
+
+ fail(file + " is expected to have errors but it passed validation");
+ } catch(SyntaxException | TranspilerException e) {
+ String msg = e.getMessage();
+ logger.info("{}\n", msg);
+ }
+ }
+ logger.info("{} files examined", map.size());
+ }
+
+}
diff --git a/agama/transpiler/src/test/java/io/jans/agama/test/ValidFlowsTest.java b/agama/transpiler/src/test/java/io/jans/agama/test/ValidFlowsTest.java
new file mode 100644
index 00000000000..1dfc6f33812
--- /dev/null
+++ b/agama/transpiler/src/test/java/io/jans/agama/test/ValidFlowsTest.java
@@ -0,0 +1,42 @@
+package io.jans.agama.test;
+
+import io.jans.agama.dsl.Transpiler;
+import io.jans.agama.dsl.TranspilerException;
+import io.jans.agama.dsl.error.SyntaxException;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.fail;
+
+public class ValidFlowsTest {
+
+ private Logger logger = LogManager.getLogger(getClass());
+
+ @Test
+ public void test() {
+
+ Map map = FlowUtil.sourcesOfFolder("target/test-classes/pass");
+ //Sonar check likes Map.Entry instead of nicer ways to iterate like map.keySet()
+ for (Map.Entry entry: map.entrySet()) {
+ String file = entry.getKey();
+
+ try {
+ logger.info("Checking syntax of '{}'", file);
+ Transpiler.runSyntaxCheck(entry.getValue());
+ } catch(SyntaxException | TranspilerException e) {
+ String msg = e.getMessage();
+ logger.error("{}\n", msg);
+
+ fail(file + " has errors", e);
+ }
+ }
+ logger.info("{} files examined", map.size());
+
+ }
+
+}
\ No newline at end of file
diff --git a/agama/transpiler/src/test/resources/fail/1-literals/01.txt b/agama/transpiler/src/test/resources/fail/1-literals/01.txt
new file mode 100644
index 00000000000..42a4ae33e4a
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/1-literals/01.txt
@@ -0,0 +1,6 @@
+Flow flow
+ Basepath ""
+
+x = "\""
+
+//Failure reason: string literals cannot contain double quotes inside; last quote is hanging
diff --git a/agama/transpiler/src/test/resources/fail/1-literals/02.txt b/agama/transpiler/src/test/resources/fail/1-literals/02.txt
new file mode 100644
index 00000000000..d948a2c3dda
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/1-literals/02.txt
@@ -0,0 +1,6 @@
+Flow flow
+ Basepath ""
+
+x = .5
+
+//Failure reason: a digit is expected before decimal separator
diff --git a/agama/transpiler/src/test/resources/fail/1-literals/03.txt b/agama/transpiler/src/test/resources/fail/1-literals/03.txt
new file mode 100644
index 00000000000..c6c142ed320
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/1-literals/03.txt
@@ -0,0 +1,6 @@
+Flow flow
+ Basepath ""
+
+x = 'hello'
+
+//Failure reason: string literals are surrounded by double quotes only
diff --git a/agama/transpiler/src/test/resources/fail/1-literals/04.txt b/agama/transpiler/src/test/resources/fail/1-literals/04.txt
new file mode 100644
index 00000000000..b7f9179b0de
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/1-literals/04.txt
@@ -0,0 +1,6 @@
+Flow flow
+ Basepath ""
+
+x = { "year": 2022, "color": "blue" }
+
+//Failure reason: map literals are not JSON-like but more like Javascript objects
diff --git a/agama/transpiler/src/test/resources/fail/1-literals/05.txt b/agama/transpiler/src/test/resources/fail/1-literals/05.txt
new file mode 100644
index 00000000000..d513174bd29
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/1-literals/05.txt
@@ -0,0 +1,8 @@
+Flow flow
+ Basepath ""
+
+x = [
+ 1,
+ 2 ]
+
+//Failure reason: in arrays, only commas can be surrounded by new lines
diff --git a/agama/transpiler/src/test/resources/fail/1-literals/06.txt b/agama/transpiler/src/test/resources/fail/1-literals/06.txt
new file mode 100644
index 00000000000..26426a0813d
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/1-literals/06.txt
@@ -0,0 +1,9 @@
+Flow flow
+ Basepath ""
+
+x = { for: "you",
+ function: [ "properly" ], goto: {}
+
+}
+
+//Failure reason: in maps, only commas can be surrounded by new lines
diff --git a/agama/transpiler/src/test/resources/fail/2-variables/01.txt b/agama/transpiler/src/test/resources/fail/2-variables/01.txt
new file mode 100644
index 00000000000..f26cfd1c947
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/2-variables/01.txt
@@ -0,0 +1,6 @@
+Flow flow
+ Basepath ""
+
+_hey = "you"
+
+//Failure reason: invalid variable name (underscored prefixed)
diff --git a/agama/transpiler/src/test/resources/fail/2-variables/02.txt b/agama/transpiler/src/test/resources/fail/2-variables/02.txt
new file mode 100644
index 00000000000..146401aac63
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/2-variables/02.txt
@@ -0,0 +1,6 @@
+Flow flow
+ Basepath ""
+
+yO0_ = { weird.Key = false }
+
+//Failure reason: invalid key name (period character)
diff --git a/agama/transpiler/src/test/resources/fail/2-variables/03.txt b/agama/transpiler/src/test/resources/fail/2-variables/03.txt
new file mode 100644
index 00000000000..5c94735d0b6
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/2-variables/03.txt
@@ -0,0 +1,6 @@
+Flow flow
+ Basepath ""
+
+x = y.oh-me
+
+//Failure reason: invalid access to key with special character in name (hyphen)
diff --git a/agama/transpiler/src/test/resources/fail/2-variables/04.txt b/agama/transpiler/src/test/resources/fail/2-variables/04.txt
new file mode 100644
index 00000000000..f261a376b34
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/2-variables/04.txt
@@ -0,0 +1,6 @@
+Flow flow
+ Basepath ""
+
+x = y["hi"]
+
+//Failure reason: only a positive number or variable name is allowed for list indexing
diff --git a/agama/transpiler/src/test/resources/fail/2-variables/05.txt b/agama/transpiler/src/test/resources/fail/2-variables/05.txt
new file mode 100644
index 00000000000..066160dadb9
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/2-variables/05.txt
@@ -0,0 +1,6 @@
+Flow flow
+ Basepath ""
+
+x = y[ z[0] ]
+
+//Failure reason: only a positive number or variable name is allowed for list indexing
diff --git a/agama/transpiler/src/test/resources/fail/2-variables/06.txt b/agama/transpiler/src/test/resources/fail/2-variables/06.txt
new file mode 100644
index 00000000000..4c441c2d479
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/2-variables/06.txt
@@ -0,0 +1,6 @@
+Flow flow
+ Basepath ""
+
+x = y[ z.w ]
+
+//Failure reason: only a positive number or variable name is allowed for list indexing
diff --git a/agama/transpiler/src/test/resources/fail/3-indentation/01.txt b/agama/transpiler/src/test/resources/fail/3-indentation/01.txt
new file mode 100644
index 00000000000..daaa645f449
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/3-indentation/01.txt
@@ -0,0 +1,7 @@
+Flow flow
+ Basepath ""
+
+When day is rainy
+Log me
+
+//Failure reason: at least one statement should be indented after When
diff --git a/agama/transpiler/src/test/resources/fail/3-indentation/02.txt b/agama/transpiler/src/test/resources/fail/3-indentation/02.txt
new file mode 100644
index 00000000000..5ee60e93ddb
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/3-indentation/02.txt
@@ -0,0 +1,8 @@
+Flow flow
+ Basepath ""
+
+When day is rainy
+ Log me
+ Log "cowboy music"
+
+//Failure reason: second log statement mis-aligned
diff --git a/agama/transpiler/src/test/resources/fail/3-indentation/03.txt b/agama/transpiler/src/test/resources/fail/3-indentation/03.txt
new file mode 100644
index 00000000000..2fc43925211
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/3-indentation/03.txt
@@ -0,0 +1,9 @@
+Flow flow
+ Basepath ""
+
+When day is rainy
+ Log me
+ Otherwise
+ Log "cowboy music"
+
+//Failure reason: Otherwise block statement mis-aligned
diff --git a/agama/transpiler/src/test/resources/fail/3-indentation/04.txt b/agama/transpiler/src/test/resources/fail/3-indentation/04.txt
new file mode 100644
index 00000000000..2b86b75152d
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/3-indentation/04.txt
@@ -0,0 +1,9 @@
+Flow flow
+ Basepath ""
+
+When day is rainy
+ Log me
+ Log "cowboy music"
+ Log "By Cerce"
+
+//Failure reason: second log statement mis-aligned
diff --git a/agama/transpiler/src/test/resources/fail/3-indentation/05.txt b/agama/transpiler/src/test/resources/fail/3-indentation/05.txt
new file mode 100644
index 00000000000..efb58a02802
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/3-indentation/05.txt
@@ -0,0 +1,9 @@
+Flow flow
+ Basepath ""
+
+When day is rainy
+ Log me
+ Log "cowboy music"
+ Log "By Cerce"
+
+//Failure reason: second log statement mis-aligned
diff --git a/agama/transpiler/src/test/resources/fail/3-indentation/06.txt b/agama/transpiler/src/test/resources/fail/3-indentation/06.txt
new file mode 100644
index 00000000000..f58e1c39858
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/3-indentation/06.txt
@@ -0,0 +1,7 @@
+Flow flow
+ Basepath ""
+ Configs conf
+
+Log "Eye hate god"
+
+//Failure reason: Configs statement mis-aligned
diff --git a/agama/transpiler/src/test/resources/fail/3-indentation/07.txt b/agama/transpiler/src/test/resources/fail/3-indentation/07.txt
new file mode 100644
index 00000000000..429fef80c10
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/3-indentation/07.txt
@@ -0,0 +1,7 @@
+Flow flow
+ Basepath ""
+
+ When day is rainy
+ Log me
+
+//Failure reason: When expected to be aligned to Flow
diff --git a/agama/transpiler/src/test/resources/fail/3-indentation/08.txt b/agama/transpiler/src/test/resources/fail/3-indentation/08.txt
new file mode 100644
index 00000000000..c8ddba2547b
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/3-indentation/08.txt
@@ -0,0 +1,9 @@
+Flow flow
+ Basepath ""
+
+When day is rainy
+ Log me
+ Log "cowboy music"
+ Log "By Cerce"
+
+//Failure reason: second and third log statements mis-aligned
diff --git a/agama/transpiler/src/test/resources/fail/3-indentation/09.txt b/agama/transpiler/src/test/resources/fail/3-indentation/09.txt
new file mode 100644
index 00000000000..df8b03b91a9
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/3-indentation/09.txt
@@ -0,0 +1,10 @@
+Flow flow
+ Basepath ""
+
+Match day to
+ 1
+ Log "cowboy music"
+ 2
+ Log "By Cerce"
+
+//Failure reason: second case for Match is mis-aligned
diff --git a/agama/transpiler/src/test/resources/fail/3-indentation/10.txt b/agama/transpiler/src/test/resources/fail/3-indentation/10.txt
new file mode 100644
index 00000000000..c15394ef7dd
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/3-indentation/10.txt
@@ -0,0 +1,6 @@
+ Flow flow
+ Basepath ""
+
+Log me
+
+//Failure reason: Flow declaration not aligned to column 1
diff --git a/agama/transpiler/src/test/resources/fail/4-structure/01.txt b/agama/transpiler/src/test/resources/fail/4-structure/01.txt
new file mode 100644
index 00000000000..429fef80c10
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/4-structure/01.txt
@@ -0,0 +1,7 @@
+Flow flow
+ Basepath ""
+
+ When day is rainy
+ Log me
+
+//Failure reason: When expected to be aligned to Flow
diff --git a/agama/transpiler/src/test/resources/fail/4-structure/02.txt b/agama/transpiler/src/test/resources/fail/4-structure/02.txt
new file mode 100644
index 00000000000..a8d75256cb5
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/4-structure/02.txt
@@ -0,0 +1,11 @@
+Flow flow
+ Basepath ""
+
+When day is rainy
+ Log me
+Otherwise
+ Log "cowboy music"
+Otherwise
+ Log "By Cerce"
+
+//Failure reason: unexpected second Otherwise block
diff --git a/agama/transpiler/src/test/resources/fail/4-structure/03.txt b/agama/transpiler/src/test/resources/fail/4-structure/03.txt
new file mode 100644
index 00000000000..e1134acf04f
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/4-structure/03.txt
@@ -0,0 +1,11 @@
+Flow flow
+ Basepath ""
+
+When day is rainy
+ Log me
+Otherwise When there is hope
+ Log "cowboy music"
+Otherwise
+ Log "By Cerce"
+
+//Failure reason: Otherwise-When does not exist
diff --git a/agama/transpiler/src/test/resources/fail/4-structure/04.txt b/agama/transpiler/src/test/resources/fail/4-structure/04.txt
new file mode 100644
index 00000000000..5076a94ce76
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/4-structure/04.txt
@@ -0,0 +1,12 @@
+Flow flow
+ Basepath ""
+
+When day is rainy
+ When there is cold
+ Log me
+ Otherwise
+ Log "cowboy music"
+ Otherwise
+ Log "By Cerce"
+
+//Failure reason: unexpected second Otherwise block
diff --git a/agama/transpiler/src/test/resources/fail/4-structure/05.txt b/agama/transpiler/src/test/resources/fail/4-structure/05.txt
new file mode 100644
index 00000000000..05b665b50cf
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/4-structure/05.txt
@@ -0,0 +1,13 @@
+Flow flow
+ Basepath ""
+
+When day is rainy
+ Repeat k times max
+ When there is cold
+ Log me
+ Otherwise
+ Log "cowboy music"
+ Otherwise
+ Log "By Cerce"
+
+//Failure reason: unexpected Otherwise block for Repeat
diff --git a/agama/transpiler/src/test/resources/fail/4-structure/06.txt b/agama/transpiler/src/test/resources/fail/4-structure/06.txt
new file mode 100644
index 00000000000..2f3132f61a0
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/4-structure/06.txt
@@ -0,0 +1,8 @@
+Flow flow
+ Basepath ""
+
+Repeat k times max
+ Quit When there is cold
+ Log me
+
+//Failure reason: unexpected indented block under Quit-When
diff --git a/agama/transpiler/src/test/resources/fail/4-structure/07.txt b/agama/transpiler/src/test/resources/fail/4-structure/07.txt
new file mode 100644
index 00000000000..6b1b9a69045
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/4-structure/07.txt
@@ -0,0 +1,9 @@
+Flow flow
+ Basepath ""
+
+Repeat k times max
+ Quit When there is cold
+ Otherwise
+ Log me
+
+//Failure reason: unexpected Otherwise block
diff --git a/agama/transpiler/src/test/resources/fail/4-structure/08.txt b/agama/transpiler/src/test/resources/fail/4-structure/08.txt
new file mode 100644
index 00000000000..fa6e6c3cd31
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/4-structure/08.txt
@@ -0,0 +1,9 @@
+Flow flow
+ Basepath ""
+
+Repeat k times max
+ Quit When there is cold
+ Log me
+ Quit When there is heat
+
+//Failure reason: unexpected (second) Quit-When
diff --git a/agama/transpiler/src/test/resources/fail/4-structure/09.txt b/agama/transpiler/src/test/resources/fail/4-structure/09.txt
new file mode 100644
index 00000000000..6e6f32dbbc5
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/4-structure/09.txt
@@ -0,0 +1,7 @@
+Flow flow
+ Basepath ""
+
+Quit When there is cold
+Log me
+
+//Failure reason: orphan Quit-When
diff --git a/agama/transpiler/src/test/resources/fail/4-structure/10.txt b/agama/transpiler/src/test/resources/fail/4-structure/10.txt
new file mode 100644
index 00000000000..fbf1307ed82
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/4-structure/10.txt
@@ -0,0 +1,8 @@
+Flow flow
+ Basepath ""
+
+Trigger co.wboy.music
+ When there is cold
+ Override Templates "path/basic.ftl" ""
+
+//Failure reason: unexpected When block under Trigger
diff --git a/agama/transpiler/src/test/resources/fail/4-structure/11.txt b/agama/transpiler/src/test/resources/fail/4-structure/11.txt
new file mode 100644
index 00000000000..c30ba7563c5
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/4-structure/11.txt
@@ -0,0 +1,8 @@
+Flow flow
+ Basepath ""
+
+Trigger co.wboy.music
+ Repeat 3 times max
+ Log idx[0]
+
+//Failure reason: unexpected Repeat block under Trigger
diff --git a/agama/transpiler/src/test/resources/fail/4-structure/12.txt b/agama/transpiler/src/test/resources/fail/4-structure/12.txt
new file mode 100644
index 00000000000..c6ef0e8a575
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/4-structure/12.txt
@@ -0,0 +1,7 @@
+Flow flow
+ Basepath ""
+
+Finish probably
+ When there is time
+
+//Failure reason: unexpected When block under Finish
diff --git a/agama/transpiler/src/test/resources/fail/4-structure/13.txt b/agama/transpiler/src/test/resources/fail/4-structure/13.txt
new file mode 100644
index 00000000000..66682a3387b
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/4-structure/13.txt
@@ -0,0 +1,8 @@
+Flow flow
+ Basepath ""
+ Configs conf
+ Timeout 100 seconds
+
+Finish true
+
+//Failure reason: header scrambled: Timeout declaration expected before Configs
diff --git a/agama/transpiler/src/test/resources/fail/4-structure/14.txt b/agama/transpiler/src/test/resources/fail/4-structure/14.txt
new file mode 100644
index 00000000000..c44b8a4de0b
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/4-structure/14.txt
@@ -0,0 +1,10 @@
+Flow flow
+ Basepath ""
+ Inputs A B Road
+
+Finish true
+
+null
+wtf
+
+//Failure reason: code is parsed to a certain point but there is a un-consumed remainder
\ No newline at end of file
diff --git a/agama/transpiler/src/test/resources/fail/5-misc/01.txt b/agama/transpiler/src/test/resources/fail/5-misc/01.txt
new file mode 100644
index 00000000000..288cb92f195
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/5-misc/01.txt
@@ -0,0 +1,4 @@
+Flow 22AcaciaAvenue
+ Basepath "foo"
+
+//Failure reason: invalid flow qualified name
diff --git a/agama/transpiler/src/test/resources/fail/5-misc/02.txt b/agama/transpiler/src/test/resources/fail/5-misc/02.txt
new file mode 100644
index 00000000000..7fc1c4ef930
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/5-misc/02.txt
@@ -0,0 +1,6 @@
+Flow oh.whammy.bar
+ Basepath "bar"
+
+Finish { success: true }
+
+//Failure reason: Expected boolean/string literal or a variable expression for Finish
diff --git a/agama/transpiler/src/test/resources/fail/5-misc/03.txt b/agama/transpiler/src/test/resources/fail/5-misc/03.txt
new file mode 100644
index 00000000000..5e3b26a9838
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/5-misc/03.txt
@@ -0,0 +1,6 @@
+Flow D.I.Y
+ Basepath "diy"
+
+Call var [1, 2 , 4]
+
+//Failure reason: List literals not allowed in a Call
diff --git a/agama/transpiler/src/test/resources/fail/5-misc/04.txt b/agama/transpiler/src/test/resources/fail/5-misc/04.txt
new file mode 100644
index 00000000000..d80bd94ee9c
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/5-misc/04.txt
@@ -0,0 +1,6 @@
+Flow D.I.Y
+ Basepath "diy"
+
+x.a | x.b = Call var arg1 arg2 arg3
+
+//Failure reason: only a simple variable expression (e.g. x, myvar_2) can be used to catch a Java Throwable if any, in a Call
diff --git a/agama/transpiler/src/test/resources/fail/5-misc/05.5xt b/agama/transpiler/src/test/resources/fail/5-misc/05.5xt
new file mode 100644
index 00000000000..948bce161cc
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/5-misc/05.5xt
@@ -0,0 +1,7 @@
+Flow P.O.N.X
+ Basepath "punx"
+
+punk = Trigger co.co.nut
+ Override templates "path/form.ftl" "myform.ftl" "formly.ftl"
+
+//Failure reason: odd number of parameters passed to Override templates; 2, 4, 6 ... expected
diff --git a/agama/transpiler/src/test/resources/fail/5-misc/06.txt b/agama/transpiler/src/test/resources/fail/5-misc/06.txt
new file mode 100644
index 00000000000..82c92ae1485
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/5-misc/06.txt
@@ -0,0 +1,9 @@
+Flow S.L.E.E.P
+ Basepath ""
+
+punk = Trigger co.co.nut
+ Override templates "path/form.ftl" "myform.ftl"
+ "formly.ftl"
+ "dreary.ftl"
+
+//Failure reason: every pair of paths must be supplied in the same line
diff --git a/agama/transpiler/src/test/resources/fail/5-misc/07.txt b/agama/transpiler/src/test/resources/fail/5-misc/07.txt
new file mode 100644
index 00000000000..793d2919b9b
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/5-misc/07.txt
@@ -0,0 +1,7 @@
+Flow L.I.F.E
+ Basepath ""
+
+x = 1
+y = x--
+
+//Failure reason: -- not recognized. No arithmetic operators in Agama
diff --git a/agama/transpiler/src/test/resources/fail/5-misc/08.txt b/agama/transpiler/src/test/resources/fail/5-misc/08.txt
new file mode 100644
index 00000000000..820674d3a6f
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/5-misc/08.txt
@@ -0,0 +1,7 @@
+Flow L.I.F.E_2
+ Basepath ""
+
+x = 0
+y = x + 1
+
+//Failure reason: + not recognized. No arithmetic operators in Agama
diff --git a/agama/transpiler/src/test/resources/fail/5-misc/09.txt b/agama/transpiler/src/test/resources/fail/5-misc/09.txt
new file mode 100644
index 00000000000..ef160148b9a
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/5-misc/09.txt
@@ -0,0 +1,6 @@
+Flow D.I.D
+ Basepath "dad"
+
+x.a = Call java.lang.Math#min 1 (Call java.lang.Math#max 2 3)
+
+//Failure reason: parenthesis not supported in Agama
diff --git a/agama/transpiler/src/test/resources/fail/5-misc/10.txt b/agama/transpiler/src/test/resources/fail/5-misc/10.txt
new file mode 100644
index 00000000000..75582697a5a
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/5-misc/10.txt
@@ -0,0 +1,6 @@
+Flow flow
+ Basepath ""
+
+RRF form.ftl data
+
+//Failure reason: first parameter of RRF expected to be a string literal
diff --git a/agama/transpiler/src/test/resources/fail/5-misc/11.txt b/agama/transpiler/src/test/resources/fail/5-misc/11.txt
new file mode 100644
index 00000000000..aebb7d17998
--- /dev/null
+++ b/agama/transpiler/src/test/resources/fail/5-misc/11.txt
@@ -0,0 +1,8 @@
+Flow flow
+ Basepath ""
+
+/*
+Log aha
+*/
+
+//Failure reason: /* and */ not part of the language
\ No newline at end of file
diff --git a/agama/transpiler/src/test/resources/log4j2-test.xml b/agama/transpiler/src/test/resources/log4j2-test.xml
new file mode 100644
index 00000000000..493117549e2
--- /dev/null
+++ b/agama/transpiler/src/test/resources/log4j2-test.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/agama/transpiler/src/test/resources/pass/structure.txt b/agama/transpiler/src/test/resources/pass/structure.txt
new file mode 100644
index 00000000000..3f97d72773f
--- /dev/null
+++ b/agama/transpiler/src/test/resources/pass/structure.txt
@@ -0,0 +1,38 @@
+//This flow does not make sense, however is syntactically valid and must pass validation
+Flow flow
+ Basepath ""
+ Inputs a1 a_1 a1A_
+
+When null is false or it is late
+ // °!"#$%&/()=?¡
+ Log "a" "A" "aha!" -10
+ Finish me
+Otherwise
+ When 1 is not 100000 and
+ car.model is "mayhem"
+ Finish "you"
+
+ Match pi to
+ 3.14
+ Finish obj
+ 2.71
+ Finish nonsense.phi
+ Otherwise
+ Finish a[0]
+
+Repeat x[1] times max
+ o."-x" = RFAC "jojo.ftlh"
+ RFAC o[Y]
+
+ Quit When it is not early
+ Log idx[0]
+ When number is prime
+ Finish men
+
+Iterate over centuries using glasses
+ k9 = Iterate over planets using a_skirt
+ RRF "day_dream.ftl"
+ RRF "night_dream.ftl" angus
+ o = RRF "night_dream.ftl" angus true
+
+ Log "what % % %?" "are" "you" "smoking"
diff --git a/agama/transpiler/src/test/resources/pass/triggers_calls.txt b/agama/transpiler/src/test/resources/pass/triggers_calls.txt
new file mode 100644
index 00000000000..4f8a0f7c822
--- /dev/null
+++ b/agama/transpiler/src/test/resources/pass/triggers_calls.txt
@@ -0,0 +1,26 @@
+//This flow does not make sense, however is syntactically valid and must pass validation
+Flow flow
+ Basepath "oh/man"
+
+When pepperoni is forgotten
+ Trigger oh.ho
+ o."-x" = Trigger oh.no some params.here
+
+Trigger $bah.humbug no params
+ Override templates "pea/body.ftl" "" "pea/media.ftl" "fluff.ftl"
+ "caravan.ftl" "../whoops.ftlh"
+
+x256 = Call java.lang.Math#incrementExact 255
+
+n | E = Call java.lang.Integer#parseInt "AGA" 16
+When E is not null
+ Log "An unexpected error has occurred at %" null
+
+x.a[0] = Call x.a[2] method
+Call anda le param1 param2
+
+minus1 = Call java.math.BigInteger#new "-1"
+
+bigcls = Call java.math.BigInteger#class
+bigcls = Call minus1 getClass
+bigcls = minus1.class
diff --git a/agama/transpiler/src/test/resources/pass/variables.txt b/agama/transpiler/src/test/resources/pass/variables.txt
new file mode 100644
index 00000000000..36e7bcbcffd
--- /dev/null
+++ b/agama/transpiler/src/test/resources/pass/variables.txt
@@ -0,0 +1,29 @@
+//This flow does not make sense, however is syntactically valid and must pass validation
+Flow flow
+ Basepath ""
+
+x = True // "True" is a valid variable name
+
+y = [ zero, False, void, return, for, while, continue ] // these are all valid variable names too
+
+y = { function: f, NaN: None, undefined: null }
+
+y = []
+
+// valid variable access (from a syntax view point)
+x = y.length
+x = y.size
+x = who.knows
+x = maybe[you]
+x = x."- wow!"
+x = x.$y
+x = x.$y[3].do
+x = y.null
+
+x = [ "no", "such", "thing"
+, "as", "a",
+ "stupid","question"]
+
+y = { hey: "ho",
+ let: "go"
+ , foo: { bar: {} } }
diff --git a/agama/transpiler/src/test/resources/testng.xml b/agama/transpiler/src/test/resources/testng.xml
new file mode 100644
index 00000000000..ab04c4f12b7
--- /dev/null
+++ b/agama/transpiler/src/test/resources/testng.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/admin/developer/agama/faq.md b/docs/admin/developer/agama/faq.md
index 7910bee801f..e72a0360850 100644
--- a/docs/admin/developer/agama/faq.md
+++ b/docs/admin/developer/agama/faq.md
@@ -124,7 +124,9 @@ This is to avoid traversing big structures fully. You can increase the value of
### How to add two numbers or compare numeric values in Agama?
-Agama only provides operators for boolean comparison in conditional statements. The structure of an authentication flow will rarely have to deal with computations/comparisons of numbers, strings, etc. In case this is needed, developers have to resort to Java.
+Agama only provides operators for equality check in conditional statements. The structure of an authentication flow will rarely have to deal with computations/comparisons of numbers, strings, etc. In case this is needed, developers have to resort to Java.
+
+_Hint_: some methods like `addExact`, `incrementExact`, etc. in `java.lang.Math` might help.
### How to concatenate strings in Agama?
@@ -139,6 +141,10 @@ Call java.lang.String#join "" strings
See the examples in the Looping section of the DSL [full reference](./dsl-full.md#looping).
+## How to know the number of iterations carried out by a loop once it has finished?
+
+You can assign this value to a variable at the top of your loop declaration. See the examples in the Looping section of the DSL [full reference](./dsl-full.md#looping).
+
### Can Agama code be called from Java?
No. These two languages are supposed to play roles that should not be mixed, check [here](./dsl.md#introduction) and [here](./lifecycle.md#design-and-code).