From 3ba062c7dc997b64f09509b0eeed71be9bd2c185 Mon Sep 17 00:00:00 2001 From: Atharva Patil Date: Sun, 19 Mar 2023 22:31:23 -0700 Subject: [PATCH 01/10] Added a test to ensure target properties are set correctly in Lfc. --- .../lflang/tests/cli/CliToolTestFixture.java | 82 +++++++++++++++++++ .../src/org/lflang/tests/cli/LfcCliTest.java | 77 ++++++++++++++++- org.lflang/src/org/lflang/cli/Lfc.java | 2 +- 3 files changed, 159 insertions(+), 2 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java b/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java index 83e7817618..a38f656dd6 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java @@ -31,6 +31,7 @@ import java.io.ByteArrayOutputStream; import java.io.PrintStream; +import java.io.PrintWriter; import java.nio.file.Path; import java.util.concurrent.Callable; import java.util.function.Consumer; @@ -39,6 +40,9 @@ import org.opentest4j.AssertionFailedError; import org.lflang.cli.Io; +import org.lflang.cli.Lfc; + +import picocli.CommandLine; /** * Test utilities for a CLI tool, eg {@link org.lflang.cli.Lfc}, @@ -87,6 +91,36 @@ public ExecutionResult run(Path wd, String... args) { return new ExecutionResult(out, err, exitCode); } + /** + * Run and return and Lfc instance with the given arguments, in the given + * working directory. + * + * @param wd working directory + * @param args Arguments + * @return The execution result + */ + public LfcObjExecutionResult runLfcObj(Path wd, String... args) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayOutputStream err = new ByteArrayOutputStream(); + + Io testIo = new Io( + new PrintStream(err), + new PrintStream(out), + wd + ); + // Main instance. + final Lfc lfcObj = new Lfc(); + // Parse arguments and execute main logic. + int exitCode = testIo.fakeSystemExit(io -> ( + new CommandLine(lfcObj) + .setOut(new PrintWriter(io.getOut())) + .setErr(new PrintWriter(io.getErr())) + ).execute(args) + ); + + return new LfcObjExecutionResult(out, err, exitCode, lfcObj); + } + /** * The result of an execution of a CLI program like LFC. * @@ -158,4 +192,52 @@ interface ThrowingConsumer { void accept(T t) throws Exception; } } + + /** + * The result, including class instance, of an execution of a CLI program + * like LFC. + * + * @param out Output stream + * @param err Error stream + * @param exitCode Exit code of the process + */ + record LfcObjExecutionResult( + ByteArrayOutputStream out, + ByteArrayOutputStream err, + int exitCode, + Lfc lfcObj + ) { + public void checkOk() { + assertEquals(0, exitCode); + } + + /** + * Use this method to wrap assertions. + */ + public void verify(ThrowingConsumer actions) { + try { + actions.accept(this); + } catch (Exception | AssertionFailedError e) { + System.out.println("TEST FAILED"); + System.out.println("> Return code: " + exitCode); + System.out.println("> Standard output -------------------------"); + System.err.println(out.toString()); + System.out.println("> Standard error --------------------------"); + System.err.println(err.toString()); + System.out.println("> -----------------------------------------"); + + if (e instanceof Exception) { + throw new AssertionFailedError("Expected no exception to be thrown", e); + } + throw (AssertionFailedError) e; + } + } + + + @FunctionalInterface + interface ThrowingConsumer { + void accept(T t) throws Exception; + } + } + } diff --git a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java index 4cec8b2dd3..a732c420f1 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java @@ -26,13 +26,16 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.lflang.tests.TestUtils.TempDirBuilder.dirBuilder; import static org.lflang.tests.TestUtils.TempDirChecker.dirChecker; import static org.lflang.tests.TestUtils.isDirectory; import static org.lflang.tests.TestUtils.isRegularFile; import java.io.IOException; +import java.lang.reflect.Method; import java.nio.file.Path; +import java.util.Properties; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -40,6 +43,7 @@ import org.lflang.LocalStrings; import org.lflang.cli.Io; import org.lflang.cli.Lfc; +import org.lflang.generator.LFGeneratorContext.BuildParm; /** * @author Clément Fournier @@ -101,10 +105,81 @@ public void testGenInSrcDir(@TempDir Path tempDir) throws IOException { } + @Test + public void testTargetProperties(@TempDir Path tempDir) + throws IOException { + dirBuilder(tempDir).file("src/File.lf", LF_PYTHON_FILE); - static class LfcTestFixture extends CliToolTestFixture { + String[] args = { + "src/File.lf", + "--output-path", "src", + "--build-type", "Release", + "--clean", + "--target-compiler", "gcc", + "--external-runtime-path", "src", + "--federated", + "--logging", "4", + "--lint", + "--no-compile", + "--quiet", + "--rti", "-1", + "--runtime-version", "rs", + "--scheduler", "2", + "--threading", "false", + "--workers", "1", + }; + + lfcTester.runLfcObj(tempDir, args) + .verify(result -> { + result.checkOk(); + // Get the properties method. + Method getPropsMethod = + Lfc.class.getDeclaredMethod("filterPassOnProps"); + // Change the method's visibility to public for testing. + getPropsMethod.setAccessible(true); + Properties properties = + (Properties) getPropsMethod.invoke(result.lfcObj()); + assertEquals( + properties.getProperty(BuildParm.BUILD_TYPE.getKey()), + "Release"); + assertEquals( + properties.getProperty(BuildParm.CLEAN.getKey()), + "true"); + assertEquals( + properties.getProperty( + BuildParm.EXTERNAL_RUNTIME_PATH.getKey()), + "src"); + assertEquals( + properties.getProperty(BuildParm.LINT.getKey()), + "true"); + assertEquals( + properties.getProperty(BuildParm.LOGGING.getKey()), + "4"); + assertEquals( + properties.getProperty( + BuildParm.TARGET_COMPILER.getKey()), + "gcc"); + assertEquals( + properties.getProperty(BuildParm.QUIET.getKey()), + "true"); + assertEquals( + properties.getProperty(BuildParm.RTI.getKey()), + "-1"); + assertEquals( + properties.getProperty( + BuildParm.RUNTIME_VERSION.getKey()), + "rs"); + assertEquals( + properties.getProperty(BuildParm.THREADING.getKey()), + "false"); + assertEquals( + properties.getProperty(BuildParm.WORKERS.getKey()), + "1"); + }); + } + static class LfcTestFixture extends CliToolTestFixture { @Override protected void runCliProgram(Io io, String[] args) { Lfc.main(io, args); diff --git a/org.lflang/src/org/lflang/cli/Lfc.java b/org.lflang/src/org/lflang/cli/Lfc.java index 489e9cd2f4..f3908b74ca 100644 --- a/org.lflang/src/org/lflang/cli/Lfc.java +++ b/org.lflang/src/org/lflang/cli/Lfc.java @@ -229,7 +229,7 @@ private Path getActualOutputPath(Path root, Path path) { * * @return Properties for the code generator. */ - protected Properties filterPassOnProps() { + private Properties filterPassOnProps() { Properties props = new Properties(); if (buildType != null) { From a1b9e5dbd261802e5375e1577cdd64a2e2613a45 Mon Sep 17 00:00:00 2001 From: Atharva Patil Date: Sun, 19 Mar 2023 22:39:26 -0700 Subject: [PATCH 02/10] Added author tag. --- .../src/org/lflang/tests/cli/CliToolTestFixture.java | 1 + org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java | 1 + org.lflang/src/lib/c/reactor-c | 2 +- org.lflang/src/lib/rs/reactor-rs | 2 +- org.lflang/src/lib/rs/runtime-version.properties | 2 +- 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java b/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java index a38f656dd6..c6ee569ca0 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java @@ -49,6 +49,7 @@ * {@link org.lflang.cli.Lff}. * * @author Clément Fournier + * @author Atharva Patil */ abstract class CliToolTestFixture { diff --git a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java index a732c420f1..8a48a59424 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java @@ -47,6 +47,7 @@ /** * @author Clément Fournier + * @author Atharva Patil */ public class LfcCliTest { diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index d43e973780..37293c04ba 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit d43e9737804f2d984d52a99cac20d8e57adad543 +Subproject commit 37293c04bafdd630341df82fc02ddf37a45a06f3 diff --git a/org.lflang/src/lib/rs/reactor-rs b/org.lflang/src/lib/rs/reactor-rs index 28f9460724..0f9e7238c6 160000 --- a/org.lflang/src/lib/rs/reactor-rs +++ b/org.lflang/src/lib/rs/reactor-rs @@ -1 +1 @@ -Subproject commit 28f9460724b266c263f4fdf8146b2029f4ff9d30 +Subproject commit 0f9e7238c69029537170f0b4dfe11fcd40270566 diff --git a/org.lflang/src/lib/rs/runtime-version.properties b/org.lflang/src/lib/rs/runtime-version.properties index 35b335b731..53d10e9fbc 100644 --- a/org.lflang/src/lib/rs/runtime-version.properties +++ b/org.lflang/src/lib/rs/runtime-version.properties @@ -1 +1 @@ -rs = 28f9460724b266c263f4fdf8146b2029f4ff9d30 +rs = 0f9e7238c69029537170f0b4dfe11fcd40270566 From efd98ee0b097ea8a175cf87b0bc3c86bf74f0780 Mon Sep 17 00:00:00 2001 From: Atharva Patil Date: Sun, 19 Mar 2023 22:57:54 -0700 Subject: [PATCH 03/10] Revert "Added author tag." This reverts commit a1b9e5dbd261802e5375e1577cdd64a2e2613a45. --- .../src/org/lflang/tests/cli/CliToolTestFixture.java | 1 - org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java | 1 - org.lflang/src/lib/c/reactor-c | 2 +- org.lflang/src/lib/rs/reactor-rs | 2 +- org.lflang/src/lib/rs/runtime-version.properties | 2 +- 5 files changed, 3 insertions(+), 5 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java b/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java index c6ee569ca0..a38f656dd6 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java @@ -49,7 +49,6 @@ * {@link org.lflang.cli.Lff}. * * @author Clément Fournier - * @author Atharva Patil */ abstract class CliToolTestFixture { diff --git a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java index 8a48a59424..a732c420f1 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java @@ -47,7 +47,6 @@ /** * @author Clément Fournier - * @author Atharva Patil */ public class LfcCliTest { diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index 37293c04ba..d43e973780 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 37293c04bafdd630341df82fc02ddf37a45a06f3 +Subproject commit d43e9737804f2d984d52a99cac20d8e57adad543 diff --git a/org.lflang/src/lib/rs/reactor-rs b/org.lflang/src/lib/rs/reactor-rs index 0f9e7238c6..28f9460724 160000 --- a/org.lflang/src/lib/rs/reactor-rs +++ b/org.lflang/src/lib/rs/reactor-rs @@ -1 +1 @@ -Subproject commit 0f9e7238c69029537170f0b4dfe11fcd40270566 +Subproject commit 28f9460724b266c263f4fdf8146b2029f4ff9d30 diff --git a/org.lflang/src/lib/rs/runtime-version.properties b/org.lflang/src/lib/rs/runtime-version.properties index 53d10e9fbc..35b335b731 100644 --- a/org.lflang/src/lib/rs/runtime-version.properties +++ b/org.lflang/src/lib/rs/runtime-version.properties @@ -1 +1 @@ -rs = 0f9e7238c69029537170f0b4dfe11fcd40270566 +rs = 28f9460724b266c263f4fdf8146b2029f4ff9d30 From be3c9934af69c6439f20cc35dfcc5b098091ecff Mon Sep 17 00:00:00 2001 From: Atharva Patil Date: Sun, 19 Mar 2023 22:58:53 -0700 Subject: [PATCH 04/10] Fixed author tag commit. --- .../src/org/lflang/tests/cli/CliToolTestFixture.java | 1 + org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java | 1 + 2 files changed, 2 insertions(+) diff --git a/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java b/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java index a38f656dd6..c6ee569ca0 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java @@ -49,6 +49,7 @@ * {@link org.lflang.cli.Lff}. * * @author Clément Fournier + * @author Atharva Patil */ abstract class CliToolTestFixture { diff --git a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java index a732c420f1..8a48a59424 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java @@ -47,6 +47,7 @@ /** * @author Clément Fournier + * @author Atharva Patil */ public class LfcCliTest { From fa3252224d97b7d9027d16d41c5553c23b1cc731 Mon Sep 17 00:00:00 2001 From: Atharva Patil Date: Sun, 19 Mar 2023 23:32:48 -0700 Subject: [PATCH 05/10] Changed indentation in cli test. --- .../src/org/lflang/tests/cli/LfcCliTest.java | 47 +++++-------------- 1 file changed, 11 insertions(+), 36 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java index 8a48a59424..e1ae31bf5d 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java @@ -140,42 +140,17 @@ public void testTargetProperties(@TempDir Path tempDir) getPropsMethod.setAccessible(true); Properties properties = (Properties) getPropsMethod.invoke(result.lfcObj()); - assertEquals( - properties.getProperty(BuildParm.BUILD_TYPE.getKey()), - "Release"); - assertEquals( - properties.getProperty(BuildParm.CLEAN.getKey()), - "true"); - assertEquals( - properties.getProperty( - BuildParm.EXTERNAL_RUNTIME_PATH.getKey()), - "src"); - assertEquals( - properties.getProperty(BuildParm.LINT.getKey()), - "true"); - assertEquals( - properties.getProperty(BuildParm.LOGGING.getKey()), - "4"); - assertEquals( - properties.getProperty( - BuildParm.TARGET_COMPILER.getKey()), - "gcc"); - assertEquals( - properties.getProperty(BuildParm.QUIET.getKey()), - "true"); - assertEquals( - properties.getProperty(BuildParm.RTI.getKey()), - "-1"); - assertEquals( - properties.getProperty( - BuildParm.RUNTIME_VERSION.getKey()), - "rs"); - assertEquals( - properties.getProperty(BuildParm.THREADING.getKey()), - "false"); - assertEquals( - properties.getProperty(BuildParm.WORKERS.getKey()), - "1"); + assertEquals(properties.getProperty(BuildParm.BUILD_TYPE.getKey()), "Release"); + assertEquals(properties.getProperty(BuildParm.CLEAN.getKey()), "true"); + assertEquals(properties.getProperty(BuildParm.EXTERNAL_RUNTIME_PATH.getKey()), "src"); + assertEquals(properties.getProperty(BuildParm.LINT.getKey()), "true"); + assertEquals(properties.getProperty(BuildParm.LOGGING.getKey()), "4"); + assertEquals(properties.getProperty(BuildParm.TARGET_COMPILER.getKey()), "gcc"); + assertEquals(properties.getProperty(BuildParm.QUIET.getKey()), "true"); + assertEquals(properties.getProperty(BuildParm.RTI.getKey()), "-1"); + assertEquals(properties.getProperty(BuildParm.RUNTIME_VERSION.getKey()), "rs"); + assertEquals(properties.getProperty(BuildParm.THREADING.getKey()), "false"); + assertEquals(properties.getProperty(BuildParm.WORKERS.getKey()), "1"); }); } From c517d10db17b09477106366c09c5cee6b87efb00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 20 Mar 2023 16:37:50 +0100 Subject: [PATCH 06/10] Use test fixture subclass --- .../lflang/tests/cli/CliToolTestFixture.java | 77 ------------------- .../src/org/lflang/tests/cli/LfcCliTest.java | 22 ++++-- org.lflang/src/org/lflang/cli/CliBase.java | 7 +- org.lflang/src/org/lflang/cli/Lfc.java | 4 +- 4 files changed, 22 insertions(+), 88 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java b/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java index c6ee569ca0..1ae794c8c9 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java @@ -92,36 +92,6 @@ public ExecutionResult run(Path wd, String... args) { return new ExecutionResult(out, err, exitCode); } - /** - * Run and return and Lfc instance with the given arguments, in the given - * working directory. - * - * @param wd working directory - * @param args Arguments - * @return The execution result - */ - public LfcObjExecutionResult runLfcObj(Path wd, String... args) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ByteArrayOutputStream err = new ByteArrayOutputStream(); - - Io testIo = new Io( - new PrintStream(err), - new PrintStream(out), - wd - ); - // Main instance. - final Lfc lfcObj = new Lfc(); - // Parse arguments and execute main logic. - int exitCode = testIo.fakeSystemExit(io -> ( - new CommandLine(lfcObj) - .setOut(new PrintWriter(io.getOut())) - .setErr(new PrintWriter(io.getErr())) - ).execute(args) - ); - - return new LfcObjExecutionResult(out, err, exitCode, lfcObj); - } - /** * The result of an execution of a CLI program like LFC. * @@ -194,51 +164,4 @@ interface ThrowingConsumer { } } - /** - * The result, including class instance, of an execution of a CLI program - * like LFC. - * - * @param out Output stream - * @param err Error stream - * @param exitCode Exit code of the process - */ - record LfcObjExecutionResult( - ByteArrayOutputStream out, - ByteArrayOutputStream err, - int exitCode, - Lfc lfcObj - ) { - public void checkOk() { - assertEquals(0, exitCode); - } - - /** - * Use this method to wrap assertions. - */ - public void verify(ThrowingConsumer actions) { - try { - actions.accept(this); - } catch (Exception | AssertionFailedError e) { - System.out.println("TEST FAILED"); - System.out.println("> Return code: " + exitCode); - System.out.println("> Standard output -------------------------"); - System.err.println(out.toString()); - System.out.println("> Standard error --------------------------"); - System.err.println(err.toString()); - System.out.println("> -----------------------------------------"); - - if (e instanceof Exception) { - throw new AssertionFailedError("Expected no exception to be thrown", e); - } - throw (AssertionFailedError) e; - } - } - - - @FunctionalInterface - interface ThrowingConsumer { - void accept(T t) throws Exception; - } - } - } diff --git a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java index e1ae31bf5d..4e3d33e6de 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java @@ -129,17 +129,12 @@ public void testTargetProperties(@TempDir Path tempDir) "--threading", "false", "--workers", "1", }; + LfcOneShotTestFixture fixture = new LfcOneShotTestFixture(); - lfcTester.runLfcObj(tempDir, args) + fixture.run(tempDir, args) .verify(result -> { result.checkOk(); - // Get the properties method. - Method getPropsMethod = - Lfc.class.getDeclaredMethod("filterPassOnProps"); - // Change the method's visibility to public for testing. - getPropsMethod.setAccessible(true); - Properties properties = - (Properties) getPropsMethod.invoke(result.lfcObj()); + Properties properties = fixture.lfc.cliArgsToBuildParams(); assertEquals(properties.getProperty(BuildParm.BUILD_TYPE.getKey()), "Release"); assertEquals(properties.getProperty(BuildParm.CLEAN.getKey()), "true"); assertEquals(properties.getProperty(BuildParm.EXTERNAL_RUNTIME_PATH.getKey()), "src"); @@ -156,10 +151,21 @@ public void testTargetProperties(@TempDir Path tempDir) static class LfcTestFixture extends CliToolTestFixture { + @Override protected void runCliProgram(Io io, String[] args) { Lfc.main(io, args); } } + static class LfcOneShotTestFixture extends CliToolTestFixture { + + private final Lfc lfc = new Lfc(); + + @Override + protected void runCliProgram(Io io, String[] args) { + lfc.doExecute(io, args); + } + } + } diff --git a/org.lflang/src/org/lflang/cli/CliBase.java b/org.lflang/src/org/lflang/cli/CliBase.java index d4dfe9c782..0cf41313ab 100644 --- a/org.lflang/src/org/lflang/cli/CliBase.java +++ b/org.lflang/src/org/lflang/cli/CliBase.java @@ -97,7 +97,11 @@ protected static void cliMain( // Main instance. final CliBase main = injector.getInstance(toolClass); // Parse arguments and execute main logic. - CommandLine cmd = new CommandLine(main) + main.doExecute(io, args); + } + + public void doExecute(Io io, String[] args) { + CommandLine cmd = new CommandLine(this) .setOut(new PrintWriter(io.getOut())) .setErr(new PrintWriter(io.getErr())); int exitCode = cmd.execute(args); @@ -247,4 +251,5 @@ public Resource getResource(Path path) { return null; } } + } diff --git a/org.lflang/src/org/lflang/cli/Lfc.java b/org.lflang/src/org/lflang/cli/Lfc.java index f3908b74ca..9560fce3aa 100644 --- a/org.lflang/src/org/lflang/cli/Lfc.java +++ b/org.lflang/src/org/lflang/cli/Lfc.java @@ -158,7 +158,7 @@ public void run() { List paths = getInputPaths(); final Path outputRoot = getOutputRoot(); // Hard code the props based on the options we want. - Properties properties = this.filterPassOnProps(); + Properties properties = this.cliArgsToBuildParams(); try { // Invoke the generator on all input file paths. @@ -229,7 +229,7 @@ private Path getActualOutputPath(Path root, Path path) { * * @return Properties for the code generator. */ - private Properties filterPassOnProps() { + public Properties cliArgsToBuildParams() { Properties props = new Properties(); if (buildType != null) { From bf5ff1d431463692647544a6e13c5b1f8e787890 Mon Sep 17 00:00:00 2001 From: Atharva Patil Date: Tue, 21 Mar 2023 01:53:31 -0700 Subject: [PATCH 07/10] Bugfix for lfc instantiation in the cli test. --- .../src/org/lflang/tests/cli/LfcCliTest.java | 14 +++++++++----- org.lflang/src/org/lflang/cli/CliBase.java | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java index 4e3d33e6de..17f6304c3d 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java @@ -32,6 +32,8 @@ import static org.lflang.tests.TestUtils.isDirectory; import static org.lflang.tests.TestUtils.isRegularFile; +import com.google.inject.Injector; + import java.io.IOException; import java.lang.reflect.Method; import java.nio.file.Path; @@ -103,11 +105,10 @@ public void testGenInSrcDir(@TempDir Path tempDir) throws IOException { .check("bin", isDirectory()) .check("src-gen/File/File.py", isRegularFile()); }); - } @Test - public void testTargetProperties(@TempDir Path tempDir) + public void testBuildParams(@TempDir Path tempDir) throws IOException { dirBuilder(tempDir).file("src/File.lf", LF_PYTHON_FILE); @@ -133,7 +134,7 @@ public void testTargetProperties(@TempDir Path tempDir) fixture.run(tempDir, args) .verify(result -> { - result.checkOk(); + // Don't validate execution because args are dummy args. Properties properties = fixture.lfc.cliArgsToBuildParams(); assertEquals(properties.getProperty(BuildParm.BUILD_TYPE.getKey()), "Release"); assertEquals(properties.getProperty(BuildParm.CLEAN.getKey()), "true"); @@ -160,12 +161,15 @@ protected void runCliProgram(Io io, String[] args) { static class LfcOneShotTestFixture extends CliToolTestFixture { - private final Lfc lfc = new Lfc(); + private Lfc lfc; @Override protected void runCliProgram(Io io, String[] args) { + // Injector used to obtain Main instance. + final Injector injector = Lfc.getInjector("lfc", io); + // Main instance. + this.lfc = injector.getInstance(Lfc.class); lfc.doExecute(io, args); } } - } diff --git a/org.lflang/src/org/lflang/cli/CliBase.java b/org.lflang/src/org/lflang/cli/CliBase.java index 0cf41313ab..8f10a5677a 100644 --- a/org.lflang/src/org/lflang/cli/CliBase.java +++ b/org.lflang/src/org/lflang/cli/CliBase.java @@ -115,7 +115,7 @@ public void doExecute(Io io, String[] args) { */ public abstract void run(); - protected static Injector getInjector(String toolName, Io io) { + public static Injector getInjector(String toolName, Io io) { final ReportingBackend reporter = new ReportingBackend(io, toolName + ": "); From 54ca2c2498c757c0b7bc57e6ed13b51f8257cd71 Mon Sep 17 00:00:00 2001 From: Atharva Patil Date: Tue, 21 Mar 2023 09:41:53 -0700 Subject: [PATCH 08/10] Removed unnecessary dependencies. --- .../src/org/lflang/tests/cli/CliToolTestFixture.java | 6 ------ org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java | 1 - 2 files changed, 7 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java b/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java index 1ae794c8c9..83e7817618 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/CliToolTestFixture.java @@ -31,7 +31,6 @@ import java.io.ByteArrayOutputStream; import java.io.PrintStream; -import java.io.PrintWriter; import java.nio.file.Path; import java.util.concurrent.Callable; import java.util.function.Consumer; @@ -40,16 +39,12 @@ import org.opentest4j.AssertionFailedError; import org.lflang.cli.Io; -import org.lflang.cli.Lfc; - -import picocli.CommandLine; /** * Test utilities for a CLI tool, eg {@link org.lflang.cli.Lfc}, * {@link org.lflang.cli.Lff}. * * @author Clément Fournier - * @author Atharva Patil */ abstract class CliToolTestFixture { @@ -163,5 +158,4 @@ interface ThrowingConsumer { void accept(T t) throws Exception; } } - } diff --git a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java index 17f6304c3d..e76ffc9e79 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java @@ -35,7 +35,6 @@ import com.google.inject.Injector; import java.io.IOException; -import java.lang.reflect.Method; import java.nio.file.Path; import java.util.Properties; From cb302ef1ca78f0f3943ea9340deedad5dbb51969 Mon Sep 17 00:00:00 2001 From: Atharva Patil Date: Tue, 28 Mar 2023 03:41:01 -0700 Subject: [PATCH 09/10] Rigorous validation and testing for Lfc. --- .../src/org/lflang/tests/cli/LfcCliTest.java | 82 ++++++++++++++++--- .../src/org/lflang/tests/cli/LffCliTest.java | 2 +- org.lflang/src/org/lflang/TargetProperty.java | 4 - org.lflang/src/org/lflang/cli/CliBase.java | 6 +- org.lflang/src/org/lflang/cli/Lfc.java | 45 ++++++++-- 5 files changed, 115 insertions(+), 24 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java index e76ffc9e79..f3abd9d869 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/LfcCliTest.java @@ -45,6 +45,7 @@ import org.lflang.cli.Io; import org.lflang.cli.Lfc; import org.lflang.generator.LFGeneratorContext.BuildParm; +import org.lflang.tests.TestUtils.TempDirBuilder; /** * @author Clément Fournier @@ -61,7 +62,6 @@ public class LfcCliTest { } """; - @Test public void testHelpArg() { lfcTester.run("--help", "--version") @@ -92,6 +92,63 @@ public void testWrongCliArg() { }); } + @Test + public void testInvalidArgs(@TempDir Path tempDir) throws IOException { + dirBuilder(tempDir).file("src/File.lf", LF_PYTHON_FILE); + LfcOneShotTestFixture fixture = new LfcOneShotTestFixture(); + + // Invalid src file. + fixture.run(tempDir, "unknown.lf") + .verify(result -> { + result.checkStdErr(containsString("No such file or directory.")); + result.checkFailed(); + }); + + // Invalid output path. + fixture.run(tempDir, "--output-path", "unknown/output/path", "src/File.lf") + .verify(result -> { + result.checkStdErr(containsString("Output location does not exist.")); + result.checkFailed(); + }); + + // Invalid build type. + fixture.run(tempDir, "--build-type", "unknown-build-type", "src/File.lf") + .verify(result -> { + result.checkStdErr(containsString("Invalid build type.")); + result.checkFailed(); + }); + + // Invalid logging level. + fixture.run(tempDir, "--logging", "unknown_level", "src/File.lf") + .verify(result -> { + result.checkStdErr(containsString("Invalid log level.")); + result.checkFailed(); + }); + + // Invalid RTI path. + fixture.run(tempDir, "--rti", "unknown/rti/path", "src/File.lf") + .verify(result -> { + result.checkStdErr(containsString("Invalid RTI path.")); + result.checkFailed(); + }); + + // Invalid scheduler. + fixture.run(tempDir, "--scheduler", "unknown-scheduler", "src/File.lf") + .verify(result -> { + result.checkStdErr(containsString("Invalid scheduler.")); + result.checkFailed(); + }); + + // Invalid workers. + fixture.run(tempDir, "--workers", "notaninteger", "src/File.lf") + .verify(result -> { + result.checkStdErr(containsString("Invalid value for option '--workers'")); + result.checkStdErr(containsString("is not an int")); + result.checkFailed(); + }); + + } + @Test public void testGenInSrcDir(@TempDir Path tempDir) throws IOException { dirBuilder(tempDir).file("src/File.lf", LF_PYTHON_FILE); @@ -107,9 +164,11 @@ public void testGenInSrcDir(@TempDir Path tempDir) throws IOException { } @Test - public void testBuildParams(@TempDir Path tempDir) + public void testGeneratorArgs(@TempDir Path tempDir) throws IOException { - dirBuilder(tempDir).file("src/File.lf", LF_PYTHON_FILE); + TempDirBuilder dir = dirBuilder(tempDir); + dir.file("src/File.lf", LF_PYTHON_FILE); + dir.mkdirs("path//to/rti"); String[] args = { "src/File.lf", @@ -119,13 +178,13 @@ public void testBuildParams(@TempDir Path tempDir) "--target-compiler", "gcc", "--external-runtime-path", "src", "--federated", - "--logging", "4", + "--logging", "info", "--lint", "--no-compile", "--quiet", - "--rti", "-1", + "--rti", "path/to/rti", "--runtime-version", "rs", - "--scheduler", "2", + "--scheduler", "GEDF_NP", "--threading", "false", "--workers", "1", }; @@ -134,22 +193,23 @@ public void testBuildParams(@TempDir Path tempDir) fixture.run(tempDir, args) .verify(result -> { // Don't validate execution because args are dummy args. - Properties properties = fixture.lfc.cliArgsToBuildParams(); + Properties properties = fixture.lfc.getGeneratorArgs(); assertEquals(properties.getProperty(BuildParm.BUILD_TYPE.getKey()), "Release"); assertEquals(properties.getProperty(BuildParm.CLEAN.getKey()), "true"); + assertEquals(properties.getProperty(BuildParm.TARGET_COMPILER.getKey()), "gcc"); assertEquals(properties.getProperty(BuildParm.EXTERNAL_RUNTIME_PATH.getKey()), "src"); + assertEquals(properties.getProperty(BuildParm.LOGGING.getKey()), "info"); assertEquals(properties.getProperty(BuildParm.LINT.getKey()), "true"); - assertEquals(properties.getProperty(BuildParm.LOGGING.getKey()), "4"); - assertEquals(properties.getProperty(BuildParm.TARGET_COMPILER.getKey()), "gcc"); + assertEquals(properties.getProperty(BuildParm.NO_COMPILE.getKey()), "true"); assertEquals(properties.getProperty(BuildParm.QUIET.getKey()), "true"); - assertEquals(properties.getProperty(BuildParm.RTI.getKey()), "-1"); + assertEquals(properties.getProperty(BuildParm.RTI.getKey()), "path/to/rti"); assertEquals(properties.getProperty(BuildParm.RUNTIME_VERSION.getKey()), "rs"); + assertEquals(properties.getProperty(BuildParm.SCHEDULER.getKey()), "GEDF_NP"); assertEquals(properties.getProperty(BuildParm.THREADING.getKey()), "false"); assertEquals(properties.getProperty(BuildParm.WORKERS.getKey()), "1"); }); } - static class LfcTestFixture extends CliToolTestFixture { @Override diff --git a/org.lflang.tests/src/org/lflang/tests/cli/LffCliTest.java b/org.lflang.tests/src/org/lflang/tests/cli/LffCliTest.java index 2bbbada212..3a34e9cb81 100644 --- a/org.lflang.tests/src/org/lflang/tests/cli/LffCliTest.java +++ b/org.lflang.tests/src/org/lflang/tests/cli/LffCliTest.java @@ -130,7 +130,7 @@ public void testNoSuchFile(@TempDir Path tempDir) { result.checkFailed(); result.checkStdErr(containsString( - tempDir.resolve("nosuchdir") + ": No such file or directory")); + tempDir.resolve("nosuchdir") + ": No such file or directory.")); } diff --git a/org.lflang/src/org/lflang/TargetProperty.java b/org.lflang/src/org/lflang/TargetProperty.java index 1c580b603e..f4e66e5ce0 100644 --- a/org.lflang/src/org/lflang/TargetProperty.java +++ b/org.lflang/src/org/lflang/TargetProperty.java @@ -383,10 +383,6 @@ public enum TargetProperty { (config, value, err) -> { config.logLevel = (LogLevel) UnionType.LOGGING_UNION .forName(ASTUtils.elementToSingleString(value)); - }, - (config, value, err) -> { - config.logLevel = (LogLevel) UnionType.LOGGING_UNION - .forName(ASTUtils.elementToSingleString(value)); }), /** diff --git a/org.lflang/src/org/lflang/cli/CliBase.java b/org.lflang/src/org/lflang/cli/CliBase.java index 8f10a5677a..b825d91966 100644 --- a/org.lflang/src/org/lflang/cli/CliBase.java +++ b/org.lflang/src/org/lflang/cli/CliBase.java @@ -146,7 +146,7 @@ protected List getInputPaths() { for (Path path : paths) { if (!Files.exists(path)) { reporter.printFatalErrorAndExit( - path + ": No such file or directory"); + path + ": No such file or directory."); } } @@ -164,11 +164,11 @@ protected Path getOutputRoot() { root = io.getWd().resolve(outputPath).normalize(); if (!Files.exists(root)) { // FIXME: Create it instead? reporter.printFatalErrorAndExit( - "Output location '" + root + "' does not exist."); + root + ": Output location does not exist."); } if (!Files.isDirectory(root)) { reporter.printFatalErrorAndExit( - "Output location '" + root + "' is not a directory."); + root + ": Output location is not a directory."); } } diff --git a/org.lflang/src/org/lflang/cli/Lfc.java b/org.lflang/src/org/lflang/cli/Lfc.java index 9560fce3aa..b31e5a8246 100644 --- a/org.lflang/src/org/lflang/cli/Lfc.java +++ b/org.lflang/src/org/lflang/cli/Lfc.java @@ -1,6 +1,7 @@ package org.lflang.cli; +import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.Properties; @@ -14,6 +15,7 @@ import org.lflang.ASTUtils; import org.lflang.FileConfig; +import org.lflang.TargetProperty.UnionType; import org.lflang.generator.LFGeneratorContext; import org.lflang.generator.LFGeneratorContext.BuildParm; @@ -105,7 +107,7 @@ public class Lfc extends CliBase { @Option( names = {"-r", "--rti"}, description = "Specify the location of the RTI.") - private String rti; + private Path rti; @Option( names = "--runtime-version", @@ -158,7 +160,7 @@ public void run() { List paths = getInputPaths(); final Path outputRoot = getOutputRoot(); // Hard code the props based on the options we want. - Properties properties = this.cliArgsToBuildParams(); + Properties properties = this.getGeneratorArgs(); try { // Invoke the generator on all input file paths. @@ -229,45 +231,78 @@ private Path getActualOutputPath(Path root, Path path) { * * @return Properties for the code generator. */ - public Properties cliArgsToBuildParams() { + public Properties getGeneratorArgs() { Properties props = new Properties(); if (buildType != null) { + // Validate build type. + if (UnionType.BUILD_TYPE_UNION.forName(buildType) == null) { + reporter.printFatalErrorAndExit( + buildType + ": Invalid build type."); + } props.setProperty(BuildParm.BUILD_TYPE.getKey(), buildType); } + if (clean) { props.setProperty(BuildParm.CLEAN.getKey(), "true"); } + if (externalRuntimePath != null) { - props.setProperty(BuildParm.EXTERNAL_RUNTIME_PATH.getKey(), externalRuntimePath.toString()); + props.setProperty(BuildParm.EXTERNAL_RUNTIME_PATH.getKey(), + externalRuntimePath.toString()); } + if (lint) { props.setProperty(BuildParm.LINT.getKey(), "true"); } + if (logging != null) { + // Validate log level. + if (UnionType.LOGGING_UNION.forName(logging) == null) { + reporter.printFatalErrorAndExit( + logging + ": Invalid log level."); + } props.setProperty(BuildParm.LOGGING.getKey(), logging); } + if (noCompile) { props.setProperty(BuildParm.NO_COMPILE.getKey(), "true"); } + if (targetCompiler != null) { props.setProperty(BuildParm.TARGET_COMPILER.getKey(), targetCompiler); } + if (quiet) { props.setProperty(BuildParm.QUIET.getKey(), "true"); } + if (rti != null) { - props.setProperty(BuildParm.RTI.getKey(), rti); + // Validate RTI path. + if (!Files.exists(io.getWd().resolve(rti))) { + reporter.printFatalErrorAndExit( + rti + ": Invalid RTI path."); + } + props.setProperty(BuildParm.RTI.getKey(), rti.toString()); } + if (runtimeVersion != null) { props.setProperty(BuildParm.RUNTIME_VERSION.getKey(), runtimeVersion); } + if (scheduler != null) { + // Validate scheduler. + if (UnionType.SCHEDULER_UNION.forName(scheduler) == null) { + reporter.printFatalErrorAndExit( + scheduler + ": Invalid scheduler."); + } props.setProperty(BuildParm.SCHEDULER.getKey(), scheduler); } + if (threading != null) { props.setProperty(BuildParm.THREADING.getKey(), threading); } + if (workers != null) { props.setProperty(BuildParm.WORKERS.getKey(), workers.toString()); } From 937b390ff058f712eebf51443357a28ad9caf0b5 Mon Sep 17 00:00:00 2001 From: Atharva Patil <44582972+patilatharva@users.noreply.github.com> Date: Sat, 1 Apr 2023 19:26:18 -0700 Subject: [PATCH 10/10] Removed CLI arg smoke tests on CI. --- .github/scripts/test-lfc.sh | 49 ------------------------------------- 1 file changed, 49 deletions(-) diff --git a/.github/scripts/test-lfc.sh b/.github/scripts/test-lfc.sh index a59d4acd3b..096736f495 100755 --- a/.github/scripts/test-lfc.sh +++ b/.github/scripts/test-lfc.sh @@ -16,54 +16,5 @@ function test_with_links() { bin/lfc test/C/src/Minimal.lf -# -c,--clean Clean before building. -bin/lfc -c test/C/src/Minimal.lf -bin/lfc --clean test/C/src/Minimal.lf - -# --external-runtime-path Specify an external runtime library to -# be used by the compiled binary. - -# -f,--federated Treat main reactor as federated. -bin/lfc -f test/C/src/Minimal.lf -bin/lfc --federated test/C/src/Minimal.lf - -# --rti Specify address of RTI. -bin/lfc -f --rti rti test/C/src/Minimal.lf -bin/lfc --federated --rti rti test/C/src/Minimal.lf - -# -h,--help Display this information. -bin/lfc -h -bin/lfc --help - -# -l, --lint Enable linting during build. -bin/lfc -l test/Python/src/Minimal.lf -bin/lfc --lint test/Python/src/Minimal.lf - -# -n,--no-compile Do not invoke target compiler. -bin/lfc -n test/C/src/Minimal.lf -bin/lfc --no-compile test/C/src/Minimal.lf - -# -o,--output-path Specify the root output directory. -bin/lfc -o . test/C/src/Minimal.lf -bin/lfc --output-path . test/C/src/Minimal.lf - -# --runtime-version Specify the version of the runtime -# library used for compiling LF -# programs. -bin/lfc --runtime-version e80cd36ce5bd625a7b167e7dfd65d25f78b0dd01 test/Cpp/src/Minimal.lf - -# -w,--workers Specify the default number of worker threads. -bin/lfc -w 2 test/C/src/Minimal.lf -bin/lfc --workers 2 test/C/src/Minimal.lf -bin/lfc --threading true test/C/src/Minimal.lf -bin/lfc --threading false test/C/src/Minimal.lf - -# --target-compiler Target compiler to invoke. -# (Added no-compile to avoid adding dependency.) -bin/lfc --target-compiler gcc --no-compile test/C/src/Minimal.lf - -# --version -bin/lfc --version - # Ensure that lfc is robust to symbolic links. test_with_links "lfc"