package table;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static sexpression.Nil.NIL;
import static sexpression.Symbol.T;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class ExecutionContextTest {

    private ExecutionContext executionContext;

    public ExecutionContextTest() {
        this.executionContext = ExecutionContext.getInstance();
    }

    @Before
    public void setUp() {
        executionContext.clearContext();
    }

    @After
    public void tearDown() {
        executionContext.clearContext();
    }

    @Test
    public void assignANewScope() {
        SymbolTable scope = new SymbolTable();
        executionContext.setScope(scope);

        assertEquals(scope, executionContext.getScope());
    }

    @Test
    public void clearContext() {
        SymbolTable scope = new SymbolTable();
        executionContext.setScope(scope);

        assertEquals(scope, executionContext.getScope());
        executionContext.clearContext();
        assertNotEquals(scope, executionContext.getScope());
        assertNull(executionContext.getScope().getParent());
    }

    @Test
    public void lookupVariable() {
        executionContext.getScope().put("test", T);

        assertEquals(T, executionContext.lookupSymbolValue("test"));
    }

    @Test
    public void lookupLocalVariable() {
        SymbolTable scope = new SymbolTable(executionContext.getScope());

        scope.put("local", T);
        executionContext.setScope(scope);

        assertEquals(T, executionContext.lookupSymbolValue("local"));
    }

    @Test
    public void lookupGlobalVariable() {
        SymbolTable scope = new SymbolTable(executionContext.getScope());

        executionContext.getScope().put("global", T);
        executionContext.setScope(scope);

        assertEquals(T, executionContext.lookupSymbolValue("global"));
    }

    @Test
    public void lookupShadowedVariable() {
        SymbolTable scope = new SymbolTable(executionContext.getScope());

        scope.put("shadowed", NIL);
        executionContext.getScope().put("shadowed", T);
        executionContext.setScope(scope);

        assertEquals(NIL, executionContext.lookupSymbolValue("shadowed"));
    }

}
