Added unit tests, refactored some code, and removed IOException references
This commit is contained in:
parent
f50b07842c
commit
c02ef37f64
|
@ -72,10 +72,6 @@ public class LOAD extends LispFunction {
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
System.out.println("LOAD: " + e.getMessage());
|
System.out.println("LOAD: " + e.getMessage());
|
||||||
|
|
||||||
return Nil.getUniqueInstance();
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.out.println("LOAD: " + e.getMessage());
|
|
||||||
|
|
||||||
return Nil.getUniqueInstance();
|
return Nil.getUniqueInstance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ package main;
|
||||||
import parser.*;
|
import parser.*;
|
||||||
import eval.*;
|
import eval.*;
|
||||||
import error.ErrorManager;
|
import error.ErrorManager;
|
||||||
|
import error.LispException;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
@ -67,11 +69,12 @@ public class LispInterpreter {
|
||||||
|
|
||||||
LispInterpreter.erasePrompt(interactive);
|
LispInterpreter.erasePrompt(interactive);
|
||||||
System.out.println(result);
|
System.out.println(result);
|
||||||
|
} catch (LispException e) {
|
||||||
|
LispInterpreter.erasePrompt(interactive);
|
||||||
|
ErrorManager.generateError(e);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
LispInterpreter.erasePrompt(interactive);
|
LispInterpreter.erasePrompt(interactive);
|
||||||
ErrorManager.generateError(e.getMessage(), 2);
|
ErrorManager.generateError(e.getMessage(), 0);
|
||||||
} catch (IOException e) {
|
|
||||||
ErrorManager.generateError(e.getMessage(), ErrorManager.CRITICAL_LEVEL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interactive) {
|
if (interactive) {
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
|
|
||||||
package parser;
|
package parser;
|
||||||
|
|
||||||
import scanner.*;
|
import java.io.InputStream;
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
import constructs.Token;
|
import constructs.Token;
|
||||||
|
import scanner.LispScanner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A <code>LispParser</code> converts a stream of bytes into internal
|
* A <code>LispParser</code> converts a stream of bytes into internal
|
||||||
|
@ -91,19 +91,12 @@ public class LispParser {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* Indicates that an I/O error has occurred.
|
* Indicates that an I/O error has occurred.
|
||||||
*/
|
*/
|
||||||
public SExpression getSExpr() throws IOException {
|
public SExpression getSExpr() {
|
||||||
if (delayedException != null) {
|
if (delayedException != null) {
|
||||||
// the 'eof' method has stored an exception for us to throw
|
// the 'eof' method has stored an exception for us to throw
|
||||||
|
|
||||||
// determine the type of the stored exception and throw it!
|
// determine the type of the stored exception and throw it!
|
||||||
if (delayedException instanceof IOException) {
|
if (delayedException instanceof RuntimeException) {
|
||||||
IOException e = (IOException) delayedException;
|
|
||||||
|
|
||||||
// remove the exception from 'delayedException'
|
|
||||||
delayedException = null;
|
|
||||||
|
|
||||||
throw e;
|
|
||||||
} else if (delayedException instanceof RuntimeException) {
|
|
||||||
RuntimeException e = (RuntimeException) delayedException;
|
RuntimeException e = (RuntimeException) delayedException;
|
||||||
|
|
||||||
// remove the exception from 'delayedException'
|
// remove the exception from 'delayedException'
|
||||||
|
@ -136,7 +129,7 @@ public class LispParser {
|
||||||
// encountered in the underlying input stream.
|
// encountered in the underlying input stream.
|
||||||
// Throws: IOException - Indicates that an I/O error has occurred.
|
// Throws: IOException - Indicates that an I/O error has occurred.
|
||||||
// Precondition: 'nextToken' is not null.
|
// Precondition: 'nextToken' is not null.
|
||||||
private SExpression sExpr() throws IOException {
|
private SExpression sExpr() {
|
||||||
// determine the type of 'nextToken' and create the appropriate
|
// determine the type of 'nextToken' and create the appropriate
|
||||||
// S-expression
|
// S-expression
|
||||||
switch (nextToken.getType()) {
|
switch (nextToken.getType()) {
|
||||||
|
@ -174,7 +167,7 @@ public class LispParser {
|
||||||
// Returns: an S-expression that matches the rules given above
|
// Returns: an S-expression that matches the rules given above
|
||||||
// Throws: IOException - Indicates that an I/O error has occurred.
|
// Throws: IOException - Indicates that an I/O error has occurred.
|
||||||
// Precondition: 'scanner' is not null.
|
// Precondition: 'scanner' is not null.
|
||||||
private SExpression sExprTail() throws IOException {
|
private SExpression sExprTail() {
|
||||||
nextToken = scanner.getNextToken();
|
nextToken = scanner.getNextToken();
|
||||||
|
|
||||||
// determine the type of 'nextToken' and create the appropriate
|
// determine the type of 'nextToken' and create the appropriate
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class LispScanner {
|
||||||
return retriever.retrieveToken();
|
return retriever.retrieveToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ComplexTokenTextRetriever {
|
private class ComplexTokenTextRetriever {
|
||||||
|
|
||||||
Function<Character, Boolean> isPartOfToken;
|
Function<Character, Boolean> isPartOfToken;
|
||||||
StringBuilder text;
|
StringBuilder text;
|
||||||
|
@ -115,7 +115,7 @@ public class LispScanner {
|
||||||
|
|
||||||
addCharacterToToken();
|
addCharacterToToken();
|
||||||
|
|
||||||
if (isStringToken() && isTerminatingDoubleQuote())
|
if (isTerminatingCharacter())
|
||||||
return text.toString();
|
return text.toString();
|
||||||
|
|
||||||
previousCharacter = currentCharacter;
|
previousCharacter = currentCharacter;
|
||||||
|
@ -132,6 +132,10 @@ public class LispScanner {
|
||||||
positionTracker.incrementLine();
|
positionTracker.incrementLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isTerminatingCharacter() {
|
||||||
|
return isStringToken() && isTerminatingDoubleQuote();
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isStringToken() {
|
private boolean isStringToken() {
|
||||||
return firstCharacter == DOUBLE_QUOTE;
|
return firstCharacter == DOUBLE_QUOTE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -103,6 +103,14 @@ public class LispScannerLineColumnTester {
|
||||||
assertTokenLineAndColumnsMatch(input, expectedLinesAndColumns);
|
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) {
|
private void assertTokenLineAndColumnsMatch(String input, LineColumn[] expectedLineColumnList) {
|
||||||
InputStream stringInputStream = TestUtilities.createInputStreamFromString(input);
|
InputStream stringInputStream = TestUtilities.createInputStreamFromString(input);
|
||||||
LispScanner lispScanner = new LispScanner(stringInputStream, "stringInputStream");
|
LispScanner lispScanner = new LispScanner(stringInputStream, "stringInputStream");
|
||||||
|
|
|
@ -32,11 +32,27 @@ public class LispScannerTextTester {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenEmptyStream_RecordsCorrectInputStreamName() {
|
public void givenEmptyStream_RecordsCorrectFileName() {
|
||||||
String input = "";
|
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) {
|
private void assertTokenTextMatches(String input, String expectedText) {
|
||||||
|
|
|
@ -30,6 +30,18 @@ public class LispScannerTypeTester {
|
||||||
assertTokenTypesMatch(input, expectedTypes);
|
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
|
@Test
|
||||||
public void givenNil_ReturnsCorrectTypes() {
|
public void givenNil_ReturnsCorrectTypes() {
|
||||||
String input = "()";
|
String input = "()";
|
||||||
|
|
Loading…
Reference in New Issue