transcendental-lisp/test/function/builtin/special/DEFUNTest.java

181 lines
5.7 KiB
Java
Raw Normal View History

package function.builtin.special;
2017-02-11 10:42:07 -05:00
import static org.junit.Assert.assertTrue;
2017-03-03 15:06:49 -05:00
import static table.FunctionTable.resetFunctionTable;
import static testutil.TestUtilities.*;
2017-01-27 12:12:27 -05:00
import java.io.*;
2017-01-27 12:12:27 -05:00
import org.junit.*;
import environment.RuntimeEnvironment;
2017-02-11 10:42:07 -05:00
import error.ErrorManager;
import function.ArgumentValidator.*;
import function.UserDefinedFunction.IllegalKeywordRestPositionException;
2017-03-15 13:37:39 -04:00
public class DEFUNTest {
2017-01-27 12:12:27 -05:00
private ByteArrayOutputStream outputStream;
2017-02-11 10:51:37 -05:00
private RuntimeEnvironment environment;
2017-03-15 13:37:39 -04:00
public DEFUNTest() {
2017-02-11 10:51:37 -05:00
this.environment = RuntimeEnvironment.getInstance();
}
2017-01-27 12:12:27 -05:00
2017-02-11 10:42:07 -05:00
private void assertSomethingPrinted() {
assertTrue(outputStream.toByteArray().length > 0);
2017-01-27 12:12:27 -05:00
}
@Before
public void setUp() {
2017-02-11 10:51:37 -05:00
outputStream = new ByteArrayOutputStream();
environment.reset();
2017-02-11 10:51:37 -05:00
environment.setOutput(new PrintStream(outputStream));
environment.setErrorManager(new ErrorManager());
2017-02-11 13:33:34 -05:00
environment.setWarningOutputDecorator(s -> s);
2017-03-03 15:06:49 -05:00
resetFunctionTable();
}
@After
public void tearDown() {
environment.reset();
2017-03-03 15:06:49 -05:00
resetFunctionTable();
2017-01-27 12:12:27 -05:00
}
@Test
public void defun() {
String input = "(defun f () t)";
assertSExpressionsMatch(parseString("f"), evaluateString(input));
assertSExpressionsMatch(parseString("t"), evaluateString("(f)"));
}
@Test
public void defunWithEmptyBody() {
String input = "(defun f ())";
assertSExpressionsMatch(parseString("f"), evaluateString(input));
assertSExpressionsMatch(parseString("()"), evaluateString("(f)"));
}
@Test
public void defunEvaluatesArguments() {
evaluateString("(defun f (x) (car x))");
assertSExpressionsMatch(parseString("1"), evaluateString("(f '(1 2 3))"));
}
@Test
public void defunRecursiveFunction() {
evaluateString("(defun fact (x) (if (< x 2) 1 (* x (fact (- x 1)))))");
assertSExpressionsMatch(parseString("120"), evaluateString("(fact 5)"));
}
@Test
public void defunTailRecursiveFunction() {
evaluateString("(defun fact-tail (x acc) (if (< x 2) acc (fact-tail (- x 1) (* x acc))))");
assertSExpressionsMatch(parseString("120"), evaluateString("(fact-tail 5 1)"));
}
@Test
public void defunSimpleClass() {
2017-03-07 16:41:26 -05:00
evaluateString("(defun counter-class () (let ((counter 0)) (lambda () (setq counter (+ 1 counter)))))");
evaluateString("(setq my-counter (counter-class))");
assertSExpressionsMatch(parseString("1"), evaluateString("(funcall my-counter)"));
assertSExpressionsMatch(parseString("2"), evaluateString("(funcall my-counter)"));
assertSExpressionsMatch(parseString("3"), evaluateString("(funcall my-counter)"));
assertSExpressionsMatch(parseString("4"), evaluateString("(funcall my-counter)"));
}
2017-01-27 12:12:27 -05:00
@Test
public void redefineFunction_DisplaysWarning() {
String input = "(defun myFunction () nil)";
evaluateString(input);
evaluateString(input);
2017-02-11 10:42:07 -05:00
assertSomethingPrinted();
2017-01-27 12:12:27 -05:00
}
@Test
public void redefineFunction_ActuallyRedefinesFunction() {
evaluateString("(defun myFunction () nil)");
evaluateString("(defun myFunction () T)");
2017-01-27 12:12:27 -05:00
2017-02-11 10:42:07 -05:00
assertSomethingPrinted();
assertSExpressionsMatch(parseString("t"), evaluateString("(myFunction)"));
2017-01-27 12:12:27 -05:00
}
@Test(expected = DottedArgumentListException.class)
public void defunWithDottedLambdaList() {
evaluateString("(funcall 'defun 'f (cons 'a 'b) ())");
}
@Test(expected = BadArgumentTypeException.class)
public void defunWithNonSymbolName() {
evaluateString("(defun 1 () ())");
}
@Test(expected = BadArgumentTypeException.class)
public void defunWithBadLambdaList() {
evaluateString("(defun f a ())");
}
@Test(expected = TooFewArgumentsException.class)
public void defunWithTooFewArguments() {
evaluateString("(defun f)");
}
@Test(expected = TooFewArgumentsException.class)
public void defunFunctionAndCallWithTooFewArguments() {
evaluateString("(defun f (a b))");
evaluateString("(f 'a)");
}
@Test(expected = TooManyArgumentsException.class)
public void defunFunctionAndCallWithTooManyArguments() {
evaluateString("(defun f (a b))");
evaluateString("(f 'a 'b 'c)");
}
@Test
public void defunWithKeywordRestParameter() {
evaluateString("(defun f (&rest x) (car x))");
assertSExpressionsMatch(parseString("1"), evaluateString("(f 1 2 3 4 5)"));
}
@Test
public void defunWithNormalAndKeywordRestParameter() {
evaluateString("(defun f (a &rest b) (cons a b))");
assertSExpressionsMatch(parseString("(1 2 3 4 5)"), evaluateString("(f 1 2 3 4 5)"));
}
@Test(expected = IllegalKeywordRestPositionException.class)
public void defunWithParametersFollowingKeywordRest() {
evaluateString("(defun f (a &rest b c) (cons a b))");
evaluateString("(f 1 2 3)");
}
@Test
public void defunWithKeywordRest_CallWithNoArguments() {
evaluateString("(defun f (&rest a) (car a))");
assertSExpressionsMatch(parseString("nil"), evaluateString("(f)"));
}
@Test(expected = TooFewArgumentsException.class)
public void defunWithNormalAndKeywordRest_CallWithNoArguments() {
evaluateString("(defun f (a &rest b) a)");
evaluateString("(f)");
}
@Test
public void resultOfFunctionIsNotEvaluated() {
evaluateString("(setq x 'grains)");
evaluateString("(define-special f (x) 'x)");
evaluateString("(f (setq x 'sprouts))");
assertSExpressionsMatch(parseString("grains"), evaluateString("x"));
}
}