2017-02-25 19:11:31 -05:00
|
|
|
package function.builtin.special;
|
|
|
|
|
|
|
|
import static org.junit.Assert.assertTrue;
|
|
|
|
import static testutil.TestUtilities.*;
|
|
|
|
|
|
|
|
import java.io.*;
|
|
|
|
|
2017-07-19 15:23:15 -04:00
|
|
|
import org.junit.Test;
|
2017-02-25 19:11:31 -05:00
|
|
|
|
|
|
|
import environment.RuntimeEnvironment;
|
|
|
|
import error.ErrorManager;
|
|
|
|
import function.ArgumentValidator.*;
|
2017-03-01 11:11:59 -05:00
|
|
|
import function.UserDefinedFunction.IllegalKeywordRestPositionException;
|
2017-07-19 15:23:15 -04:00
|
|
|
import testutil.SymbolAndFunctionCleaner;
|
2017-02-25 19:11:31 -05:00
|
|
|
|
2017-07-19 15:23:15 -04:00
|
|
|
public class DEFINE_SPECIALTest extends SymbolAndFunctionCleaner {
|
2017-02-25 19:11:31 -05:00
|
|
|
|
|
|
|
private ByteArrayOutputStream outputStream;
|
|
|
|
private RuntimeEnvironment environment;
|
|
|
|
|
2017-03-15 13:37:39 -04:00
|
|
|
public DEFINE_SPECIALTest() {
|
2017-02-25 19:11:31 -05:00
|
|
|
this.environment = RuntimeEnvironment.getInstance();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void assertSomethingPrinted() {
|
|
|
|
assertTrue(outputStream.toByteArray().length > 0);
|
|
|
|
}
|
|
|
|
|
2017-07-19 15:23:15 -04:00
|
|
|
@Override
|
|
|
|
public void additionalSetUp() {
|
2017-02-25 19:11:31 -05:00
|
|
|
outputStream = new ByteArrayOutputStream();
|
|
|
|
|
2017-03-05 10:20:31 -05:00
|
|
|
environment.reset();
|
2017-02-25 19:11:31 -05:00
|
|
|
environment.setOutput(new PrintStream(outputStream));
|
|
|
|
environment.setErrorManager(new ErrorManager());
|
|
|
|
environment.setWarningOutputDecorator(s -> s);
|
|
|
|
}
|
|
|
|
|
2017-07-19 15:23:15 -04:00
|
|
|
@Override
|
|
|
|
public void additionalTearDown() {
|
2017-03-05 10:20:31 -05:00
|
|
|
environment.reset();
|
2017-02-25 19:11:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecial() {
|
|
|
|
String input = "(define-special f () t)";
|
2017-02-25 19:11:31 -05:00
|
|
|
|
|
|
|
assertSExpressionsMatch(parseString("f"), evaluateString(input));
|
|
|
|
assertSExpressionsMatch(parseString("t"), evaluateString("(f)"));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialWithEmptyBody() {
|
|
|
|
String input = "(define-special f ())";
|
2017-02-25 19:11:31 -05:00
|
|
|
|
|
|
|
assertSExpressionsMatch(parseString("f"), evaluateString(input));
|
|
|
|
assertSExpressionsMatch(parseString("()"), evaluateString("(f)"));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
2017-03-10 15:08:42 -05:00
|
|
|
public void defineSpecialDoesNotEvaluateArguments() {
|
2017-03-07 13:15:40 -05:00
|
|
|
evaluateString("(define-special f (x) (car x))");
|
2017-02-25 19:11:31 -05:00
|
|
|
assertSExpressionsMatch(parseString("quote"), evaluateString("(f '(1 2 3))"));
|
|
|
|
}
|
2017-02-25 19:12:34 -05:00
|
|
|
|
2017-02-25 19:11:31 -05:00
|
|
|
@Test
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialAdd() {
|
|
|
|
evaluateString("(define-special f (x) (+ (eval x) 23))");
|
2017-02-25 19:11:31 -05:00
|
|
|
assertSExpressionsMatch(parseString("27"), evaluateString("(f (+ 2 2))"));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialSetVariable() {
|
|
|
|
evaluateString("(define-special f (x) (set x 23))");
|
2017-02-25 19:11:31 -05:00
|
|
|
evaluateString("(f y)");
|
|
|
|
assertSExpressionsMatch(parseString("23"), evaluateString("y"));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialVariableCapture() {
|
2017-03-07 16:41:26 -05:00
|
|
|
evaluateString("(setq x 0)");
|
2017-03-07 13:15:40 -05:00
|
|
|
evaluateString("(define-special f (x) (set x 23))");
|
2017-02-25 19:11:31 -05:00
|
|
|
evaluateString("(f x)");
|
|
|
|
assertSExpressionsMatch(parseString("0"), evaluateString("x"));
|
|
|
|
}
|
2017-02-25 19:12:34 -05:00
|
|
|
|
2017-02-25 19:11:31 -05:00
|
|
|
@Test
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialAvoidVariableCaptureConvention() {
|
2017-03-07 16:41:26 -05:00
|
|
|
evaluateString("(setq x 0)");
|
2017-03-07 13:15:40 -05:00
|
|
|
evaluateString("(define-special f (-x-) (set -x- 23))");
|
2017-02-25 19:11:31 -05:00
|
|
|
evaluateString("(f x)");
|
|
|
|
assertSExpressionsMatch(parseString("23"), evaluateString("x"));
|
|
|
|
}
|
2017-02-25 19:12:34 -05:00
|
|
|
|
2017-02-25 19:11:31 -05:00
|
|
|
@Test
|
2017-03-07 13:15:40 -05:00
|
|
|
public void redefineSpecial_DisplaysWarning() {
|
|
|
|
String input = "(define-special myFunction () nil)";
|
2017-02-25 19:11:31 -05:00
|
|
|
evaluateString(input);
|
|
|
|
evaluateString(input);
|
|
|
|
|
|
|
|
assertSomethingPrinted();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
2017-03-07 13:15:40 -05:00
|
|
|
public void redefineSpecial_ActuallyRedefinesSpecialFunction() {
|
|
|
|
evaluateString("(define-special mySpecialFunction () nil)");
|
|
|
|
evaluateString("(define-special mySpecialFunction () T)");
|
2017-02-25 19:11:31 -05:00
|
|
|
|
|
|
|
assertSomethingPrinted();
|
2017-03-07 13:15:40 -05:00
|
|
|
assertSExpressionsMatch(parseString("t"), evaluateString("(mySpecialFunction)"));
|
2017-02-25 19:11:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = DottedArgumentListException.class)
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialWithDottedLambdaList() {
|
|
|
|
evaluateString("(funcall 'define-special 'x (cons 'a 'b) ())");
|
2017-02-25 19:11:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = BadArgumentTypeException.class)
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialWithNonSymbolName() {
|
|
|
|
evaluateString("(define-special 1 () ())");
|
2017-02-25 19:11:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = BadArgumentTypeException.class)
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialWithBadLambdaList() {
|
|
|
|
evaluateString("(define-special x a ())");
|
2017-02-25 19:11:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = TooFewArgumentsException.class)
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialWithTooFewArguments() {
|
|
|
|
evaluateString("(define-special x)");
|
2017-02-25 19:11:31 -05:00
|
|
|
}
|
|
|
|
|
2017-03-01 11:11:59 -05:00
|
|
|
@Test(expected = TooFewArgumentsException.class)
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialAndCallWithTooFewArguments() {
|
|
|
|
evaluateString("(define-special x (a b))");
|
2017-03-01 11:11:59 -05:00
|
|
|
evaluateString("(x a)");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = TooManyArgumentsException.class)
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialAndCallWithTooManyArguments() {
|
|
|
|
evaluateString("(define-special x (a b))");
|
2017-03-01 11:11:59 -05:00
|
|
|
evaluateString("(x a b c)");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialWithKeywordRestParameter() {
|
|
|
|
evaluateString("(define-special f (&rest x) (car x))");
|
2017-03-01 11:11:59 -05:00
|
|
|
assertSExpressionsMatch(parseString("1"), evaluateString("(f 1 2 3 4 5)"));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialWithNormalAndKeywordRestParameter() {
|
|
|
|
evaluateString("(define-special f (a &rest b) (cons a b))");
|
2017-03-01 11:11:59 -05:00
|
|
|
assertSExpressionsMatch(parseString("(1 2 3 4 5)"), evaluateString("(f 1 2 3 4 5)"));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = IllegalKeywordRestPositionException.class)
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialWithParametersFollowingKeywordRest() {
|
|
|
|
evaluateString("(define-special f (a &rest b c) (cons a b))");
|
2017-03-01 11:11:59 -05:00
|
|
|
evaluateString("(f 1 2 3)");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialWithKeywordRest_CallWithNoArguments() {
|
|
|
|
evaluateString("(define-special f (&rest a) (car a))");
|
2017-03-01 11:11:59 -05:00
|
|
|
assertSExpressionsMatch(parseString("nil"), evaluateString("(f)"));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = TooFewArgumentsException.class)
|
2017-03-07 13:15:40 -05:00
|
|
|
public void defineSpecialWithNormalAndKeywordRest_CallWithNoArguments() {
|
|
|
|
evaluateString("(define-special f (a &rest b) a)");
|
2017-03-01 11:11:59 -05:00
|
|
|
evaluateString("(f)");
|
|
|
|
}
|
|
|
|
|
2017-03-10 15:08:42 -05:00
|
|
|
@Test
|
|
|
|
public void resultOfSpecialFunctionIsNotEvaluated() {
|
|
|
|
evaluateString("(setq x 'grains)");
|
|
|
|
evaluateString("(define-special f (x) x)");
|
|
|
|
evaluateString("(f (setq x 'sprouts))");
|
|
|
|
|
|
|
|
assertSExpressionsMatch(parseString("grains"), evaluateString("x"));
|
|
|
|
}
|
|
|
|
|
2017-02-25 19:11:31 -05:00
|
|
|
}
|