Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
242 changes: 221 additions & 21 deletions src/test/interpreter/VisitorUnitTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,23 @@
import interpreter.types.*;
import interpreter.utils.MockTerminalNode;
import interpreter.utils.MockToken;
import org.antlr.v4.runtime.Token;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.lang.reflect.Field;
import java.util.concurrent.atomic.AtomicReference;

Expand All @@ -36,8 +41,14 @@ class VisitorUnitTest {
@Mock private MineScriptParser.IdContext mockIdContext;
@Mock private MineScriptParser.NegContext mockNegContext;
@Mock private MineScriptParser.NotExprContext mockNotExprContext;
@Mock private MineScriptParser.AndContext mockAndContext;
@Mock private MineScriptParser.AddSubContext mockAddSubContext;
@Mock private MineScriptParser.PowContext mockPowContext;
@Mock private MineScriptParser.ParenExprContext mockParenExprContext;
@Mock private MineScriptParser.CompContext mockCompContext;
@Mock private MineScriptParser.FuncCallContext mockFuncCallContext;
@Mock private MineScriptParser.Actual_parametersContext mockActualParametersContext;
@Mock private MineScriptParser.StatementsContext mockStatementsContext;
@Mock private MineScriptParser.AndContext mockAndContext;
@Mock private MineScriptParser.OrContext mockOrContext;
@Mock private MineScriptParser.MultDivModContext mockMultDivModContext;
@Mock private MineScriptParser.IsIsNotContext mockIsIsNotContext;
Expand All @@ -63,6 +74,7 @@ void visitAssignStoresCorrectNumber(int value) {
Assertions.assertNull(result);
}


@ParameterizedTest
@ValueSource(booleans = {true, false})
void visitAssignStoresCorrectBoolean(boolean value) {
Expand Down Expand Up @@ -124,6 +136,13 @@ void visitAssignStoresCorrectAbsDir(MSAbsDir.Direction value) {
}

@Test
void visitNotExprPassZeroReturnsTrue() {
Mockito.when(mockNotExprContext.expression()).thenReturn(mockExpressionContext1);
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSNumber(0));

MSType result = spyVisitor.visitNotExpr(mockNotExprContext);
Assertions.assertTrue(((MSBool) result).getValue());
}
void visitNotExprValidBoolReturnsNegatedBool() {
Mockito.when(mockNotExprContext.expression()).thenReturn(mockExpressionContext1);
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSBool(false));
Expand All @@ -133,6 +152,15 @@ void visitNotExprValidBoolReturnsNegatedBool() {
}

@ParameterizedTest
@ValueSource(ints = {-1000, -100, 100, 1000})
void visitNotExprPassNonZeroNumberReturnsFalse(int value) {
Mockito.when(mockNotExprContext.expression()).thenReturn(mockExpressionContext1);
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSNumber(value));

MSType result = spyVisitor.visitNotExpr(mockNotExprContext);
Assertions.assertFalse(((MSBool) result).getValue());
}

@ValueSource(ints = {-1000, -100, 0, 100, 1000})
void visitNotExprPassNumberThrowsRuntimeException(int value) {
Mockito.when(mockNotExprContext.expression()).thenReturn(mockExpressionContext);
Expand Down Expand Up @@ -251,7 +279,196 @@ void visitNumberInvalidInputThrowsRuntimeException(){
Mockito.when(mockNumberContext.NUMBER()).thenReturn(new MockTerminalNode("abc"));
Assertions.assertThrows(RuntimeException.class, () -> spyVisitor.visitNumber(mockNumberContext));
}


@ParameterizedTest
@CsvSource ({"1, 2, +", "2, 1, -", "0, 0, +", "-1, -2, +", "-2, -1, -"})
void visitAddSubValidInputReturnsNumber(int value1, int value2, String operator){
mockAddSubContext.op = new MockToken(operator);
Mockito.when(mockAddSubContext.expression(0)).thenReturn(mockExpressionContext1);
Mockito.when(mockAddSubContext.expression(1)).thenReturn(mockExpressionContext2);
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSNumber(value1));
Mockito.when(spyVisitor.visit(mockExpressionContext2)).thenReturn(new MSNumber(value2));

MSType result = spyVisitor.visitAddSub(mockAddSubContext);
if (operator.equals("+")){
Assertions.assertEquals(value1 + value2, ((MSNumber) result).getValue());
} else if (operator.equals("-")){
Assertions.assertEquals(value1 - value2, ((MSNumber) result).getValue());
}
}

@Test
void visitAddSubInvalidTypeThrowsRuntimeException(){
mockAddSubContext.op = new MockToken("+");
Mockito.when(mockAddSubContext.expression(0)).thenReturn(mockExpressionContext1);
Mockito.when(mockAddSubContext.expression(1)).thenReturn(mockExpressionContext2);
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSBool(false));
Mockito.when(spyVisitor.visit(mockExpressionContext2)).thenReturn(new MSNumber(2));

Assertions.assertThrows(RuntimeException.class, () -> spyVisitor.visitAddSub(mockAddSubContext));
}

@ParameterizedTest
@CsvSource ({"1, 2", "2, 1", "0, 0", "-1, 1", "-2, 2"})
void visitPowValidInputReturnsNumber(int value1, int value2){
Mockito.when(mockPowContext.expression(0)).thenReturn(mockExpressionContext1);
Mockito.when(mockPowContext.expression(1)).thenReturn(mockExpressionContext2);
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSNumber(value1));
Mockito.when(spyVisitor.visit(mockExpressionContext2)).thenReturn(new MSNumber(value2));

MSType result = spyVisitor.visitPow(mockPowContext);
Assertions.assertEquals(Math.pow(value1, value2), ((MSNumber) result).getValue());
}

@Test
void visitPowInvalidInputThrowsRuntimeException(){
Mockito.when(mockPowContext.expression(0)).thenReturn(mockExpressionContext1);
Mockito.when(mockPowContext.expression(1)).thenReturn(mockExpressionContext2);
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSNumber(1));
Mockito.when(spyVisitor.visit(mockExpressionContext2)).thenReturn(new MSNumber(-1));

Assertions.assertThrows(RuntimeException.class, () -> spyVisitor.visitPow(mockPowContext));
}

@ParameterizedTest
@CsvSource ({"true, false", "false, false"})
void visitPowInvalidTypeThrowsRuntimeException(boolean bool1, boolean bool2){
Mockito.when(mockPowContext.expression(0)).thenReturn(mockExpressionContext1);
Mockito.when(mockPowContext.expression(1)).thenReturn(mockExpressionContext2);
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSBool(bool1));
Mockito.when(spyVisitor.visit(mockExpressionContext2)).thenReturn(new MSBool(bool2));

Assertions.assertThrows(RuntimeException.class, () -> spyVisitor.visitPow(mockPowContext));

}

@ParameterizedTest
@CsvSource ({"1", "2", "0", "-1", "-2"})
void visitParenExprValidInputReturnsNumber(int value){
Mockito.when(mockParenExprContext.expression()).thenReturn(mockExpressionContext1);
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSNumber(value));

MSType result = spyVisitor.visitParenExpr(mockParenExprContext);
Assertions.assertEquals(value, ((MSNumber) result).getValue());
}

@ParameterizedTest
@ValueSource (booleans = {true, false})
void visitParenExprValidInputReturnsBoolean(boolean value){
Mockito.when(mockParenExprContext.expression()).thenReturn(mockExpressionContext1);
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSBool(value));

MSType result = spyVisitor.visitParenExpr(mockParenExprContext);
Assertions.assertEquals(value, ((MSBool) result).getValue());
}

@ParameterizedTest
@CsvSource ({"1, 2, <", "2, 1, >", "0, 0, >=", "-1, 1, <", "-2, 2, <="})
void visitCompValidInputReturnsTrue(int value1, int value2, String operator){
mockCompContext.op = new MockToken(operator);
Mockito.when(mockCompContext.expression(0)).thenReturn(mockExpressionContext1);
Mockito.when(mockCompContext.expression(1)).thenReturn(mockExpressionContext2);
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSNumber(value1));
Mockito.when(spyVisitor.visit(mockExpressionContext2)).thenReturn(new MSNumber(value2));

MSType result = spyVisitor.visitComp(mockCompContext);
Assertions.assertEquals(true, ((MSBool) result).getValue());
}

@ParameterizedTest
@CsvSource ({"1, 2, >=", "2, 1, <", "0, 0, <", "-1, 1, >=", "-2, 2, >"})
void visitCompValidInputReturnsFalse(int value1, int value2, String operator){
mockCompContext.op = new MockToken(operator);
Mockito.when(mockCompContext.expression(0)).thenReturn(mockExpressionContext1);
Mockito.when(mockCompContext.expression(1)).thenReturn(mockExpressionContext2);
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSNumber(value1));
Mockito.when(spyVisitor.visit(mockExpressionContext2)).thenReturn(new MSNumber(value2));

MSType result = spyVisitor.visitComp(mockCompContext);
Assertions.assertEquals(false, ((MSBool) result).getValue());
}

@Test
void visitCompInvalidTypeThrowsException(){
mockCompContext.op = new MockToken(">");
Mockito.when(mockCompContext.expression(0)).thenReturn(mockExpressionContext1);
Mockito.when(mockCompContext.expression(1)).thenReturn(mockExpressionContext2);
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSBool(true));
Mockito.when(spyVisitor.visit(mockExpressionContext2)).thenReturn(new MSNumber(14));

Assertions.assertThrows(RuntimeException.class, () -> spyVisitor.visitComp(mockCompContext));
}

@Test
void visitFuncCallValidInputNoParamsReturnsNumber(){
Mockito.when(mockFuncCallContext.actual_parameters()).thenReturn(mockActualParametersContext);
Mockito.when(mockFuncCallContext.ID()).thenReturn(new MockTerminalNode("testFunction"));
symbolTable.enterSymbol("testFunction", new MSFunction("testFunction", new ArrayList<String>(), mockStatementsContext));

Mockito.when(spyVisitor.visit(mockStatementsContext)).thenReturn(new MSNumber(1));

MSType result = spyVisitor.visitFuncCall(mockFuncCallContext);
Assertions.assertEquals(1, ((MSNumber) result).getValue());
}
@ParameterizedTest
@CsvSource ({"1", "2", "0", "-1", "-2", "123", "-123"})
void visitFuncCallValidInputOneParamReturnsNumber(int value){

Mockito.when(mockFuncCallContext.ID()).thenReturn(new MockTerminalNode("testFunction"));
Mockito.when(mockFuncCallContext.actual_parameters()).thenReturn(mockActualParametersContext);
Mockito.when(mockFuncCallContext.actual_parameters().expression()).thenReturn(new ArrayList<MineScriptParser.ExpressionContext>(){{add(mockExpressionContext1);}});
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSNumber(value));

symbolTable.enterSymbol("testFunction", new MSFunction("testFunction", new ArrayList<String>(){{add("Param1");}}, mockStatementsContext));

Mockito.when(spyVisitor.visit(mockStatementsContext)).thenReturn(new MSNumber(value));

MSType result = spyVisitor.visitFuncCall(mockFuncCallContext);
Assertions.assertEquals(value, ((MSNumber) result).getValue());
}

@ParameterizedTest
@CsvSource ({"1, 2", "2, 1", "0, 0", "-1, 1", "-2, 2", "123, 122", "123, 124", "123, 123"})
void visitFuncCallValidInputTwoParamReturnsNumber(int value1, int value2){

Mockito.when(mockFuncCallContext.ID()).thenReturn(new MockTerminalNode("testFunction"));
Mockito.when(mockFuncCallContext.actual_parameters()).thenReturn(mockActualParametersContext);
Mockito.when(mockFuncCallContext.actual_parameters().expression()).thenReturn(new ArrayList<MineScriptParser.ExpressionContext>(){{add(mockExpressionContext1); add(mockExpressionContext2);}});
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSNumber(value1));
Mockito.when(spyVisitor.visit(mockExpressionContext2)).thenReturn(new MSNumber(value2));

symbolTable.enterSymbol("testFunction", new MSFunction("testFunction", new ArrayList<String>(){{add("Param1"); add("Param2");}}, mockStatementsContext));

Mockito.when(spyVisitor.visit(mockStatementsContext)).thenReturn(new MSNumber(value1+value2));

MSType result = spyVisitor.visitFuncCall(mockFuncCallContext);
Assertions.assertEquals(value1+value2, ((MSNumber) result).getValue());
}

@ParameterizedTest
@CsvSource ({"1, 2", "2, 1", "0, 0", "-1, 1", "-2, 2"})
void visitFuncCallInvalidInputThrowsException(int value1, int value2){

Mockito.when(mockFuncCallContext.ID()).thenReturn(new MockTerminalNode("testFunction"));
Mockito.when(mockFuncCallContext.actual_parameters()).thenReturn(mockActualParametersContext);
Mockito.when(mockFuncCallContext.actual_parameters().expression()).thenReturn(new ArrayList<MineScriptParser.ExpressionContext>(){{add(mockExpressionContext1); add(mockExpressionContext2);}});
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSNumber(value1));
Mockito.when(spyVisitor.visit(mockExpressionContext2)).thenReturn(new MSNumber(value2));

symbolTable.enterSymbol("testFunction", new MSFunction("testFunction", new ArrayList<String>(){{add("Param1");}}, mockStatementsContext));

Assertions.assertThrows(RuntimeException.class, () -> spyVisitor.visitFuncCall(mockFuncCallContext));
}

@Test
void visitFuncCallInvalidFunction(){
Mockito.when(mockFuncCallContext.ID()).thenReturn(new MockTerminalNode("testFunctionFake"));
Mockito.when(mockFuncCallContext.actual_parameters()).thenReturn(mockActualParametersContext);
symbolTable.enterSymbol("testFunction", new MSFunction("testFunction", new ArrayList<String>(){{add("Param1"); }}, mockStatementsContext));

Assertions.assertThrows(RuntimeException.class, () -> spyVisitor.visitFuncCall(mockFuncCallContext));
}

@Test
void visitAndValidBoolsReturnsTrue(){
Mockito.when(mockAndContext.expression(0)).thenReturn(mockExpressionContext1);
Expand All @@ -262,7 +479,7 @@ void visitAndValidBoolsReturnsTrue(){
MSType result = spyVisitor.visitAnd(mockAndContext);
Assertions.assertTrue(((MSBool) result).getValue());
}

@Test
void visitAndBoolsTrueAndFalseReturnsFalse(){
Mockito.when(mockAndContext.expression(0)).thenReturn(mockExpressionContext1);
Expand All @@ -282,23 +499,6 @@ void visitAndFalseWithShortCircuitReturnsFalse() {
Assertions.assertFalse(((MSBool) result).getValue());
}

@ParameterizedTest
@CsvSource ({"1, 2, +", "2, 1, -", "0, 0, +", "-1, -2, +", "-2, -1, -"})
void visitAddSubValidInputReturnsNumber(int left, int right, String operator){
mockAddSubContext.op = new MockToken(operator);
Mockito.when(mockAddSubContext.expression(0)).thenReturn(mockExpressionContext1);
Mockito.when(mockAddSubContext.expression(1)).thenReturn(mockExpressionContext2);
Mockito.when(spyVisitor.visit(mockExpressionContext1)).thenReturn(new MSNumber(left));
Mockito.when(spyVisitor.visit(mockExpressionContext2)).thenReturn(new MSNumber(right));

MSType result = spyVisitor.visitAddSub(mockAddSubContext);
if (operator.equals("+")){
Assertions.assertEquals(left + right, ((MSNumber) result).getValue());
} else if (operator.equals("-")){
Assertions.assertEquals(left - right, ((MSNumber) result).getValue());
}
}

@ParameterizedTest
@CsvSource({"false, false", "false, true", "true, false", "true, true"})
void visitOrValidInputReturnsOrValue(boolean left, boolean right) {
Expand Down