package function.builtin;

import static testutil.TestUtilities.assertSExpressionsMatch;
import static testutil.TestUtilities.evaluateString;

import org.junit.Test;

import function.ArgumentValidator.TooManyArgumentsException;
import testutil.SymbolAndFunctionCleaner;

public class SYMBOLSTest extends SymbolAndFunctionCleaner {

    @Test
    public void noSymbols() {
        assertSExpressionsMatch(evaluateString("'(nil)"), evaluateString("(symbols)"));
    }

    @Test
    public void globalSymbol() {
        evaluateString("(setq x 10)");
        assertSExpressionsMatch(evaluateString("'(((x 10)))"), evaluateString("(symbols)"));
    }

    @Test
    public void multipleSymbolsSorted() {
        evaluateString("(setq x 10)");
        evaluateString("(setq a 20)");
        evaluateString("(setq y 30)");
        evaluateString("(setq w 40)");
        evaluateString("(setq e 50)");

        assertSExpressionsMatch(evaluateString("'(((a 20) (e 50) (w 40) (x 10) (y 30)))"), evaluateString("(symbols)"));
    }

    @Test
    public void fullExecutionContext() {
        evaluateString("(setq x 10)");
        evaluateString("(setq y 30)");

        assertSExpressionsMatch(evaluateString("'(((x 10) (y 30)) ((a 100) (q 99) (z nil)))"),
                                evaluateString("(let ((q 99) (a 100) (z)) (symbols))"));
    }

    @Test
    public void updateSymbolInLet() {
        evaluateString("(setq x 10)");
        evaluateString("(setq y 30)");

        assertSExpressionsMatch(evaluateString("'(((x 10) (y 30)) ((q 99) (x 1) (z 2)))"),
                                evaluateString("(let ((q 99) (x 100) (z 2)) (setq x 1) (symbols))"));
    }

    @Test(expected = TooManyArgumentsException.class)
    public void symbolsWithTooManyArguments() {
        evaluateString("(symbols 1)");
    }
}
