transcendental-lisp/src/test/kotlin/interpreter/LispInterpreterTest.kt

155 lines
5.1 KiB
Kotlin

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<String>()
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())
}
}