From cc2cb5b747f3c67122cd0578debd17b7a9294ea8 Mon Sep 17 00:00:00 2001 From: Rob Greene Date: Sun, 19 Oct 2025 10:34:30 -0700 Subject: [PATCH] Adding some 'bt' command line tests. Had to restructure how System.exit is called due to the Java agent throwing an execution for tracking. --- settings.gradle | 2 + .../bastools/tools/bt/Main.java | 15 +++-- tools/tests/build.gradle | 24 +++++++ .../tools/tests/CommandLineTests.java | 39 +++++++++++ tools/tests/src/test/resources/bt-config.yml | 65 +++++++++++++++++++ 5 files changed, 139 insertions(+), 6 deletions(-) create mode 100644 tools/tests/build.gradle create mode 100644 tools/tests/src/test/java/io/github/applecommander/bastools/tools/tests/CommandLineTests.java create mode 100644 tools/tests/src/test/resources/bt-config.yml diff --git a/settings.gradle b/settings.gradle index 3886e9a..d5218f3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,9 +1,11 @@ include 'api' include 'tools:bt' include 'tools:st' +include 'tools:tests' rootProject.name = 'bastools' project(":api").name = 'bastools-api' project(":tools").name = 'bastools-tools' project(":tools:bt").name = 'bastools-tools-bt' project(":tools:st").name = 'bastools-tools-st' +project(":tools:tests").name = 'bastools-tools-tests' diff --git a/tools/bt/src/main/java/io/github/applecommander/bastools/tools/bt/Main.java b/tools/bt/src/main/java/io/github/applecommander/bastools/tools/bt/Main.java index 9778f8e..d72176c 100644 --- a/tools/bt/src/main/java/io/github/applecommander/bastools/tools/bt/Main.java +++ b/tools/bt/src/main/java/io/github/applecommander/bastools/tools/bt/Main.java @@ -49,7 +49,7 @@ import picocli.CommandLine.Parameters; optionListHeading = "%nOptions:%n", name = "bt", mixinStandardHelpOptions = true, versionProvider = VersionProvider.class) -public class Main implements Callable { +public class Main implements Callable { private static final int BAS = 0xfc; @Option(names = { "-o", "--output" }, description = "Write binary output to file.") @@ -118,9 +118,11 @@ public class Main implements Callable { private File sourceFile; public static void main(String[] args) { + // The CLI unit test library throws an exception when 'System.exit' is called; + // so we cannot have the 'System.exit' call in the try-catch block! + int exitCode = 0; try { - int exitCode = new CommandLine(new Main()).execute(args); - System.exit(exitCode); + exitCode = new CommandLine(new Main()).execute(args); } catch (Throwable t) { if (Main.debugFlag) { t.printStackTrace(System.err); @@ -132,12 +134,13 @@ public class Main implements Callable { } System.err.printf("Error: %s\n", Optional.ofNullable(message).orElse("An error occurred.")); } - System.exit(1); + exitCode = 1; } + System.exit(exitCode); } @Override - public Void call() throws IOException { + public Integer call() throws IOException { if (checkParameters()) { Configuration.Builder builder = Configuration.builder() .maxLineLength(this.maxLineLength) @@ -147,7 +150,7 @@ public class Main implements Callable { process(builder.build()); } - return null; // To satisfy object "Void" + return 0; } /** A basic test to ensure parameters are somewhat sane. */ diff --git a/tools/tests/build.gradle b/tools/tests/build.gradle new file mode 100644 index 0000000..27eff21 --- /dev/null +++ b/tools/tests/build.gradle @@ -0,0 +1,24 @@ +plugins { + id 'java' +} + +repositories { + mavenCentral() +} + +dependencies { + implementation project(':bastools-tools:bastools-tools-bt') + + testImplementation platform('org.junit:junit-bom:5.10.0') + testImplementation 'org.junit.jupiter:junit-jupiter' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + testImplementation "io.github.a2geek:clth:2.0" +} + +test { + useJUnitPlatform() + + def junit5SystemExit = configurations.testRuntimeClasspath.files + .find { it.name.contains('junit5-system-exit') } + jvmArgumentProviders.add({["-javaagent:$junit5SystemExit"]} as CommandLineArgumentProvider) +} diff --git a/tools/tests/src/test/java/io/github/applecommander/bastools/tools/tests/CommandLineTests.java b/tools/tests/src/test/java/io/github/applecommander/bastools/tools/tests/CommandLineTests.java new file mode 100644 index 0000000..72e081c --- /dev/null +++ b/tools/tests/src/test/java/io/github/applecommander/bastools/tools/tests/CommandLineTests.java @@ -0,0 +1,39 @@ +package io.github.applecommander.bastools.tools.tests; + +import io.github.a2geek.clth.Config; +import io.github.a2geek.clth.JUnitHelper; +import io.github.a2geek.clth.TestHarness; +import io.github.a2geek.clth.TestSuite; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.util.stream.Stream; + +public class CommandLineTests { + @ParameterizedTest(name = "{1}: {2}") + @MethodSource("testCasesBT") + public void testBT(TestSuite testSuite, String name, String parameters) { + final TestHarness.Settings settings = TestHarness.settings() + .deleteFiles() + .enableAlwaysShowOutput() + .get(); + TestHarness.run(testSuite, JUnitHelper::execute, settings); + } + + public static Stream testCasesBT() { + try (InputStream inputStream = CommandLineTests.class.getResourceAsStream("/bt-config.yml")) { + assert inputStream != null; + String document = new String(inputStream.readAllBytes()); + Config config = Config.load(document); + + return TestSuite.build(config) + .map(t -> Arguments.of(t, t.testName(), String.join(" ", t.variables().values()))); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} diff --git a/tools/tests/src/test/resources/bt-config.yml b/tools/tests/src/test/resources/bt-config.yml new file mode 100644 index 0000000..7245e4a --- /dev/null +++ b/tools/tests/src/test/resources/bt-config.yml @@ -0,0 +1,65 @@ +commands: + bt: + main-class: io.github.applecommander.bastools.tools.bt.Main + system-exit: yes + +files: + helloWorld: + type: text + content: | + 10 TEXT + 20 HOME + 30 PRINT "HELLO, WORLD" + 40 END + suffix: .bas + +tests: + - name: Forms of help + steps: + - command: bt --help + criteria: + match: contains + stdout: "Usage: bt" + - command: bt + criteria: + match: contains + stderr: "Usage: bt" + rc: 2 + - name: list output + steps: + - command: bt --list $helloWorld + criteria: + whitespace: trim + stdout: | + 10 TEXT + 20 HOME + 30 PRINT "HELLO, WORLD" + 40 END + - name: copy/paste output + steps: + - command: bt --copy $helloWorld + criteria: + whitespace: trim + stdout: | + 0067:01 08 29 08 + 0800:00 + 0801:07 08 0A 00 89 00 0D 08 14 00 97 00 21 08 1E 00 + 0811:BA 22 48 45 4C 4C 4F 2C 20 57 4F 52 4C 44 22 00 + 0821:27 08 28 00 80 00 00 00 + - name: optimize output + steps: + - command: bt --optimize --list $helloWorld + criteria: + whitespace: trim + stdout: | + 0 TEXT : HOME : PRINT "HELLO, WORLD": END + - name: wrap output + steps: + - command: bt --wrapper --hex $helloWorld + criteria: + whitespace: trim + stdout: | + 0801: 16 08 0a 00 b9 31 30 33 2c 32 34 3a b9 31 30 34 .....103,24:.104 + 0811: 2c 38 3a ac 00 00 00 1e 08 0a 00 89 00 24 08 14 ,8:..........$.. + 0821: 00 97 00 38 08 1e 00 ba 22 48 45 4c 4c 4f 2c 20 ...8...."HELLO, + 0831: 57 4f 52 4c 44 22 00 3e 08 28 00 80 00 00 00 .. WORLD".>.(.....