package function.builtin;

import static error.ErrorManager.Severity.ERROR;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static sexpression.Nil.NIL;
import static testutil.TestUtilities.evaluateString;

import org.junit.Test;

import function.ArgumentValidator.BadArgumentTypeException;
import function.ArgumentValidator.TooFewArgumentsException;
import function.ArgumentValidator.TooManyArgumentsException;
import function.builtin.SYMBOL_FUNCTION.UndefinedSymbolFunctionException;
import testutil.SymbolAndFunctionCleaner;

public class SYMBOL_FUNCTIONTest extends SymbolAndFunctionCleaner {

    @Test
    public void symbolFunction_BuiltInFunction() {
        String input = "(symbol-function '+)";

        assertEquals("#<FUNCTION +>", evaluateString(input).toString());
    }

    @Test
    public void symbolFunction_BuiltInSpecialFunction() {
        String input = "(symbol-function 'if)";

        assertEquals("#<SPECIAL-FUNCTION IF>", evaluateString(input).toString());
    }

    @Test
    public void symbolFunction_UserDefinedFunction() {
        String defineUserFunction = "(defun y (n m) (+ n m))";
        String input = "(symbol-function 'y)";

        evaluateString(defineUserFunction);
        assertEquals("(Y (N M) (+ N M))", evaluateString(input).toString());
    }

    @Test(expected = UndefinedSymbolFunctionException.class)
    public void symbolFunction_NonFunction() {
        String input = "(symbol-function 'a)";

        evaluateString(input);
    }

    @Test(expected = BadArgumentTypeException.class)
    public void symbolFunctionWithBadArgumentType() {
        evaluateString("(symbol-function 2)");
    }

    @Test(expected = TooManyArgumentsException.class)
    public void symbolFunctionWithTooManyArguments() {
        evaluateString("(symbol-function 'a 'b)");
    }

    @Test(expected = TooFewArgumentsException.class)
    public void symbolFunctionWithTooFewArguments() {
        evaluateString("(symbol-function)");
    }

    @Test
    public void undefinedSymbolFunctionException_HasCorrectAttributes() {
        UndefinedSymbolFunctionException e = new UndefinedSymbolFunctionException(NIL);

        assertEquals(ERROR, e.getSeverity());
        assertNotNull(e.getMessage());
        assertTrue(e.getMessage().length() > 0);
    }

}
