@@ -0,0 +1,2921 @@
+package it;%0A%0Aimport static org.junit.jupiter.api.Assertions.assertEquals;%0Aimport static org.junit.jupiter.api.Assertions.assertLinesMatch;%0A%0Aimport java.io.BufferedReader;%0Aimport java.io.IOException;%0Aimport java.io.InputStream;%0Aimport java.io.InputStreamReader;%0Aimport java.io.UncheckedIOException;%0Aimport java.nio.file.Path;%0Aimport java.util.List;%0Aimport java.util.concurrent.TimeUnit;%0Aimport java.util.stream.Collectors;%0Aimport org.junit.jupiter.api.DisplayName;%0Aimport org.junit.jupiter.api.Test;%0A%0Aclass SanityTests %7B%0A%0A  private static final String BACH = %22src/bach/Bach.java%22;%0A%0A  private static final List%3CString%3E EXPECTED_NORMAL_OUTPUT_LINES =%0A      List.of(%22%3E%3E INITIALIZATION %3E%3E%22, %22  home='' -%3E %22 + Path.of(%22%22).toUri(), %22  work='bin'%22);%0A%0A  @Test%0A  @DisplayName(%22jshell Bach.jsh%22)%0A  void openAndRunInJShellReturnsZero() throws Exception %7B%0A    var builder = new ProcessBuilder(%22jshell%22);%0A    builder.command().add(%22--execution=local%22);%0A    builder.command().add(%22-J-ea%22);%0A    builder.command().add(%22-%22); // Standard input, without interactive I/O.%0A    var process = builder.start();%0A    var source =%0A        List.of(%0A            %22/open %22 + BACH,%0A            %22var code = 0%22,%0A            %22try %7B%22,%0A            %22  Bach.of().main(List.of(%5C%22info%5C%22));%22,%0A            %22%7D catch (Throwable throwable) %7B%22,%0A            %22  throwable.printStackTrace();%22,%0A            %22  code = 1;%22,%0A            %22%7D%22,%0A            %22%22);%0A    process.getOutputStream().write(String.join(%22%5Cn%22, source).getBytes());%0A    process.getOutputStream().write(%22/exit code%5Cn%22.getBytes());%0A    process.getOutputStream().flush();%0A    process.waitFor(19, TimeUnit.SECONDS);%0A    assertStreams(List.of(), process);%0A    assertEquals(0, process.exitValue(), process.toString());%0A  %7D%0A%0A  @Test%0A  @DisplayName(%22java Bach.java%22)%0A  void compileAndRunWithJavaReturnsZero() throws Exception %7B%0A    var builder = new ProcessBuilder(%22java%22);%0A    builder.command().add(%22-ea%22);%0A    builder.command().add(BACH);%0A    builder.command().add(%22info%22);%0A    var process = builder.start();%0A    process.waitFor(19, TimeUnit.SECONDS);%0A    assertStreams(List.of(), process);%0A    assertEquals(0, process.exitValue(), process.toString());%0A  %7D%0A%0A  static void assertStreams(List%3CString%3E expectedErrorStreamLines, Process process) %7B%0A    var out = lines(process.getInputStream());%0A    var err = lines(process.getErrorStream());%0A    try %7B%0A      assertLinesMatch(EXPECTED_NORMAL_OUTPUT_LINES, out);%0A      assertLinesMatch(expectedErrorStreamLines, err);%0A    %7D catch (AssertionError e) %7B%0A      var msg = String.join(%22%5Cn%22, err) + String.join(%22%5Cn%22, out);%0A      System.err.println(msg);%0A      throw e;%0A    %7D%0A  %7D%0A%0A  static List%3CString%3E lines(InputStream stream) %7B%0A    try (var reader = new BufferedReader(new InputStreamReader(stream))) %7B%0A      return reader.lines().collect(Collectors.toList());%0A    %7D catch (IOException e) %7B%0A      throw new UncheckedIOException(%22Reading from stream failed!%22, e);%0A    %7D%0A  %7D%0A%7D%0A

Add sanity tests ensuring generated Bach.java is compile- and executable