package function.builtin.special;

import static testutil.TestUtilities.evaluateString;
import static testutil.TypeAssertions.assertNil;
import static testutil.TypeAssertions.assertT;

import org.junit.Test;

import function.ArgumentValidator.TooFewArgumentsException;
import function.ArgumentValidator.TooManyArgumentsException;
import function.builtin.EVAL.UndefinedSymbolException;
import testutil.SymbolAndFunctionCleaner;

public class IFTest extends SymbolAndFunctionCleaner {

    @Test
    public void ifWithOneExpression_ReturnsExpression() {
        String input = "(if t t)";

        assertT(evaluateString(input));
    }

    @Test
    public void ifWithOneExpression_ReturnsNil() {
        String input = "(if nil t)";

        assertNil(evaluateString(input));
    }

    @Test
    public void ifWithTwoExpressions_ReturnsFirst() {
        String input = "(if t t nil)";

        assertT(evaluateString(input));
    }

    @Test
    public void ifWithTwoExpressions_ReturnsSecond() {
        String input = "(if nil nil t)";

        assertT(evaluateString(input));
    }

    @Test
    public void ifWithNumericConditional() {
        String input = "(if 23 t nil)";

        assertT(evaluateString(input));
    }

    @Test(expected = UndefinedSymbolException.class)
    public void ifWithNilCondition_DoesNotEvaluateThenForm() {
        String input = "(if nil (setq x 22))";

        assertNil(evaluateString(input));
        evaluateString("x");
    }

    @Test(expected = UndefinedSymbolException.class)
    public void ifWithTrueCondition_DoesNotEvaluateElseForm() {
        String input = "(if t nil (setq x 22))";

        assertNil(evaluateString(input));
        evaluateString("x");
    }

    @Test(expected = TooFewArgumentsException.class)
    public void ifWithTooFewArguments() {
        evaluateString("(if t)");
    }

    @Test(expected = TooManyArgumentsException.class)
    public void ifWithTooManyArguments() {
        evaluateString("(if t t t t)");
    }

}
