package function.builtin;

import static org.junit.Assert.*;
import static testutil.TestUtilities.*;

import org.junit.Test;

import function.ArgumentValidator.*;
import function.builtin.EVAL.*;
import sexpression.Nil;

public class EVALTester {

    @Test
    public void testEval() {
        String input = "(eval 9)";

        assertSExpressionsMatch(parseString("9"), evaluateString(input));
    }

    @Test
    public void testEvalNil() {
        String input = "(eval ())";

        assertSExpressionsMatch(parseString("()"), evaluateString(input));
    }

    @Test
    public void testLookupSymbol() {
        String symbol = ":symbol";
        assertSExpressionsMatch(parseString(symbol), EVAL.lookupSymbol(symbol));
    }

    @Test
    public void testLookupT() {
        String symbol = "T";
        assertSExpressionsMatch(parseString(symbol), EVAL.lookupSymbol(symbol));
    }

    @Test
    public void testLookupNil() {
        String symbol = "NIL";
        assertSExpressionsMatch(parseString(symbol), EVAL.lookupSymbol(symbol));
    }

    @Test
    public void testLookupUndefinedSymbol() {
        assertNull(EVAL.lookupSymbol("undefined"));
    }

    @Test(expected = UndefinedFunctionException.class)
    public void testEvalUndefinedFunction() {
        String input = "(funcall 'eval '(undefined))";

        evaluateString(input);
    }

    @Test(expected = UndefinedSymbolException.class)
    public void testEvalUndefinedSymbol() {
        String input = "(eval undefined)";

        evaluateString(input);
    }

    @Test(expected = DottedArgumentListException.class)
    public void testEvalWithDottedLambdaList() {
        String input = "(funcall 'eval (cons '+ 1))";

        evaluateString(input);
    }

    @Test(expected = TooManyArgumentsException.class)
    public void testEvalWithTooManyArguments() {
        evaluateString("(eval '1 '2 '3)");
    }

    @Test(expected = TooFewArgumentsException.class)
    public void testEvalWithTooFewArguments() {
        evaluateString("(eval)");
    }

    @Test
    public void undefinedFunctionException_HasMessageText() {
        UndefinedFunctionException e = new UndefinedFunctionException(Nil.getInstance());

        assertNotNull(e.getMessage());
        assertTrue(e.getMessage().length() > 0);
    }

    @Test
    public void undefinedSymbolException_HasMessageText() {
        UndefinedSymbolException e = new UndefinedSymbolException(Nil.getInstance());

        assertNotNull(e.getMessage());
        assertTrue(e.getMessage().length() > 0);
    }

}
