From ab9754a524cb9ff13f586be84161cbb61c587e88 Mon Sep 17 00:00:00 2001 From: LWagner Date: Fri, 24 Nov 2023 20:07:21 +0100 Subject: [PATCH 1/2] refactor!: Clean up return codes of Main --- src/main/java/cambio/simulator/Main.java | 139 +++++++++--------- src/main/java/cambio/simulator/misc/Util.java | 21 ++- 2 files changed, 87 insertions(+), 73 deletions(-) diff --git a/src/main/java/cambio/simulator/Main.java b/src/main/java/cambio/simulator/Main.java index 97e2a108..e0e8f658 100644 --- a/src/main/java/cambio/simulator/Main.java +++ b/src/main/java/cambio/simulator/Main.java @@ -19,6 +19,17 @@ */ public final class Main { + /** + * Exit codes for the program. See {@link #main(String[])} for meanings. + */ + public static final class ExitCodes { + public static final int SUCCESSFUL_RUN = 0; + public static final int EXCEPTION_DURING_ARGUMENT_PARSING = 1; + public static final int EXCEPTION_DURING_PARSING = 2; + public static final int EXCEPTION_DURING_SIMULATION = 16; + public static final int EXCEPTION_UNKNOWN = 512; + } + /** * Main entry point of the program. Pass "-h" to see arguments. * @@ -64,47 +75,9 @@ public final class Main { * @see #runExperiment(ExperimentStartupConfig) */ public static void main(final String[] args) { + int returnCode = runExperiment(args); - ExperimentStartupConfig startupConfig = parseArgsToConfig(args); - - try { - - //---------------------------------------Experiment execution----------------------------------------------- - - Experiment experiment = runExperiment(args); - - //-------------------------------------------Error handling------------------------------------------------- - - if (experiment.hasError()) { - System.out.println("[INFO] Simulation failed."); - System.exit(16); - } else { - System.out.println("[INFO] Simulation finished successfully."); - writeCommandLineReport((MiSimModel) experiment.getModel()); - System.exit(0); - } - } catch (ParsingException | JsonParseException e) { - if (startupConfig.debugOutputOn()) { - e.printStackTrace(); - } else { - System.out.println("[ERROR] " + e.getMessage()); - } - System.exit(2); - } catch (Exception e) { - //In tests, System.exit throws an exception with a private type from the - //"com.github.stefanbirkner.systemlambda" package. This exception is supposed to be - //thrown up to top level to be detected by a test and therefore is not handled here. - //TODO: this should (and will have to be with later java versions) be removed - if (e.getClass().getPackage().getName().equals("com.github.stefanbirkner.systemlambda")) { - throw e; - } - - if (startupConfig.debugOutputOn()) { - e.printStackTrace(); - } - - System.exit(512); - } + System.exit(returnCode); } /** @@ -129,71 +102,95 @@ public static void mainVarargs(final String... args) { } - private static @NotNull ExperimentStartupConfig parseArgsToConfig(String[] args) { + private static @NotNull ExperimentStartupConfig parseArgsToConfig(String[] args) throws ParseException { // trim whitespaces from arguments to please apache cli String[] argsTrimmed = Arrays.stream(args).map(String::trim).toArray(String[]::new); - try { - return CLI.parseArguments(ExperimentStartupConfig.class, argsTrimmed); - } catch (ParseException e) { - System.err.println("[ERROR] " + e.getMessage()); - System.exit(1); - } - return null; - } - - - private static @NotNull Experiment runExperiment(String[] args) { - - ExperimentStartupConfig startupConfig = parseArgsToConfig(args); - - Experiment experiment = runExperiment(startupConfig); - - return experiment; - + return CLI.parseArguments(ExperimentStartupConfig.class, argsTrimmed); } /** * Starts an experiment, and uses the given string as cli arguments (splits on spaces). Use spaces only to separate * arguments and not inside a value. * - * @param cliString the cli argument string + * @param cliString the cli argument string to parse. See {@link ExperimentStartupConfig} or --help for details. + * @return the exit code of the experiment, see {@link #main(String[])} for meanings. * @see #main(String[]) * @see #mainVarargs(String...) * @see #runExperiment(ExperimentStartupConfig) */ - public static @NotNull Experiment runExperiment(final String cliString) { + public static int runExperiment(final String cliString) { return runExperiment(cliString.replaceAll("\\s*", " ").split(" ")); } + /** + * Starts an experiment, and uses the given string as cli arguments. See {@link ExperimentStartupConfig} or --help + * for details. + * + * @param args the cli arguments to parse. See {@link ExperimentStartupConfig} for options. + * @return the exit code of the experiment, see {@link #main(String[])} for meanings. + */ + public static int runExperiment(String[] args) { + ExperimentStartupConfig startupConfig; + + try { + startupConfig = parseArgsToConfig(args); + } catch (ParseException e) { + System.err.println("[ERROR] " + e.getMessage()); + return ExitCodes.EXCEPTION_DURING_ARGUMENT_PARSING; + } + return runExperiment(startupConfig); + } + + /** * Starts an experiment with the given {@link ExperimentStartupConfig}. * * @param startupConfig the experiment startup configuration + * @return the exit code of the experiment, see {@link #main(String[])} for meanings. * @see #runExperiment(String) * @see #main(String[]) * @see #mainVarargs(String...) */ - public static @NotNull Experiment runExperiment(final ExperimentStartupConfig startupConfig) { - Experiment experiment = new ExperimentCreator().createSimulationExperiment(startupConfig); - System.out.printf("[INFO] Starting simulation at approximately %s%n", java.time.LocalDateTime.now()); - experiment.start(); - experiment.finish(); + public static int runExperiment(final ExperimentStartupConfig startupConfig) { + boolean isDebugOutputOn = startupConfig.debugOutputOn(); + try { + + Experiment experiment = new ExperimentCreator().createSimulationExperiment(startupConfig); + System.out.printf("[INFO] Starting simulation at approximately %s%n", java.time.LocalDateTime.now()); + experiment.start(); + experiment.finish(); - RNGStorage.reset(); + RNGStorage.reset(); //TODO: this should happen first - return experiment; + + if (experiment.hasError()) { + System.out.println("[INFO] Simulation failed."); + return ExitCodes.EXCEPTION_DURING_SIMULATION; + } + + System.out.println("[INFO] Simulation finished successfully."); + writeCommandLineReport((MiSimModel) experiment.getModel()); + return ExitCodes.SUCCESSFUL_RUN; + + } catch (ParsingException | JsonParseException e) { + Util.printExceptionMessage(e, isDebugOutputOn); + return ExitCodes.EXCEPTION_DURING_PARSING; + } catch (Exception e) { + Util.printExceptionMessage(e, isDebugOutputOn); + return ExitCodes.EXCEPTION_UNKNOWN; + } } private static void writeCommandLineReport(MiSimModel model) { ExperimentMetaData metaData = model.getExperimentMetaData(); System.out.println("\n*** MiSim Report ***"); System.out.println("Simulation of Architecture: " - + metaData.getArchitectureDescriptionLocation().getAbsolutePath()); + + metaData.getArchitectureDescriptionLocation().getAbsolutePath()); System.out.println("Executed Experiment: " - + metaData.getExperimentDescriptionLocation().getAbsolutePath()); + + metaData.getExperimentDescriptionLocation().getAbsolutePath()); System.out.println("Report Location: " - + metaData.getReportLocation().toAbsolutePath()); + + metaData.getReportLocation().toAbsolutePath()); System.out.println("Setup took: " + Util.timeFormat(metaData.getSetupExecutionDuration())); System.out.println("Experiment took: " + Util.timeFormat(metaData.getExperimentExecutionDuration())); System.out.println("Execution took: " + Util.timeFormat(metaData.getExecutionDuration())); diff --git a/src/main/java/cambio/simulator/misc/Util.java b/src/main/java/cambio/simulator/misc/Util.java index 1a4de61c..78547753 100644 --- a/src/main/java/cambio/simulator/misc/Util.java +++ b/src/main/java/cambio/simulator/misc/Util.java @@ -138,8 +138,8 @@ public static void injectField(String fieldName, @NotNull Object object, Object if (field == null) { assert object.getClass() != null; throw new NoSuchFieldException( - String.format("Could not find find field %s on type %s or its super-classes.", fieldName, - object.getClass().getName())); + String.format("Could not find find field %s on type %s or its super-classes.", fieldName, + object.getClass().getName())); } field.setAccessible(true); @@ -165,4 +165,21 @@ public static Field[] getAllFields(Class clazz) { } return list.toArray(new Field[0]); } + + /** + * Prints the message of an exception to the console. If debug output is enabled, the stacktrace is also printed. + * + * @param e the exception + * @param isDebugOutputOn whether the stacktrace should be printed + */ + public static void printExceptionMessage(Exception e, boolean isDebugOutputOn) { + System.out.println("[ERROR] " + e.getMessage()); + if (isDebugOutputOn) { + e.printStackTrace(); + } + } + + public static void printExceptionMessage(Exception e) { + printExceptionMessage(e, false); + } } From cd5105cc7bc465a36ebdab603d8a3493427f4e7d Mon Sep 17 00:00:00 2001 From: LWagner Date: Fri, 24 Nov 2023 20:09:02 +0100 Subject: [PATCH 2/2] chore(test): remove com.github.stefanbirkner.system-lambda dependency --- pom.xml | 9 +-------- src/test/java/cambio/simulator/test/TestBase.java | 15 +++++++-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/pom.xml b/pom.xml index 89981b4c..9c6d0649 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ cambio.simulator misim - 3.3.4-SNAPSHOT + 3.4.0-SNAPSHOT jar MiSim Simulator @@ -28,7 +28,6 @@ 5.9.1 4.8.0 - 1.2.1 @@ -139,12 +138,6 @@ ${mockito.version} test - - com.github.stefanbirkner - system-lambda - ${system-lambda.version} - test - org.apache.commons commons-text diff --git a/src/test/java/cambio/simulator/test/TestBase.java b/src/test/java/cambio/simulator/test/TestBase.java index 070e9d92..a0a3fb2b 100644 --- a/src/test/java/cambio/simulator/test/TestBase.java +++ b/src/test/java/cambio/simulator/test/TestBase.java @@ -1,6 +1,5 @@ package cambio.simulator.test; -import static com.github.stefanbirkner.systemlambda.SystemLambda.catchSystemExit; import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.File; @@ -64,13 +63,13 @@ public Pair getConnectedMockModel(File architecture, protected void runSimulationCheckExit(int expectedExitCode, File arch, File exp, String... additionalArgs) { try { - int code = catchSystemExit(() -> { - String[] fileLocations = new String[] {"-a", arch.getAbsolutePath(), "-e", exp.getAbsolutePath(), "-d"}; - String[] allArgs = new String[additionalArgs.length + fileLocations.length]; - System.arraycopy(fileLocations, 0, allArgs, 0, fileLocations.length); - System.arraycopy(additionalArgs, 0, allArgs, fileLocations.length, additionalArgs.length); - Main.main(allArgs); - }); + String[] fileLocations = new String[]{"-a", arch.getAbsolutePath(), "-e", exp.getAbsolutePath(), "-d"}; + String[] allArgs = new String[additionalArgs.length + fileLocations.length]; + System.arraycopy(fileLocations, 0, allArgs, 0, fileLocations.length); + System.arraycopy(additionalArgs, 0, allArgs, fileLocations.length, additionalArgs.length); + int code = Main.runExperiment(allArgs); + + System.out.println("Test exited with code: " + code); assertEquals(expectedExitCode, code); } catch (Exception e) { Assertions.fail("Simulation failed.", e);