package interpreter import environment.RuntimeEnvironment import interpreter.InteractiveLispInterpreter.PROMPT import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import testutil.TestUtilities.createInputStreamFromString import java.io.ByteArrayOutputStream import java.io.PrintStream import java.text.MessageFormat.format import java.util.HashSet class LispInterpreterTest { companion object { private const val TERMINATED = "terminated" private val FILE = LispInterpreterTest::class.java.getResource("file.lisp").file } private var indicatorSet = HashSet() private var outputStream = ByteArrayOutputStream() private var errorOutputStream = ByteArrayOutputStream() private fun setCommonFeatures() { LispInterpreterBuilder.setOutput(PrintStream(outputStream)) LispInterpreterBuilder.setErrorOutput(PrintStream(errorOutputStream)) LispInterpreterBuilder.setTerminationFunction { } LispInterpreterBuilder.setErrorTerminationFunction { indicatorSet.add(TERMINATED) } } private fun assertTerminated() { assertTrue(indicatorSet.contains(TERMINATED)) } private fun assertErrorMessageWritten() { assertTrue(errorOutputStream.toByteArray().isNotEmpty()) } @Before fun setUp() { indicatorSet.clear() outputStream.reset() errorOutputStream.reset() RuntimeEnvironment.reset() LispInterpreterBuilder.reset() } @After fun tearDown() { RuntimeEnvironment.reset() LispInterpreterBuilder.reset() } @Test fun buildInteractiveInterpreter() { setCommonFeatures() LispInterpreterBuilder.setInput(System.`in`, "stdin") val interpreter = LispInterpreterBuilder.build() assertTrue(interpreter is InteractiveLispInterpreter) } @Test fun buildNonInteractiveInterpreter() { setCommonFeatures() LispInterpreterBuilder.setInput(System.`in`, "stdin") LispInterpreterBuilder.setNotInteractive() val interpreter = LispInterpreterBuilder.build() assertFalse(interpreter is InteractiveLispInterpreter) assertFalse(interpreter is FileLispInterpreter) } @Test fun buildFileBasedInterpreter() { setCommonFeatures() LispInterpreterBuilder.useFile(FILE) val interpreter = LispInterpreterBuilder.build() assertTrue(interpreter is FileLispInterpreter) } @Test fun attemptToBuildInterpreterOnBadFile() { setCommonFeatures() LispInterpreterBuilder.useFile("does-not-exist.lisp") LispInterpreterBuilder.build() assertErrorMessageWritten() assertTerminated() } @Test fun makeSureDecoratorsAreInitializedWithDefaults() { LispInterpreterBuilder.build() assertEquals("", RuntimeEnvironment.decoratePrompt("")) assertEquals("", RuntimeEnvironment.decorateValueOutput("")) assertEquals("", RuntimeEnvironment.decorateWarningOutput("")) assertEquals("", RuntimeEnvironment.decorateErrorOutput("")) assertEquals("", RuntimeEnvironment.decorateCriticalOutput("")) } @Test fun makeSureDecoratorsAreSetCorrectly() { LispInterpreterBuilder.setPromptDecorator { s -> "#$s#" } LispInterpreterBuilder.setValueOutputDecorator { s -> "@$s@" } LispInterpreterBuilder.setWarningOutputDecorator { s -> "%$s%" } LispInterpreterBuilder.setErrorOutputDecorator { s -> "*$s*" } LispInterpreterBuilder.setCriticalOutputDecorator { s -> "$$s$" } LispInterpreterBuilder.build() assertEquals("#x#", RuntimeEnvironment.decoratePrompt("x")) assertEquals("@x@", RuntimeEnvironment.decorateValueOutput("x")) assertEquals("%x%", RuntimeEnvironment.decorateWarningOutput("x")) assertEquals("*x*", RuntimeEnvironment.decorateErrorOutput("x")) assertEquals("\$x$", RuntimeEnvironment.decorateCriticalOutput("x")) } @Test fun fileBasedInterpreterWorks_PrintsLastValueOnly() { setCommonFeatures() LispInterpreterBuilder.useFile(FILE) LispInterpreterBuilder.build().interpret() assertEquals("PICKLE\n\n", outputStream.toString()) assertEquals("", errorOutputStream.toString()) } @Test fun interactiveInterpreterWorks() { setCommonFeatures() LispInterpreterBuilder.setInput(createInputStreamFromString("'pickle"), "input") LispInterpreterBuilder.build().interpret() assertEquals(format("{0}\n{1}\n{0}\n", PROMPT, "PICKLE"), outputStream.toString()) assertEquals("", errorOutputStream.toString()) } @Test fun interpreterHandlesError() { setCommonFeatures() LispInterpreterBuilder.setNotInteractive() LispInterpreterBuilder.setInput(createInputStreamFromString("pickle"), "input") LispInterpreterBuilder.build().interpret() assertEquals("\n", outputStream.toString()) assertEquals("[error] symbol PICKLE has no value\n", errorOutputStream.toString()) } }