Started refactoring the sexpression package and cleaned up some unit test code

This commit is contained in:
Mike Cifelli 2016-12-15 11:19:03 -05:00
parent c4e3740dfb
commit 7b7556cc65
29 changed files with 73 additions and 437 deletions

View File

@ -1,3 +0,0 @@
<body>
Provides a class for managing errors in the Lisp Interpreter.
</body>

View File

@ -67,7 +67,7 @@ public class DEFUN extends LispFunction {
// place the function in the function table // place the function in the function table
functionTable.put(name.toString(), functionTable.put(name.toString(),
new UDFunction(name.toString(), lambdaList, body)); new UserDefinedFunction(name.toString(), lambdaList, body));
return name; return name;
} }

View File

@ -47,7 +47,7 @@ public class LAMBDA extends LispFunction {
* @throws RuntimeException * @throws RuntimeException
* Indicates that <code>lexpr</code> is not a valid lambda expression. * Indicates that <code>lexpr</code> is not a valid lambda expression.
*/ */
public static UDFunction createFunction(Cons lexpr) { public static UserDefinedFunction createFunction(Cons lexpr) {
LAMBDA lambda = new LAMBDA(); LAMBDA lambda = new LAMBDA();
SExpression cdr = lexpr.getCdr(); SExpression cdr = lexpr.getCdr();
@ -92,7 +92,7 @@ public class LAMBDA extends LispFunction {
Cons lambdaList = (Cons) car; Cons lambdaList = (Cons) car;
Cons body = (Cons) argList.getCdr(); Cons body = (Cons) argList.getCdr();
Cons lexpr = new Cons(new Symbol("LAMBDA"), argList); Cons lexpr = new Cons(new Symbol("LAMBDA"), argList);
UDFunction function = new UDFunction(":LAMBDA", lambdaList, body); UserDefinedFunction function = new UserDefinedFunction(":LAMBDA", lambdaList, body);
return new LambdaExpression(lexpr, function); return new LambdaExpression(lexpr, function);
} }

View File

@ -16,7 +16,7 @@ import sexpression.SExpression;
public class LambdaExpression extends SExpression { public class LambdaExpression extends SExpression {
private Cons lexpr; private Cons lexpr;
private UDFunction function; private UserDefinedFunction function;
/** /**
* Create a new FUNCTION with the specified lambda expression and * Create a new FUNCTION with the specified lambda expression and
@ -27,7 +27,7 @@ public class LambdaExpression extends SExpression {
* @param function * @param function
* the internal representation of this FUNCTION * the internal representation of this FUNCTION
*/ */
public LambdaExpression(Cons lexpr, UDFunction function) { public LambdaExpression(Cons lexpr, UserDefinedFunction function) {
this.lexpr = lexpr; this.lexpr = lexpr;
this.function = function; this.function = function;
} }
@ -58,7 +58,7 @@ public class LambdaExpression extends SExpression {
* @return * @return
* the user-defined function of this FUNCTION * the user-defined function of this FUNCTION
*/ */
public UDFunction getFunction() { public UserDefinedFunction getFunction() {
return function; return function;
} }

View File

@ -44,10 +44,10 @@ public class SYMBOL_FUNCTION extends LispFunction {
// make sure the function actually exists // make sure the function actually exists
if (function != null) { if (function != null) {
if (function instanceof UDFunction) { if (function instanceof UserDefinedFunction) {
// this is a user-defined function // this is a user-defined function
UDFunction udFunction = (UDFunction) function; UserDefinedFunction udFunction = (UserDefinedFunction) function;
return udFunction.getLexpr(); return udFunction.getLexpr();
} }

View File

@ -1,23 +1,10 @@
/*
* Name: Mike Cifelli
* Course: CIS 443 - Programming Languages
* Assignment: Lisp Interpreter 2
*/
package eval; package eval;
import parser.*;
import sexpression.Cons;
import sexpression.SExpression;
import sexpression.Symbol;
import java.util.ArrayList; import java.util.ArrayList;
/** import sexpression.*;
* A <code>UDFunction</code> is an internal representation of a user-defined
* function in the Lisp programming language. public class UserDefinedFunction extends LispFunction {
*/
public class UDFunction extends LispFunction {
// the number of arguments that this user-defined function takes. // the number of arguments that this user-defined function takes.
private final int NUM_ARGS; private final int NUM_ARGS;
@ -40,7 +27,7 @@ public class UDFunction extends LispFunction {
* @param body * @param body
* the body of this user-defined function (MUST BE A PROPER LIST) * the body of this user-defined function (MUST BE A PROPER LIST)
*/ */
public UDFunction(String name, Cons lambdaList, Cons body) { public UserDefinedFunction(String name, Cons lambdaList, Cons body) {
this.name = name; this.name = name;
this.body = body; this.body = body;
this.lexpr = new Cons(new Symbol(name), new Cons(lambdaList, body)); this.lexpr = new Cons(new Symbol(name), new Cons(lambdaList, body));

View File

@ -1,4 +0,0 @@
<body>
Provides functions and forms to be used during the evaluation of an
S-expression.
</body>

View File

@ -1,7 +1,5 @@
package file; package file;
import java.util.Objects;
public class FilePosition { public class FilePosition {
private String fileName; private String fileName;
@ -11,29 +9,25 @@ public class FilePosition {
public FilePosition(String fileName) { public FilePosition(String fileName) {
this.fileName = fileName; this.fileName = fileName;
} }
public String getFileName() { public String getFileName() {
return fileName; return fileName;
} }
public int getLineNumber() { public int getLineNumber() {
return lineNumber; return lineNumber;
} }
public void setLineNumber(int lineNumber) { public void setLineNumber(int lineNumber) {
this.lineNumber = lineNumber; this.lineNumber = lineNumber;
} }
public int getColumnNumber() { public int getColumnNumber() {
return columnNumber; return columnNumber;
} }
public void setColumnNumber(int columnNumber) { public void setColumnNumber(int columnNumber) {
this.columnNumber = columnNumber; this.columnNumber = columnNumber;
} }
public boolean isEqual(FilePosition otherFilePosition) {
return Objects.equals(this.fileName, otherFilePosition.fileName) && (this.lineNumber == otherFilePosition.lineNumber)
&& (this.columnNumber == otherFilePosition.columnNumber);
}
} }

View File

@ -16,11 +16,10 @@ import java.io.*;
import java.text.MessageFormat; import java.text.MessageFormat;
/** /**
* <code>LispInterpreter</code> is an interpreter for the Lisp programming * This is an interpreter for the Lisp programming language. It takes the name of a file as a
* language. It takes the name of a file as a command-line argument, evaluates * command-line argument, evaluates the s-expressions found in the file and then prints the results
* the S-expressions found in the file and then prints the results to the * to the console. If no file name is provided at the command-line, this program will read from
* console. If no file name is provided at the command-line, this program will * standard input.
* read from standard input.
*/ */
public class LispInterpreter { public class LispInterpreter {
@ -31,15 +30,9 @@ public class LispInterpreter {
public static final String ANSI_GREEN = "\u001B[32m"; public static final String ANSI_GREEN = "\u001B[32m";
/** /**
* Evaluate the S-expressions found in the file given as a command-line * Evaluate the s-expressions found in the file given as a command-line argument and print the
* argument and print the results to the console. If no file name was given, * results to the console. If no file name was given, retrieve the s-expressions from standard
* retrieve the S-expressions from standard input. * input.
*
* @param args
* the command-line arguments:
* <ul>
* <li><code>args[0]</code> - file name (optional)</li>
* </ul>
*/ */
public static void main(String[] args) { public static void main(String[] args) {
LispParser parser = null; LispParser parser = null;
@ -94,7 +87,7 @@ public class LispInterpreter {
@Override @Override
public int getSeverity() { public int getSeverity() {
return 0; return 0;
} }
@Override @Override

View File

@ -1,3 +0,0 @@
<body>
Provides test drivers for the various stages of the Lisp Interpreter.
</body>

View File

@ -9,8 +9,7 @@ import token.Eof;
import token.Token; import token.Token;
/** /**
* Converts a stream of bytes into internal representations of Lisp * Converts a stream of bytes into internal representations of Lisp s-expressions.
* S-expressions.
*/ */
public class LispParser { public class LispParser {
@ -50,7 +49,7 @@ public class LispParser {
isNextTokenStored = false; isNextTokenStored = false;
return nextToken.sExpr(scanner::getNextToken); return nextToken.parseSExpression(scanner::getNextToken);
} }
private void throwDelayedExceptionIfNecessary() { private void throwDelayedExceptionIfNecessary() {

View File

@ -1,4 +0,0 @@
<body>
Provides the classes necessary for creating an internal representation of
the Lisp programming language.
</body>

View File

@ -1,3 +0,0 @@
<body>
Provides the classes necessary to perform a lexical analysis of the Lisp programming language.
</body>

View File

@ -1,44 +1,17 @@
/*
* Name: Mike Cifelli
* Course: CIS 443 - Programming Languages
* Assignment: Lisp Parser
*/
package sexpression; package sexpression;
/** public abstract class Atom extends SExpression {
* This class represents an ATOM in the PL-Lisp implementation.
*/
public class Atom extends SExpression {
private String text; private String text;
/**
* Create a new ATOM with the specified text.
*
* @param text
* the text representing this ATOM
*/
public Atom(String text) { public Atom(String text) {
this.text = text; this.text = text;
} }
/**
* Test if this S-expression is an ATOM.
*
* @return
* <code>true</code>
*/
public boolean atomp() { public boolean atomp() {
return true; return true;
} }
/**
* Returns a string representation of this ATOM.
*
* @return
* a string representation of this ATOM
*/
public String toString() { public String toString() {
return text; return text;
} }

View File

@ -1,88 +1,35 @@
/*
* Name: Mike Cifelli
* Course: CIS 443 - Programming Languages
* Assignment: Lisp Parser
*/
package sexpression; package sexpression;
/**
* This class represents a Lisp CONS cell in the PL-Lisp implementation.
*/
public class Cons extends SExpression { public class Cons extends SExpression {
private SExpression car; private SExpression car;
private SExpression cdr; private SExpression cdr;
/**
* Create a new CONS cell with the specified car and cdr.
*
* @param car
* the car of this CONS cell
* @param cdr
* the cdr of this CONS cell
*/
public Cons(SExpression car, SExpression cdr) { public Cons(SExpression car, SExpression cdr) {
this.car = car; this.car = car;
this.cdr = cdr; this.cdr = cdr;
} }
/**
* Retrieve the car of this CONS cell.
*
* @return
* the car of this CONS cell
*/
public SExpression getCar() { public SExpression getCar() {
return car; return car;
} }
/**
* Retrieve the cdr of this CONS cell.
*
* @return
* the cdr of this CONS cell
*/
public SExpression getCdr() { public SExpression getCdr() {
return cdr; return cdr;
} }
/**
* Set the car of this CONS cell to the specified value.
*
* @param newCar
* the value to assign to the car of this CONS cell
*/
public void setCar(SExpression newCar) { public void setCar(SExpression newCar) {
car = newCar; car = newCar;
} }
/**
* Set the cdr of this CONS cell to the specified value.
*
* @param newCdr
* the value to assign to the cdr of this CONS cell
*/
public void setCdr(SExpression newCdr) { public void setCdr(SExpression newCdr) {
cdr = newCdr; cdr = newCdr;
} }
/**
* Test if this S-expression is a CONS cell.
*
* @return
* <code>true</code>
*/
public boolean consp() { public boolean consp() {
return true; return true;
} }
/**
* Returns a string representation of this CONS cell.
*
* @return
* a string representation of this CONS cell
*/
public String toString() { public String toString() {
return ("(" + toStringAux()); return ("(" + toStringAux());
} }
@ -94,17 +41,12 @@ public class Cons extends SExpression {
// this method. When used in conjunction with the 'toString' method of this // this method. When used in conjunction with the 'toString' method of this
// class, this method provides a means for creating the correct string // class, this method provides a means for creating the correct string
// representation of a list. // representation of a list.
//
// Returns: a string representation of the car of a CONS cell followed by
// its cdr
private String toStringAux() { private String toStringAux() {
if (cdr.nullp()) { if (cdr.nullp())
return (car.toString() + ")"); return (car.toString() + ")");
} else if (cdr.consp()) { else if (cdr.consp())
return (car.toString() + " " + ((Cons) cdr).toStringAux()); return (car.toString() + " " + ((Cons) cdr).toStringAux());
}
// the cdr of this CONS cell is not a list
return (car.toString() + " . " + cdr.toString() + ")"); return (car.toString() + " . " + cdr.toString() + ")");
} }

View File

@ -1,65 +1,29 @@
/*
* Name: Mike Cifelli
* Course: CIS 443 - Programming Languages
* Assignment: Lisp Parser
*/
package sexpression; package sexpression;
/**
* This class represents a NUMBER in the PL-Lisp implementation.
*/
public class LispNumber extends Atom { public class LispNumber extends Atom {
private int value; private int value;
/**
* Create a new NUMBER with the specified text.
*
* @param text
* the text representing this NUMBER
* @throws IllegalArgumentException
* Indicates that <code>text</code> does not represent a valid integer.
*/
public LispNumber(String text) { public LispNumber(String text) {
super(text.replaceFirst("^0+(?!$)", "")); super(text.replaceFirst("^0+(?!$)", ""));
try { try {
this.value = Integer.parseInt(text); this.value = Integer.parseInt(text);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new IllegalArgumentException(text + throw new IllegalArgumentException(text + " is not a valid integer");
" is not a valid integer");
} }
} }
/**
* Create a new NUMBER with the specified value.
*
* @param value
* the integer value of this NUMBER
*/
public LispNumber(int value) { public LispNumber(int value) {
super(Integer.toString(value)); super(Integer.toString(value));
this.value = value; this.value = value;
} }
/**
* Test if this S-expression is a NUMBER.
*
* @return
* <code>true</code>
*/
public boolean numberp() { public boolean numberp() {
return true; return true;
} }
/**
* Retrieve the integer value of this NUMBER.
*
* @return
* the integer value of this NUMBER
*/
public int getValue() { public int getValue() {
return value; return value;
} }

View File

@ -1,32 +1,11 @@
/*
* Name: Mike Cifelli
* Course: CIS 443 - Programming Languages
* Assignment: Lisp Parser
*/
package sexpression; package sexpression;
/**
* This class represents a STRING in the PL-Lisp implementation.
*/
public class LispString extends Atom { public class LispString extends Atom {
/**
* Create a new STRING with the specified text.
*
* @param text
* the text representing this STRING
*/
public LispString(String text) { public LispString(String text) {
super(text); super(text);
} }
/**
* Test if this S-expression is a STRING.
*
* @return
* <code>true</code>
*/
public boolean stringp() { public boolean stringp() {
return true; return true;
} }

View File

@ -1,102 +1,48 @@
/*
* Name: Mike Cifelli
* Course: CIS 443 - Programming Languages
* Assignment: Lisp Parser
*/
package sexpression; package sexpression;
/**
* This class represents NIL in the PL-Lisp implementation.
*/
public class Nil extends Cons { public class Nil extends Cons {
private static Nil uniqueInstance = new Nil(); private static Nil uniqueInstance = new Nil();
/**
* Retrieve the single unique instance of NIL.
*
* @return
* the single unique instance of NIL
*/
public static Nil getUniqueInstance() { public static Nil getUniqueInstance() {
return uniqueInstance; return uniqueInstance;
} }
// We are using the Singleton pattern, so the constructor for 'Nil' is
// private.
private Nil() { private Nil() {
super(null, null); super(null, null);
// the car and cdr of NIL both refer to NIL
super.setCar(this); super.setCar(this);
super.setCdr(this); super.setCdr(this);
} }
/**
* Test if this S-expression is NULL.
*
* @return
* <code>true</code>
*/
public boolean nullp() { public boolean nullp() {
return true; return true;
} }
/**
* Test if this S-expression is an ATOM.
*
* @return
* <code>true</code>
*/
public boolean atomp() { public boolean atomp() {
return true; return true;
} }
/**
* Test if this S-expression is a CONS cell.
*
* @return
* <code>false</code>
*/
public boolean consp() { public boolean consp() {
return false; return false;
} }
/**
* Test if this S-expression is a SYMBOL.
*
* @return
* <code>true</code>
*/
public boolean symbolp() { public boolean symbolp() {
return true; return true;
} }
/** /**
* Set the car of this CONS cell to the specified value. This method does * Set the car of this CONS cell to the specified value. This method does nothing (the car of
* nothing (the car of NIL can not be changed). * NIL can not be changed).
*
* @param newCar
* the value to assign to the car of this CONS cell
*/ */
public void setCar(SExpression newCar) {} public void setCar(SExpression newCar) {}
/** /**
* Set the cdr of this CONS cell to the specified value. This method does * Set the cdr of this CONS cell to the specified value. This method does nothing (the cdr of
* nothing (the cdr of NIL can not be changed). * NIL can not be changed).
*
* @param newCdr
* the value to assign to the cdr of this CONS cell
*/ */
public void setCdr(SExpression newCdr) {} public void setCdr(SExpression newCdr) {}
/**
* Returns a string representation of NIL.
*
* @return
* a string representation of NIL
*/
public String toString() { public String toString() {
return "NIL"; return "NIL";
} }

View File

@ -1,120 +1,49 @@
/*
* Name: Mike Cifelli
* Course: CIS 443 - Programming Languages
* Assignment: Lisp Parser
*/
package sexpression; package sexpression;
/** public abstract class SExpression {
* This is the base class for memory in the PL-Lisp implementation.
*/
public class SExpression {
// for mark and sweep garbage collection // for mark and sweep garbage collection
private boolean marked = false; private boolean marked = false;
/**
* Determine if this <code>SExpression</code> is marked.
*
* @return
* <code>true</code> if this <code>SExpression</code> is marked;
* <code>false</code> otherwise
*/
public final boolean isMarked() { public final boolean isMarked() {
return marked; return marked;
} }
/**
* Set the marked status of this S-expression to the specified value.
*
* @param value
* the value to assign to this S-expression's marked status
*/
public final void setMarked(final boolean value) { public final void setMarked(final boolean value) {
marked = value; marked = value;
} }
// Lisp type predicates; // Lisp type predicates...
// by default, all return false (an SExpression effectively has NO type);
// overridden in subclasses to describe their Lisp type // overridden in subclasses to describe their Lisp type
/**
* Test if this S-expression is NULL.
*
* @return
* <code>false</code>
*/
public boolean nullp() { public boolean nullp() {
return false; return false;
} }
/**
* Test if this S-expression is an ATOM.
*
* @return
* <code>false</code>
*/
public boolean atomp() { public boolean atomp() {
return false; return false;
} }
/**
* Test if this S-expression is a CONS cell.
*
* @return
* <code>false</code>
*/
public boolean consp() { public boolean consp() {
return false; return false;
} }
/**
* Test if this S-expression is a LIST.
*
* @return
* the value of <code>(consp() || nullp())</code>
*/
public boolean listp() { public boolean listp() {
return (consp() || nullp()); return (consp() || nullp());
} }
/**
* Test if this S-expression is a NUMBER.
*
* @return
* <code>false</code>
*/
public boolean numberp() { public boolean numberp() {
return false; return false;
} }
/**
* Test if this S-expression is a SYMBOL.
*
* @return
* <code>false</code>
*/
public boolean symbolp() { public boolean symbolp() {
return false; return false;
} }
/**
* Test if this S-expression is a FUNCTION.
*
* @return
* <code>false</code>
*/
public boolean functionp() { public boolean functionp() {
return false; return false;
} }
/**
* Test if this S-expression is a STRING.
*
* @return
* <code>false</code>
*/
public boolean stringp() { public boolean stringp() {
return false; return false;
} }

View File

@ -1,35 +1,17 @@
/*
* Name: Mike Cifelli
* Course: CIS 443 - Programming Languages
* Assignment: Lisp Parser
*/
package sexpression; package sexpression;
/**
* This class represents a SYMBOL in the PL-Lisp implementation.
*/
public class Symbol extends Atom { public class Symbol extends Atom {
/** This SYMBOL represents TRUE in the PL-Lisp implementation. */
public static final Symbol T = new Symbol("T"); public static final Symbol T = new Symbol("T");
public static Symbol createQuote() {
return new Symbol("QUOTE");
}
/**
* Create a new SYMBOL with the specified text.
*
* @param text
* the text representing this SYMBOL
*/
public Symbol(String text) { public Symbol(String text) {
super(text.toUpperCase()); super(text.toUpperCase());
} }
/**
* Test if this S-expression is a SYMBOL.
*
* @return
* <code>true</code>
*/
public boolean symbolp() { public boolean symbolp() {
return true; return true;
} }

View File

@ -13,7 +13,7 @@ public class Eof extends Token {
} }
@Override @Override
public SExpression sExpr(Supplier<Token> getNextToken) { public SExpression parseSExpression(Supplier<Token> getNextToken) {
throw new EofEncounteredException(this); throw new EofEncounteredException(this);
} }

View File

@ -13,7 +13,7 @@ public class Identifier extends Token {
} }
@Override @Override
public SExpression sExpr(Supplier<Token> getNextToken) { public SExpression parseSExpression(Supplier<Token> getNextToken) {
return new Symbol(getText()); return new Symbol(getText());
} }

View File

@ -12,10 +12,10 @@ public class LeftParenthesis extends Token {
} }
@Override @Override
public SExpression sExpr(Supplier<Token> getNextToken) { public SExpression parseSExpression(Supplier<Token> getNextToken) {
Token nextToken = getNextToken.get(); Token nextToken = getNextToken.get();
return nextToken.sExprTail(getNextToken); return nextToken.parseSExpressionTail(getNextToken);
} }
} }

View File

@ -13,7 +13,7 @@ public class Number extends Token {
} }
@Override @Override
public SExpression sExpr(Supplier<Token> getNextToken) { public SExpression parseSExpression(Supplier<Token> getNextToken) {
return new LispNumber(getText()); return new LispNumber(getText());
} }

View File

@ -12,11 +12,11 @@ public class QuoteMark extends Token {
} }
@Override @Override
public SExpression sExpr(Supplier<Token> getNextToken) { public SExpression parseSExpression(Supplier<Token> getNextToken) {
Token nextToken = getNextToken.get(); Token nextToken = getNextToken.get();
SExpression argument = nextToken.sExpr(getNextToken); SExpression argument = nextToken.parseSExpression(getNextToken);
return new Cons(new Symbol("QUOTE"), new Cons(argument, Nil.getUniqueInstance())); return new Cons(Symbol.createQuote(), new Cons(argument, Nil.getUniqueInstance()));
} }
} }

View File

@ -13,7 +13,7 @@ public class QuotedString extends Token {
} }
@Override @Override
public SExpression sExpr(Supplier<Token> getNextToken) { public SExpression parseSExpression(Supplier<Token> getNextToken) {
return new LispString(getText()); return new LispString(getText());
} }

View File

@ -14,12 +14,12 @@ public class RightParenthesis extends Token {
} }
@Override @Override
public SExpression sExpr(Supplier<Token> getNextToken) { public SExpression parseSExpression(Supplier<Token> getNextToken) {
throw new StartsWithRightParenthesisException(this); throw new StartsWithRightParenthesisException(this);
} }
@Override @Override
public SExpression sExprTail(Supplier<Token> getNextToken) { public SExpression parseSExpressionTail(Supplier<Token> getNextToken) {
return Nil.getUniqueInstance(); return Nil.getUniqueInstance();
} }

View File

@ -35,16 +35,15 @@ public abstract class Token {
return position.getColumnNumber(); return position.getColumnNumber();
} }
// sExpr ::= NUMBER | IDENTIFIER | STRING | QUOTE_MARK sExpr | // sExpr ::= NUMBER | IDENTIFIER | STRING | QUOTE_MARK sExpr | LEFT_PAREN sExprTail
// LEFT_PAREN sExprTail public abstract SExpression parseSExpression(Supplier<Token> getNextToken);
public abstract SExpression sExpr(Supplier<Token> getNextToken);
// sExprTail ::= RIGHT_PAREN | sExpr sExprTail // sExprTail ::= RIGHT_PAREN | sExpr sExprTail
public SExpression sExprTail(Supplier<Token> getNextToken) { public SExpression parseSExpressionTail(Supplier<Token> getNextToken) {
SExpression car = sExpr(getNextToken); SExpression car = parseSExpression(getNextToken);
Token nextToken = getNextToken.get(); Token nextToken = getNextToken.get();
SExpression cdr = nextToken.sExprTail(getNextToken); SExpression cdr = nextToken.parseSExpressionTail(getNextToken);
return new Cons(car, cdr); return new Cons(car, cdr);
} }

View File

@ -1,8 +1,9 @@
package file; package file;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.util.Objects;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -20,81 +21,46 @@ public class FilePositionTrackerTester {
return position; 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 @Before
public void setUp() throws Exception { public void setUp() throws Exception {
trackerUnderTest = new FilePositionTracker(FILE_NAME); trackerUnderTest = new FilePositionTracker(FILE_NAME);
} }
@Test
public void filePositionEquality_CorrectlyReturnsTrue() {
FilePosition positionOne = createFilePosition(5, 9);
FilePosition positionTwo = createFilePosition(5, 9);
assertTrue(positionOne.isEqual(positionTwo));
}
@Test
public void filePositionEquality_CorrectlyReturnsFalseWithDifferentLine() {
FilePosition positionOne = createFilePosition(5, 9);
FilePosition positionTwo = createFilePosition(8, 9);
assertFalse(positionOne.isEqual(positionTwo));
}
@Test
public void filePositionEquality_CorrectlyReturnsFalseWithDifferentColumn() {
FilePosition positionOne = createFilePosition(5, 9);
FilePosition positionTwo = createFilePosition(5, 10);
assertFalse(positionOne.isEqual(positionTwo));
}
@Test
public void filePositionEquality_CorrectlyReturnsFalseWithDifferentFileName() {
FilePosition positionOne = new FilePosition("FileOne");
positionOne.setLineNumber(5);
positionOne.setColumnNumber(9);
FilePosition positionTwo = new FilePosition("FileTwo");
positionTwo.setLineNumber(5);
positionTwo.setColumnNumber(9);
assertFalse(positionOne.isEqual(positionTwo));
}
@Test @Test
public void noMovement_ReturnsInitialPosition() { public void noMovement_ReturnsInitialPosition() {
FilePosition expectedPosition = createFilePosition(1, 0); assertTrackerPositionEquals(createFilePosition(1, 0));
assertTrue(expectedPosition.isEqual(trackerUnderTest.getCurrentPosition()));
} }
@Test @Test
public void advanceOneColumn_ReturnsCorrectPosition() { public void advanceOneColumn_ReturnsCorrectPosition() {
FilePosition expectedPosition = createFilePosition(1, 1);
trackerUnderTest.incrementColumn(); trackerUnderTest.incrementColumn();
assertTrue(expectedPosition.isEqual(trackerUnderTest.getCurrentPosition())); assertTrackerPositionEquals(createFilePosition(1, 1));
} }
@Test @Test
public void advanceOneLine_ReturnsCorrectPosition() { public void advanceOneLine_ReturnsCorrectPosition() {
FilePosition expectedPosition = createFilePosition(2, 0);
trackerUnderTest.incrementLine(); trackerUnderTest.incrementLine();
assertTrue(expectedPosition.isEqual(trackerUnderTest.getCurrentPosition())); assertTrackerPositionEquals(createFilePosition(2, 0));
} }
@Test @Test
public void advanceOneLine_ResetsColumn() { public void advanceOneLine_ResetsColumn() {
FilePosition expectedPosition = createFilePosition(2, 0);
trackerUnderTest.incrementColumn(); trackerUnderTest.incrementColumn();
trackerUnderTest.incrementLine(); trackerUnderTest.incrementLine();
assertTrue(expectedPosition.isEqual(trackerUnderTest.getCurrentPosition())); assertTrackerPositionEquals(createFilePosition(2, 0));
} }
} }