Refactored some code and added unit tests

This commit is contained in:
Mike Cifelli 2016-12-16 11:26:53 -05:00
parent 62a509eb4b
commit 60a7eb562c
9 changed files with 262 additions and 101 deletions

View File

@ -1,5 +1,9 @@
package sexpression;
import java.text.MessageFormat;
import error.LispException;
public class LispNumber extends Atom {
private int value;
@ -10,7 +14,7 @@ public class LispNumber extends Atom {
try {
this.value = Integer.parseInt(text);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(text + " is not a valid integer");
throw new InvalidNumberException(text);
}
}
@ -28,4 +32,25 @@ public class LispNumber extends Atom {
return value;
}
public class InvalidNumberException extends LispException {
private static final long serialVersionUID = 1L;
private String text;
public InvalidNumberException(String text) {
this.text = text;
}
@Override
public int getSeverity() {
return 0;
}
@Override
public String getMessage() {
return MessageFormat.format("{0} is not a valid integer", text);
}
}
}

View File

@ -2,20 +2,6 @@ package sexpression;
public abstract class SExpression {
// for mark and sweep garbage collection
private boolean marked = false;
public final boolean isMarked() {
return marked;
}
public final void setMarked(final boolean value) {
marked = value;
}
// Lisp type predicates...
// overridden in subclasses to describe their Lisp type
public boolean nullp() {
return false;
}

View File

@ -3,8 +3,8 @@ package token;
import java.util.function.Supplier;
import file.FilePosition;
import sexpression.MalformedSExpressionException.EofEncounteredException;
import sexpression.SExpression;
import token.ParseException.EofEncounteredException;
public class Eof extends Token {

View File

@ -1,16 +1,15 @@
package sexpression;
package token;
import java.text.MessageFormat;
import error.LispException;
import token.Token;
public abstract class MalformedSExpressionException extends LispException {
public abstract class ParseException extends LispException {
private static final long serialVersionUID = 1L;
private Token token;
public MalformedSExpressionException(Token token) {
public ParseException(Token token) {
this.token = token;
}
@ -27,7 +26,7 @@ public abstract class MalformedSExpressionException extends LispException {
public abstract String getMessagePrefix();
public static class EofEncounteredException extends MalformedSExpressionException {
public static class EofEncounteredException extends ParseException {
private static final long serialVersionUID = 1L;
@ -40,7 +39,7 @@ public abstract class MalformedSExpressionException extends LispException {
}
}
public static class StartsWithRightParenthesisException extends MalformedSExpressionException {
public static class StartsWithRightParenthesisException extends ParseException {
private static final long serialVersionUID = 1L;
@ -53,17 +52,4 @@ public abstract class MalformedSExpressionException extends LispException {
}
}
public static class UnrecognizedTokenException extends MalformedSExpressionException {
private static final long serialVersionUID = 1L;
public UnrecognizedTokenException(Token token) {
super(token);
}
public String getMessagePrefix() {
return "Unrecognized token";
}
}
}

View File

@ -3,9 +3,9 @@ package token;
import java.util.function.Supplier;
import file.FilePosition;
import sexpression.MalformedSExpressionException.StartsWithRightParenthesisException;
import sexpression.Nil;
import sexpression.SExpression;
import token.ParseException.StartsWithRightParenthesisException;
public class RightParenthesis extends Token {

View File

@ -1,6 +1,7 @@
package parser;
import static org.junit.Assert.*;
import static parser.SExpressionTypeAssertions.*;
import static testutil.TestUtilities.createIOExceptionThrowingInputStream;
import static testutil.TestUtilities.createInputStreamFromString;
@ -8,13 +9,12 @@ import java.io.InputStream;
import org.junit.Test;
import error.ErrorManager;
import error.LispException;
import scanner.LispInputStream.UncheckedIOException;
import scanner.LispScanner.UnterminatedStringException;
import sexpression.MalformedSExpressionException.EofEncounteredException;
import sexpression.MalformedSExpressionException.StartsWithRightParenthesisException;
import sexpression.Nil;
import sexpression.SExpression;
import token.ParseException.EofEncounteredException;
import token.ParseException.StartsWithRightParenthesisException;
import token.TokenFactory.BadCharacterException;
public class LispParserTester {
@ -29,64 +29,6 @@ public class LispParserTester {
return new LispParser(stringInputStream, "testFile");
}
private void assertList(SExpression sExpression) {
assertFalse(sExpression.atomp());
assertTrue(sExpression.consp());
assertFalse(sExpression.functionp());
assertTrue(sExpression.listp());
assertFalse(sExpression.nullp());
assertFalse(sExpression.numberp());
assertFalse(sExpression.stringp());
assertFalse(sExpression.symbolp());
}
private void assertNil(SExpression sExpression) {
assertEquals(sExpression, Nil.getUniqueInstance());
assertTrue(sExpression.atomp());
assertFalse(sExpression.consp());
assertFalse(sExpression.functionp());
assertTrue(sExpression.listp());
assertTrue(sExpression.nullp());
assertFalse(sExpression.numberp());
assertFalse(sExpression.stringp());
assertTrue(sExpression.symbolp());
}
private void assertNumber(SExpression sExpression) {
assertTrue(sExpression.atomp());
assertFalse(sExpression.consp());
assertFalse(sExpression.functionp());
assertFalse(sExpression.listp());
assertFalse(sExpression.nullp());
assertTrue(sExpression.numberp());
assertFalse(sExpression.stringp());
assertFalse(sExpression.symbolp());
}
private void assertString(SExpression sExpression) {
assertTrue(sExpression.atomp());
assertFalse(sExpression.consp());
assertFalse(sExpression.functionp());
assertFalse(sExpression.listp());
assertFalse(sExpression.nullp());
assertFalse(sExpression.numberp());
assertTrue(sExpression.stringp());
assertFalse(sExpression.symbolp());
}
private void assertSymbol(SExpression sExpression) {
assertTrue(sExpression.atomp());
assertFalse(sExpression.consp());
assertFalse(sExpression.functionp());
assertFalse(sExpression.listp());
assertFalse(sExpression.nullp());
assertFalse(sExpression.numberp());
assertFalse(sExpression.stringp());
assertTrue(sExpression.symbolp());
}
@Test
public void testEofMethod_ReturnsTrueWithNoInput() {
String input = "";
@ -107,8 +49,8 @@ public class LispParserTester {
public void testEofMethod_ReturnsTrueAfterSomeInput() {
String input = "(yyz 9 9 9)";
LispParser parser = createLispParser(input);
parser.getNextSExpression();
parser.getNextSExpression();
assertTrue(parser.isEof());
}
@ -116,6 +58,7 @@ public class LispParserTester {
public void testEofMethod_ReturnsFalseAfterMultipleExpressions() {
String input = "()()()";
LispParser parser = createLispParser(input);
assertFalse(parser.isEof());
parser.getNextSExpression();
assertFalse(parser.isEof());
@ -127,6 +70,7 @@ public class LispParserTester {
public void testEofMethod_ReturnsTrueAfterMultipleExpressions() {
String input = "()()()";
LispParser parser = createLispParser(input);
assertFalse(parser.isEof());
parser.getNextSExpression();
assertFalse(parser.isEof());
@ -238,6 +182,33 @@ public class LispParserTester {
parser.getNextSExpression();
}
@Test
public void givenBadToken_ExceptionHasCorrectSeverity() {
String input = "[";
LispParser parser = createLispParser(input);
try {
parser.getNextSExpression();
} catch (BadCharacterException e) {
assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL);
}
}
@Test
public void givenBadToken_ExceptionHasMessageText() {
String input = "[";
LispParser parser = createLispParser(input);
try {
parser.getNextSExpression();
} catch (BadCharacterException e) {
String message = e.getMessage();
assertNotNull(message);
assertTrue(message.length() > 0);
}
}
@Test(expected = UnterminatedStringException.class)
public void givenUnterminatedString_ThrowsException() {
String input = "\"string";
@ -254,6 +225,33 @@ public class LispParserTester {
parser.getNextSExpression();
}
@Test
public void givenUnterminatedList_ExceptionHasCorrectSeverity() {
String input = "(bad list";
LispParser parser = createLispParser(input);
try {
parser.getNextSExpression();
} catch (EofEncounteredException e) {
assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL);
}
}
@Test
public void givenUnterminatedList_ExceptionHasMessage() {
String input = "(bad list";
LispParser parser = createLispParser(input);
try {
parser.getNextSExpression();
} catch (EofEncounteredException e) {
String message = e.getMessage();
assertNotNull(message);
assertTrue(message.length() > 0);
}
}
@Test(expected = StartsWithRightParenthesisException.class)
public void givenUnmatchedRightParenthesis_ThrowsException() {
String input = ")";
@ -262,6 +260,33 @@ public class LispParserTester {
parser.getNextSExpression();
}
@Test
public void givenUnmatchedRightParenthesis_ExceptionHasCorrectSeverity() {
String input = ")";
LispParser parser = createLispParser(input);
try {
parser.getNextSExpression();
} catch (StartsWithRightParenthesisException e) {
assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL);
}
}
@Test
public void givenUnmatchedRightParenthesis_ExceptionHasMessage() {
String input = ")";
LispParser parser = createLispParser(input);
try {
parser.getNextSExpression();
} catch (StartsWithRightParenthesisException e) {
String message = e.getMessage();
assertNotNull(message);
assertTrue(message.length() > 0);
}
}
@Test(expected = BadCharacterException.class)
public void givenBadCharacter_ThrowsExceptionAfterEofCalled() {
String input = "[";

View File

@ -0,0 +1,68 @@
package parser;
import static org.junit.Assert.*;
import sexpression.Nil;
import sexpression.SExpression;
public final class SExpressionTypeAssertions {
public static void assertList(SExpression sExpression) {
assertFalse(sExpression.atomp());
assertTrue(sExpression.consp());
assertFalse(sExpression.functionp());
assertTrue(sExpression.listp());
assertFalse(sExpression.nullp());
assertFalse(sExpression.numberp());
assertFalse(sExpression.stringp());
assertFalse(sExpression.symbolp());
}
public static void assertNil(SExpression sExpression) {
assertEquals(sExpression, Nil.getUniqueInstance());
assertTrue(sExpression.atomp());
assertFalse(sExpression.consp());
assertFalse(sExpression.functionp());
assertTrue(sExpression.listp());
assertTrue(sExpression.nullp());
assertFalse(sExpression.numberp());
assertFalse(sExpression.stringp());
assertTrue(sExpression.symbolp());
}
public static void assertNumber(SExpression sExpression) {
assertTrue(sExpression.atomp());
assertFalse(sExpression.consp());
assertFalse(sExpression.functionp());
assertFalse(sExpression.listp());
assertFalse(sExpression.nullp());
assertTrue(sExpression.numberp());
assertFalse(sExpression.stringp());
assertFalse(sExpression.symbolp());
}
public static void assertString(SExpression sExpression) {
assertTrue(sExpression.atomp());
assertFalse(sExpression.consp());
assertFalse(sExpression.functionp());
assertFalse(sExpression.listp());
assertFalse(sExpression.nullp());
assertFalse(sExpression.numberp());
assertTrue(sExpression.stringp());
assertFalse(sExpression.symbolp());
}
public static void assertSymbol(SExpression sExpression) {
assertTrue(sExpression.atomp());
assertFalse(sExpression.consp());
assertFalse(sExpression.functionp());
assertFalse(sExpression.listp());
assertFalse(sExpression.nullp());
assertFalse(sExpression.numberp());
assertFalse(sExpression.stringp());
assertTrue(sExpression.symbolp());
}
}

View File

@ -1,10 +1,13 @@
package sexpression;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import error.ErrorManager;
import sexpression.LispNumber.InvalidNumberException;
public class SExpressionTester {
private void assertSExpressionMatchesString(String expected, SExpression sExpression) {
@ -67,4 +70,72 @@ public class SExpressionTester {
assertSExpressionMatchesString(expected, list);
}
@Test
public void testConsWithNonListCdrToString() {
String expected = "(A . B)";
Cons list = new Cons(new Symbol("A"), new Symbol("B"));
assertSExpressionMatchesString(expected, list);
}
@Test
public void testCarOfNilIsNil() {
assertEquals(Nil.getUniqueInstance().getCar(), Nil.getUniqueInstance());
}
@Test
public void testCdrOfNilIsNil() {
assertEquals(Nil.getUniqueInstance().getCdr(), Nil.getUniqueInstance());
}
@Test
public void afterSettingCarOfNil_ShouldStillBeNil() {
Cons nil = Nil.getUniqueInstance();
nil.setCar(new LispNumber(2));
assertEquals(nil.getCar(), Nil.getUniqueInstance());
}
@Test
public void afterSettingCdrOfNil_ShouldStillBeNil() {
Cons nil = Nil.getUniqueInstance();
nil.setCdr(new LispNumber(2));
assertEquals(nil.getCdr(), Nil.getUniqueInstance());
}
@Test
public void testNumberValue() {
int value = 12;
LispNumber number = new LispNumber(String.valueOf(value));
assertEquals(number.getValue(), value);
}
@Test(expected = InvalidNumberException.class)
public void testInvalidNumberText_ThrowsException() {
new LispNumber("a");
}
@Test
public void testInvalidNumberException_HasCorrectSeverity() {
try {
new LispNumber("a");
} catch (InvalidNumberException e) {
assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL);
}
}
@Test
public void testInvalidNumberException_HasMessageText() {
try {
new LispNumber("a");
} catch (InvalidNumberException e) {
String message = e.getMessage();
assertNotNull(message);
assertTrue(message.length() > 0);
}
}
}

View File

@ -2,7 +2,7 @@ package testutil;
import java.io.*;
public class TestUtilities {
public final class TestUtilities {
public static InputStream createInputStreamFromString(String string) {
return new ByteArrayInputStream(string.getBytes());