diff --git a/pom.xml b/pom.xml index c05f3ef..5e646ba 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 1.2.31 + 1.2.41 5.1.0 false diff --git a/src/main/kotlin/error/Severity.kt b/src/main/kotlin/error/Severity.kt index 91e048d..761d476 100644 --- a/src/main/kotlin/error/Severity.kt +++ b/src/main/kotlin/error/Severity.kt @@ -6,21 +6,21 @@ enum class Severity { WARNING { override fun decorate(output: String, environment: RuntimeEnvironment): String = - RuntimeEnvironment.decorateWarningOutput(output)!! + RuntimeEnvironment.decorateWarningOutput(output) override fun toDisplayString() = "warning" }, ERROR { override fun decorate(output: String, environment: RuntimeEnvironment): String = - RuntimeEnvironment.decorateErrorOutput(output)!! + RuntimeEnvironment.decorateErrorOutput(output) override fun toDisplayString() = "error" }, CRITICAL { override fun decorate(output: String, environment: RuntimeEnvironment): String = - RuntimeEnvironment.decorateCriticalOutput(output)!! + RuntimeEnvironment.decorateCriticalOutput(output) override fun toDisplayString() = "critical" }; diff --git a/src/main/kotlin/file/FilePosition.java b/src/main/kotlin/file/FilePosition.java deleted file mode 100644 index 83cf0e1..0000000 --- a/src/main/kotlin/file/FilePosition.java +++ /dev/null @@ -1,32 +0,0 @@ -package file; - -public class FilePosition { - - private String fileName; - private int lineNumber; - private int columnNumber; - - public FilePosition(String fileName) { - this.fileName = fileName; - } - - public String getFileName() { - return fileName; - } - - public int getLineNumber() { - return lineNumber; - } - - public void setLineNumber(int lineNumber) { - this.lineNumber = lineNumber; - } - - public int getColumnNumber() { - return columnNumber; - } - - public void setColumnNumber(int columnNumber) { - this.columnNumber = columnNumber; - } -} \ No newline at end of file diff --git a/src/main/kotlin/file/FilePosition.kt b/src/main/kotlin/file/FilePosition.kt new file mode 100644 index 0000000..3332798 --- /dev/null +++ b/src/main/kotlin/file/FilePosition.kt @@ -0,0 +1,3 @@ +package file + +data class FilePosition(val fileName: String, val lineNumber: Int, val columnNumber: Int) \ No newline at end of file diff --git a/src/main/kotlin/file/FilePositionTracker.java b/src/main/kotlin/file/FilePositionTracker.java deleted file mode 100644 index bf6c33e..0000000 --- a/src/main/kotlin/file/FilePositionTracker.java +++ /dev/null @@ -1,31 +0,0 @@ -package file; - -public class FilePositionTracker { - - private String fileName; - private int lineNumber; - private int columnNumber; - - public FilePositionTracker(String fileName) { - this.fileName = fileName; - this.lineNumber = 1; - this.columnNumber = 0; - } - - public FilePosition getCurrentPosition() { - FilePosition currentPosition = new FilePosition(fileName); - currentPosition.setLineNumber(lineNumber); - currentPosition.setColumnNumber(columnNumber); - - return currentPosition; - } - - public void incrementColumn() { - columnNumber++; - } - - public void incrementLine() { - lineNumber++; - columnNumber = 0; - } -} \ No newline at end of file diff --git a/src/main/kotlin/file/FilePositionTracker.kt b/src/main/kotlin/file/FilePositionTracker.kt new file mode 100644 index 0000000..06b2f36 --- /dev/null +++ b/src/main/kotlin/file/FilePositionTracker.kt @@ -0,0 +1,18 @@ +package file + +class FilePositionTracker(private val fileName: String) { + + private var lineNumber = 1 + private var columnNumber = 0 + + fun currentPosition() = FilePosition(fileName = fileName, lineNumber = lineNumber, columnNumber = columnNumber) + + fun incrementColumn() { + columnNumber++ + } + + fun incrementLine() { + lineNumber++ + columnNumber = 0 + } +} \ No newline at end of file diff --git a/src/main/kotlin/interpreter/LispInterpreterBuilder.kt b/src/main/kotlin/interpreter/LispInterpreterBuilder.kt index d57630b..f57b0ff 100644 --- a/src/main/kotlin/interpreter/LispInterpreterBuilder.kt +++ b/src/main/kotlin/interpreter/LispInterpreterBuilder.kt @@ -77,7 +77,7 @@ object LispInterpreterBuilder { this.languageFiles = ArrayList() for (fileName in languageFiles) - this.languageFiles!!.add(LanguageFile(classLoader.getResourceAsStream(fileName), fileName)) + this.languageFiles.add(LanguageFile(classLoader.getResourceAsStream(fileName), fileName)) } fun setTerminationFunction(terminationFunction: () -> Unit) { @@ -135,7 +135,7 @@ object LispInterpreterBuilder { private fun configurePath() { if (isFileBased) - RuntimeEnvironment.path = Path.getPathPrefix(inputName!!) + RuntimeEnvironment.path = Path.getPathPrefix(inputName) else RuntimeEnvironment.path = "" } diff --git a/src/main/kotlin/scanner/LispScanner.java b/src/main/kotlin/scanner/LispScanner.java index 74efabb..e4030f7 100644 --- a/src/main/kotlin/scanner/LispScanner.java +++ b/src/main/kotlin/scanner/LispScanner.java @@ -40,11 +40,11 @@ public class LispScanner { positionTracker.incrementLine(); } - return tokenFactory.createEofToken(positionTracker.getCurrentPosition()); + return tokenFactory.createEofToken(positionTracker.currentPosition()); } private Token createTokenFromCharacter(char c) { - FilePosition currentPosition = positionTracker.getCurrentPosition(); + FilePosition currentPosition = positionTracker.currentPosition(); String tokenText = retrieveTokenText(c); return tokenFactory.createToken(tokenText, currentPosition); @@ -107,7 +107,7 @@ public class LispScanner { public ComplexTokenTextRetriever(char firstCharacter, Function isPartOfToken) { this.isPartOfToken = isPartOfToken; this.text = new StringBuilder(); - this.position = positionTracker.getCurrentPosition(); + this.position = positionTracker.currentPosition(); this.firstCharacter = firstCharacter; this.currentCharacter = firstCharacter; this.previousCharacter = firstCharacter; diff --git a/src/test/kotlin/application/MainTest.kt b/src/test/kotlin/application/MainTest.kt index b5a063e..ecf75ed 100644 --- a/src/test/kotlin/application/MainTest.kt +++ b/src/test/kotlin/application/MainTest.kt @@ -89,7 +89,7 @@ class MainTest : SymbolAndFunctionCleaner() { } @Test - fun runWithBadFile() { + fun `bad file displays correct error message`() { val expectedMessage = "[critical] bad.lisp (No such file or directory)" exit.expectSystemExitWithStatus(1) @@ -102,7 +102,7 @@ class MainTest : SymbolAndFunctionCleaner() { } @Test - fun runWithFile_PrintsDecoratedLastValueOnly() { + fun `interpret file prints the decorated last value only`() { runInterpreterWithFile(FILE) assertEquals("", systemErrLog()) @@ -110,7 +110,7 @@ class MainTest : SymbolAndFunctionCleaner() { } @Test - fun runInteractive() { + fun `run interactive interpreter`() { val terminal = runInterpreterAndGetInteractor() terminal.waitForPrompt() diff --git a/src/test/kotlin/environment/RuntimeEnvironmentTest.kt b/src/test/kotlin/environment/RuntimeEnvironmentTest.kt index 2d87826..e1d21d9 100644 --- a/src/test/kotlin/environment/RuntimeEnvironmentTest.kt +++ b/src/test/kotlin/environment/RuntimeEnvironmentTest.kt @@ -90,7 +90,7 @@ class RuntimeEnvironmentTest { } @Test - fun `assing a prompt decorator`() { + fun `assign a prompt decorator`() { RuntimeEnvironment.promptDecorator = { "[$it]" } assertThat(RuntimeEnvironment.decoratePrompt("test")).isEqualTo("[test]") diff --git a/src/test/kotlin/file/FilePositionTrackerTest.java b/src/test/kotlin/file/FilePositionTrackerTest.java deleted file mode 100644 index 882705f..0000000 --- a/src/test/kotlin/file/FilePositionTrackerTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package file; - -import org.junit.Before; -import org.junit.Test; - -import java.util.Objects; - -import static org.junit.Assert.assertTrue; - -public class FilePositionTrackerTest { - - public static final String FILE_NAME = "testFile"; - - private FilePositionTracker trackerUnderTest; - - private FilePosition createFilePosition(int lineNumber, int columnNumber) { - FilePosition position = new FilePosition(FILE_NAME); - position.setLineNumber(lineNumber); - position.setColumnNumber(columnNumber); - - return position; - } - - private void assertTrackerPositionEquals(FilePosition expectedPosition) { - assertTrue(arePositionsEqual(expectedPosition, trackerUnderTest.getCurrentPosition())); - } - - private boolean arePositionsEqual(FilePosition position1, FilePosition position2) { - return Objects.equals(position1.getFileName(), position2.getFileName()) - && Objects.equals(position1.getLineNumber(), position2.getLineNumber()) - && Objects.equals(position1.getColumnNumber(), position2.getColumnNumber()); - } - - @Before - public void setUp() { - trackerUnderTest = new FilePositionTracker(FILE_NAME); - } - - @Test - public void noMovement_ReturnsInitialPosition() { - assertTrackerPositionEquals(createFilePosition(1, 0)); - } - - @Test - public void advanceOneColumn_ReturnsCorrectPosition() { - trackerUnderTest.incrementColumn(); - - assertTrackerPositionEquals(createFilePosition(1, 1)); - } - - @Test - public void advanceOneLine_ReturnsCorrectPosition() { - trackerUnderTest.incrementLine(); - - assertTrackerPositionEquals(createFilePosition(2, 0)); - } - - @Test - public void advanceOneLine_ResetsColumn() { - trackerUnderTest.incrementColumn(); - trackerUnderTest.incrementLine(); - - assertTrackerPositionEquals(createFilePosition(2, 0)); - } -} diff --git a/src/test/kotlin/file/FilePositionTrackerTest.kt b/src/test/kotlin/file/FilePositionTrackerTest.kt new file mode 100644 index 0000000..c4ddf5d --- /dev/null +++ b/src/test/kotlin/file/FilePositionTrackerTest.kt @@ -0,0 +1,58 @@ +package file + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS + +@TestInstance(PER_CLASS) +class FilePositionTrackerTest { + + companion object { + const val FILE_NAME = "testFile" + } + + private lateinit var trackerUnderTest: FilePositionTracker + + private fun createFilePosition(lineNumber: Int, columnNumber: Int): FilePosition { + return FilePosition(FILE_NAME, lineNumber, columnNumber) + } + + private fun assertTrackerPositionEquals(expectedPosition: FilePosition) { + assertThat(trackerUnderTest.currentPosition()).isEqualTo(expectedPosition) + } + + @BeforeEach + fun setUp() { + trackerUnderTest = FilePositionTracker(FILE_NAME) + } + + @Test + fun noMovement_ReturnsInitialPosition() { + assertTrackerPositionEquals(createFilePosition(1, 0)) + } + + @Test + fun advanceOneColumn_ReturnsCorrectPosition() { + trackerUnderTest.incrementColumn() + + assertTrackerPositionEquals(createFilePosition(1, 1)) + } + + @Test + fun advanceOneLine_ReturnsCorrectPosition() { + trackerUnderTest.incrementLine() + + assertTrackerPositionEquals(createFilePosition(2, 0)) + } + + @Test + fun advanceOneLine_ResetsColumn() { + trackerUnderTest.incrementColumn() + trackerUnderTest.incrementLine() + + assertTrackerPositionEquals(createFilePosition(2, 0)) + } + +} diff --git a/src/test/kotlin/interpreter/LispInterpreterTest.kt b/src/test/kotlin/interpreter/LispInterpreterTest.kt index e3b063a..67ae1e2 100644 --- a/src/test/kotlin/interpreter/LispInterpreterTest.kt +++ b/src/test/kotlin/interpreter/LispInterpreterTest.kt @@ -16,52 +16,50 @@ import java.util.HashSet class LispInterpreterTest { - private var indicatorSet: MutableSet? = null - private var outputStream: ByteArrayOutputStream? = null - private var errorOutputStream: ByteArrayOutputStream? = null - private val environment: RuntimeEnvironment - private val builder: LispInterpreterBuilder - - init { - this.environment = RuntimeEnvironment - this.builder = LispInterpreterBuilder + 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() { - builder.setOutput(PrintStream(outputStream!!)) - builder.setErrorOutput(PrintStream(errorOutputStream!!)) - builder.setTerminationFunction { } - builder.setErrorTerminationFunction { indicatorSet!!.add(TERMINATED) } + LispInterpreterBuilder.setOutput(PrintStream(outputStream)) + LispInterpreterBuilder.setErrorOutput(PrintStream(errorOutputStream)) + LispInterpreterBuilder.setTerminationFunction { } + LispInterpreterBuilder.setErrorTerminationFunction { indicatorSet.add(TERMINATED) } } private fun assertTerminated() { - assertTrue(indicatorSet!!.contains(TERMINATED)) + assertTrue(indicatorSet.contains(TERMINATED)) } private fun assertErrorMessageWritten() { - assertTrue(errorOutputStream!!.toByteArray().size > 0) + assertTrue(errorOutputStream.toByteArray().isNotEmpty()) } @Before fun setUp() { - indicatorSet = HashSet() - outputStream = ByteArrayOutputStream() - errorOutputStream = ByteArrayOutputStream() - environment.reset() - builder.reset() + indicatorSet.clear() + outputStream.reset() + errorOutputStream.reset() + RuntimeEnvironment.reset() + LispInterpreterBuilder.reset() } @After fun tearDown() { - environment.reset() - builder.reset() + RuntimeEnvironment.reset() + LispInterpreterBuilder.reset() } @Test fun buildInteractiveInterpreter() { setCommonFeatures() - builder.setInput(System.`in`, "stdin") - val interpreter = builder.build() + LispInterpreterBuilder.setInput(System.`in`, "stdin") + val interpreter = LispInterpreterBuilder.build() assertTrue(interpreter is InteractiveLispInterpreter) } @@ -69,9 +67,9 @@ class LispInterpreterTest { @Test fun buildNonInteractiveInterpreter() { setCommonFeatures() - builder.setInput(System.`in`, "stdin") - builder.setNotInteractive() - val interpreter = builder.build() + LispInterpreterBuilder.setInput(System.`in`, "stdin") + LispInterpreterBuilder.setNotInteractive() + val interpreter = LispInterpreterBuilder.build() assertFalse(interpreter is InteractiveLispInterpreter) assertFalse(interpreter is FileLispInterpreter) @@ -80,8 +78,8 @@ class LispInterpreterTest { @Test fun buildFileBasedInterpreter() { setCommonFeatures() - builder.useFile(FILE) - val interpreter = builder.build() + LispInterpreterBuilder.useFile(FILE) + val interpreter = LispInterpreterBuilder.build() assertTrue(interpreter is FileLispInterpreter) } @@ -89,8 +87,8 @@ class LispInterpreterTest { @Test fun attemptToBuildInterpreterOnBadFile() { setCommonFeatures() - builder.useFile("does-not-exist.lisp") - builder.build() + LispInterpreterBuilder.useFile("does-not-exist.lisp") + LispInterpreterBuilder.build() assertErrorMessageWritten() assertTerminated() @@ -98,65 +96,59 @@ class LispInterpreterTest { @Test fun makeSureDecoratorsAreInitializedWithDefaults() { - builder.build() + LispInterpreterBuilder.build() - assertEquals("", environment.decoratePrompt("")) - assertEquals("", environment.decorateValueOutput("")) - assertEquals("", environment.decorateWarningOutput("")) - assertEquals("", environment.decorateErrorOutput("")) - assertEquals("", environment.decorateCriticalOutput("")) + assertEquals("", RuntimeEnvironment.decoratePrompt("")) + assertEquals("", RuntimeEnvironment.decorateValueOutput("")) + assertEquals("", RuntimeEnvironment.decorateWarningOutput("")) + assertEquals("", RuntimeEnvironment.decorateErrorOutput("")) + assertEquals("", RuntimeEnvironment.decorateCriticalOutput("")) } @Test fun makeSureDecoratorsAreSetCorrectly() { - builder.setPromptDecorator { s -> "#$s#" } - builder.setValueOutputDecorator { s -> "@$s@" } - builder.setWarningOutputDecorator { s -> "%$s%" } - builder.setErrorOutputDecorator { s -> "*$s*" } - builder.setCriticalOutputDecorator { s -> "$$s$" } - builder.build() + LispInterpreterBuilder.setPromptDecorator { s -> "#$s#" } + LispInterpreterBuilder.setValueOutputDecorator { s -> "@$s@" } + LispInterpreterBuilder.setWarningOutputDecorator { s -> "%$s%" } + LispInterpreterBuilder.setErrorOutputDecorator { s -> "*$s*" } + LispInterpreterBuilder.setCriticalOutputDecorator { s -> "$$s$" } + LispInterpreterBuilder.build() - assertEquals("#x#", environment.decoratePrompt("x")) - assertEquals("@x@", environment.decorateValueOutput("x")) - assertEquals("%x%", environment.decorateWarningOutput("x")) - assertEquals("*x*", environment.decorateErrorOutput("x")) - assertEquals("\$x$", environment.decorateCriticalOutput("x")) + 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() - builder.useFile(FILE) - builder.build().interpret() + LispInterpreterBuilder.useFile(FILE) + LispInterpreterBuilder.build().interpret() - assertEquals("PICKLE\n\n", outputStream!!.toString()) - assertEquals("", errorOutputStream!!.toString()) + assertEquals("PICKLE\n\n", outputStream.toString()) + assertEquals("", errorOutputStream.toString()) } @Test fun interactiveInterpreterWorks() { setCommonFeatures() - builder.setInput(createInputStreamFromString("'pickle"), "input") - builder.build().interpret() + LispInterpreterBuilder.setInput(createInputStreamFromString("'pickle"), "input") + LispInterpreterBuilder.build().interpret() - assertEquals(format("{0}\n{1}\n{0}\n", PROMPT, "PICKLE"), outputStream!!.toString()) - assertEquals("", errorOutputStream!!.toString()) + assertEquals(format("{0}\n{1}\n{0}\n", PROMPT, "PICKLE"), outputStream.toString()) + assertEquals("", errorOutputStream.toString()) } @Test fun interpreterHandlesError() { setCommonFeatures() - builder.setNotInteractive() - builder.setInput(createInputStreamFromString("pickle"), "input") - builder.build().interpret() + LispInterpreterBuilder.setNotInteractive() + LispInterpreterBuilder.setInput(createInputStreamFromString("pickle"), "input") + LispInterpreterBuilder.build().interpret() - assertEquals("\n", outputStream!!.toString()) - assertEquals("[error] symbol PICKLE has no value\n", errorOutputStream!!.toString()) - } - - companion object { - - private val TERMINATED = "terminated" - private val FILE = LispInterpreterTest::class.java.getResource("file.lisp").file + assertEquals("\n", outputStream.toString()) + assertEquals("[error] symbol PICKLE has no value\n", errorOutputStream.toString()) } } diff --git a/src/test/kotlin/testutil/SymbolAndFunctionCleaner.kt b/src/test/kotlin/testutil/SymbolAndFunctionCleaner.kt index d16b86f..ab18a68 100644 --- a/src/test/kotlin/testutil/SymbolAndFunctionCleaner.kt +++ b/src/test/kotlin/testutil/SymbolAndFunctionCleaner.kt @@ -29,6 +29,5 @@ abstract class SymbolAndFunctionCleaner { } open fun additionalSetUp() {} - open fun additionalTearDown() {} } diff --git a/src/test/kotlin/token/TokenFactoryTest.java b/src/test/kotlin/token/TokenFactoryTest.java index 2354909..170b6f8 100644 --- a/src/test/kotlin/token/TokenFactoryTest.java +++ b/src/test/kotlin/token/TokenFactoryTest.java @@ -21,9 +21,7 @@ public class TokenFactoryTest { @Before public void setUp() { tokenFactory = new TokenFactoryImpl(); - testPosition = new FilePosition("testFile"); - testPosition.setLineNumber(0); - testPosition.setColumnNumber(0); + testPosition = new FilePosition("testFile", 0, 0); } private Token createToken(String text) {