package main; import static java.text.MessageFormat.format; import static main.LispMain.ANSI_GREEN; import static main.LispMain.ANSI_PURPLE; import static main.LispMain.ANSI_RESET; import static main.LispMain.GREETING; import static org.junit.Assert.assertEquals; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.util.concurrent.CountDownLatch; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.ExpectedSystemExit; import org.junit.contrib.java.lang.system.SystemErrRule; import org.junit.contrib.java.lang.system.SystemOutRule; import com.googlecode.lanterna.input.KeyType; import com.googlecode.lanterna.terminal.virtual.DefaultVirtualTerminal; import environment.RuntimeEnvironment; import interpreter.LispInterpreterBuilderImpl; import terminal.TerminalConfiguration; import terminal.VirtualTerminalInteractor; public class MainTest { private RuntimeEnvironment environment; private CountDownLatch latch; public MainTest() { this.environment = RuntimeEnvironment.getInstance(); } private void runInterpreterWithFile(String fileName) { TerminalConfiguration configuration = new TerminalConfiguration(); configuration.setInputPair(new PipedOutputStream(), new PipedInputStream()); configuration.setOutputPair(new PipedOutputStream(), new PipedInputStream()); configuration.setTerminal(new DefaultVirtualTerminal()); LispMain main = new LispMain(new LispInterpreterBuilderImpl() {}, configuration); main.runWithFile(fileName); } private VirtualTerminalInteractor runInterpreterAndGetInteractor() { VirtualTerminalInteractor terminal = new VirtualTerminalInteractor(); latch = new CountDownLatch(1); new Thread(() -> { try { LispMain main = new LispMain(new LispInterpreterBuilderImpl() {}, terminal.getConfiguration()); main.runInteractive(); } finally { latch.countDown(); } }).start(); return terminal; } private void waitForInterpreterToShutdown() { try { latch.await(); } catch (InterruptedException ignored) {} } private String getSystemOutLog() { return systemOutRule.getLogWithNormalizedLineSeparator(); } private String getSystemErrLog() { return systemErrRule.getLogWithNormalizedLineSeparator(); } @Rule public ExpectedSystemExit exit = ExpectedSystemExit.none(); @Rule public SystemErrRule systemErrRule = new SystemErrRule().enableLog().mute(); @Rule public SystemOutRule systemOutRule = new SystemOutRule().enableLog().mute(); @Before public void setUp() { environment.reset(); } @After public void tearDown() { environment.reset(); } @Test public void runWithBadFile() { String expectedMessage = "[critical] test/main/test-files/bad.lisp (No such file or directory)"; exit.expectSystemExitWithStatus(1); exit.checkAssertionAfterwards(() -> { assertEquals(format("{0}{1}{2}\n", ANSI_PURPLE, expectedMessage, ANSI_RESET), getSystemErrLog()); assertEquals("", getSystemOutLog()); }); runInterpreterWithFile("test/main/test-files/bad.lisp"); } @Test public void runWithFile_PrintsDecoratedLastValueOnly() { runInterpreterWithFile("test/main/test-files/file.lisp"); assertEquals("", getSystemErrLog()); assertEquals(format("{0}{1}{2}\n\n", ANSI_GREEN, "RADISH", ANSI_RESET), getSystemOutLog()); } @Test public void runInteractive() { VirtualTerminalInteractor terminal = runInterpreterAndGetInteractor(); terminal.waitForPrompt(); terminal.enterCharacters("'hi"); terminal.pressKey(KeyType.Enter); terminal.waitForPrompt(); terminal.assertCursorPosition(2, 5); terminal.assertScreenText(GREETING, " ", "~ 'hi ", " ", "HI ", "~ "); terminal.enterControlCharacter('d'); terminal.assertInputStreamClosed(); waitForInterpreterToShutdown(); } @Test public void runMain() { LispMain.main(new String[] { "test/main/test-files/file.lisp" }); assertEquals("", getSystemErrLog()); assertEquals(format("{0}{1}{2}\n\n", ANSI_GREEN, "RADISH", ANSI_RESET), getSystemOutLog()); } }