From c02ef37f64dbaaf8b506c3b23535fde16a0c3a46 Mon Sep 17 00:00:00 2001 From: Mike Cifelli Date: Sun, 11 Dec 2016 15:09:48 -0500 Subject: [PATCH] Added unit tests, refactored some code, and removed IOException references --- src/eval/LOAD.java | 4 -- src/main/LispInterpreter.java | 9 ++- src/parser/LispParser.java | 19 ++--- src/scanner/LispScanner.java | 8 ++- test/constructs/TokenFactoryTester.java | 70 +++++++++++++++++++ test/scanner/LispScannerLineColumnTester.java | 8 +++ test/scanner/LispScannerTextTester.java | 22 +++++- test/scanner/LispScannerTypeTester.java | 12 ++++ 8 files changed, 127 insertions(+), 25 deletions(-) create mode 100644 test/constructs/TokenFactoryTester.java diff --git a/src/eval/LOAD.java b/src/eval/LOAD.java index 4a94235..1ce3f57 100644 --- a/src/eval/LOAD.java +++ b/src/eval/LOAD.java @@ -72,10 +72,6 @@ public class LOAD extends LispFunction { } catch (RuntimeException e) { System.out.println("LOAD: " + e.getMessage()); - return Nil.getUniqueInstance(); - } catch (IOException e) { - System.out.println("LOAD: " + e.getMessage()); - return Nil.getUniqueInstance(); } } diff --git a/src/main/LispInterpreter.java b/src/main/LispInterpreter.java index 154e1fe..abfbb26 100644 --- a/src/main/LispInterpreter.java +++ b/src/main/LispInterpreter.java @@ -9,6 +9,8 @@ package main; import parser.*; import eval.*; import error.ErrorManager; +import error.LispException; + import java.io.*; import java.text.MessageFormat; @@ -67,11 +69,12 @@ public class LispInterpreter { LispInterpreter.erasePrompt(interactive); System.out.println(result); + } catch (LispException e) { + LispInterpreter.erasePrompt(interactive); + ErrorManager.generateError(e); } catch (RuntimeException e) { LispInterpreter.erasePrompt(interactive); - ErrorManager.generateError(e.getMessage(), 2); - } catch (IOException e) { - ErrorManager.generateError(e.getMessage(), ErrorManager.CRITICAL_LEVEL); + ErrorManager.generateError(e.getMessage(), 0); } if (interactive) { diff --git a/src/parser/LispParser.java b/src/parser/LispParser.java index f93e11a..ebd5be5 100644 --- a/src/parser/LispParser.java +++ b/src/parser/LispParser.java @@ -6,10 +6,10 @@ package parser; -import scanner.*; -import java.io.*; +import java.io.InputStream; import constructs.Token; +import scanner.LispScanner; /** * A LispParser converts a stream of bytes into internal @@ -91,19 +91,12 @@ public class LispParser { * @throws IOException * Indicates that an I/O error has occurred. */ - public SExpression getSExpr() throws IOException { + public SExpression getSExpr() { if (delayedException != null) { // the 'eof' method has stored an exception for us to throw // determine the type of the stored exception and throw it! - if (delayedException instanceof IOException) { - IOException e = (IOException) delayedException; - - // remove the exception from 'delayedException' - delayedException = null; - - throw e; - } else if (delayedException instanceof RuntimeException) { + if (delayedException instanceof RuntimeException) { RuntimeException e = (RuntimeException) delayedException; // remove the exception from 'delayedException' @@ -136,7 +129,7 @@ public class LispParser { // encountered in the underlying input stream. // Throws: IOException - Indicates that an I/O error has occurred. // Precondition: 'nextToken' is not null. - private SExpression sExpr() throws IOException { + private SExpression sExpr() { // determine the type of 'nextToken' and create the appropriate // S-expression switch (nextToken.getType()) { @@ -174,7 +167,7 @@ public class LispParser { // Returns: an S-expression that matches the rules given above // Throws: IOException - Indicates that an I/O error has occurred. // Precondition: 'scanner' is not null. - private SExpression sExprTail() throws IOException { + private SExpression sExprTail() { nextToken = scanner.getNextToken(); // determine the type of 'nextToken' and create the appropriate diff --git a/src/scanner/LispScanner.java b/src/scanner/LispScanner.java index 7a1b84e..ebc2910 100644 --- a/src/scanner/LispScanner.java +++ b/src/scanner/LispScanner.java @@ -83,7 +83,7 @@ public class LispScanner { return retriever.retrieveToken(); } - public class ComplexTokenTextRetriever { + private class ComplexTokenTextRetriever { Function isPartOfToken; StringBuilder text; @@ -115,7 +115,7 @@ public class LispScanner { addCharacterToToken(); - if (isStringToken() && isTerminatingDoubleQuote()) + if (isTerminatingCharacter()) return text.toString(); previousCharacter = currentCharacter; @@ -132,6 +132,10 @@ public class LispScanner { positionTracker.incrementLine(); } + private boolean isTerminatingCharacter() { + return isStringToken() && isTerminatingDoubleQuote(); + } + private boolean isStringToken() { return firstCharacter == DOUBLE_QUOTE; } diff --git a/test/constructs/TokenFactoryTester.java b/test/constructs/TokenFactoryTester.java new file mode 100644 index 0000000..38d25e1 --- /dev/null +++ b/test/constructs/TokenFactoryTester.java @@ -0,0 +1,70 @@ +package constructs; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + +import file.FilePosition; + +public class TokenFactoryTester { + + private TokenFactory tokenFactory; + private FilePosition testPosition; + + @Before + public void setUp() throws Exception { + tokenFactory = new TokenFactoryImpl(); + testPosition = new FilePosition("testFile"); + testPosition.setLineNumber(0); + testPosition.setColumnNumber(0); + } + + @Test + public void testEOFTokenCreation() { + assertEquals(Token.Type.EOF, tokenFactory.createEOFToken(testPosition).getType()); + } + + @Test + public void testLeftParenthesisCreation() { + String text = "("; + assertEquals(Token.Type.LEFT_PAREN, tokenFactory.createToken(text, testPosition).getType()); + } + + @Test + public void testRightParenthesisCreation() { + String text = ")"; + assertEquals(Token.Type.RIGHT_PAREN, tokenFactory.createToken(text, testPosition).getType()); + } + + @Test + public void testQuoteMarkCreation() { + String text = "'"; + assertEquals(Token.Type.QUOTE_MARK, tokenFactory.createToken(text, testPosition).getType()); + } + + @Test + public void testNumberCreation() { + String text = "987"; + assertEquals(Token.Type.NUMBER, tokenFactory.createToken(text, testPosition).getType()); + } + + @Test + public void testIdentifierCreation() { + String text = "identifier"; + assertEquals(Token.Type.IDENTIFIER, tokenFactory.createToken(text, testPosition).getType()); + } + + @Test + public void testStringCreation() { + String text = "\"string\""; + assertEquals(Token.Type.STRING, tokenFactory.createToken(text, testPosition).getType()); + } + + @Test(expected = TokenFactory.BadCharacterException.class) + public void testBadCharacter() { + String text = "[abc]"; + tokenFactory.createToken(text, testPosition); + } + +} diff --git a/test/scanner/LispScannerLineColumnTester.java b/test/scanner/LispScannerLineColumnTester.java index fb922c9..7cc3c49 100644 --- a/test/scanner/LispScannerLineColumnTester.java +++ b/test/scanner/LispScannerLineColumnTester.java @@ -103,6 +103,14 @@ public class LispScannerLineColumnTester { assertTokenLineAndColumnsMatch(input, expectedLinesAndColumns); } + @Test + public void givenCommentImmediatelyFollowingNumber_RecordsCorrectLocations() { + String input = "12;comment\n34"; + LineColumn[] expectedLinesAndColumns = { LineColumn.create(1, 1), LineColumn.create(2, 1) }; + + assertTokenLineAndColumnsMatch(input, expectedLinesAndColumns); + } + private void assertTokenLineAndColumnsMatch(String input, LineColumn[] expectedLineColumnList) { InputStream stringInputStream = TestUtilities.createInputStreamFromString(input); LispScanner lispScanner = new LispScanner(stringInputStream, "stringInputStream"); diff --git a/test/scanner/LispScannerTextTester.java b/test/scanner/LispScannerTextTester.java index 7887df5..16f8138 100644 --- a/test/scanner/LispScannerTextTester.java +++ b/test/scanner/LispScannerTextTester.java @@ -32,11 +32,27 @@ public class LispScannerTextTester { } @Test - public void givenEmptyStream_RecordsCorrectInputStreamName() { + public void givenEmptyStream_RecordsCorrectFileName() { String input = ""; - String expectedInputStreamName = "testInputStream"; + String expectedFileName = "testFileName"; - assertInputFileNameMatches(input, expectedInputStreamName); + assertInputFileNameMatches(input, expectedFileName); + } + + @Test + public void givenNumberFollowedByComment_RecordsCorrectText() { + String input = "192837456;comment"; + String expected = "192837456"; + + assertTokenTextMatches(input, expected); + } + + @Test + public void givenIdentifiersWithCommentBetween_RecordsCorrectText() { + String input = "abc123;comment\nabc222"; + String expected = "abc123"; + + assertTokenTextMatches(input, expected); } private void assertTokenTextMatches(String input, String expectedText) { diff --git a/test/scanner/LispScannerTypeTester.java b/test/scanner/LispScannerTypeTester.java index 5349f58..e514b18 100644 --- a/test/scanner/LispScannerTypeTester.java +++ b/test/scanner/LispScannerTypeTester.java @@ -30,6 +30,18 @@ public class LispScannerTypeTester { assertTokenTypesMatch(input, expectedTypes); } + @Test + public void givenBadCharacter_ExceptionContainsCorrectSeverity() { + String input = "abc\ndef["; + Token.Type[] expectedTypes = { Type.IDENTIFIER, Type.IDENTIFIER }; + + try { + assertTokenTypesMatch(input, expectedTypes); + } catch (TokenFactory.BadCharacterException e) { + assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL); + } + } + @Test public void givenNil_ReturnsCorrectTypes() { String input = "()";