From 9df0da89ffa5aad643f33d799d91bb93a69e940b Mon Sep 17 00:00:00 2001 From: nitrix Date: Mon, 9 Mar 2020 21:32:05 +0100 Subject: [PATCH] implement junit tests --- src/test/java/AndTest.java | 21 +++++++++++ src/test/java/ConstructorCallTest.java | 43 ++++++++++++++++++++++ src/test/java/DestroyStatementTest.java | 21 +++++++++++ src/test/java/FieldAssignmentTest.java | 32 ++++++++++++++++ src/test/java/FunctionCallTest.java | 43 ++++++++++++++++++++++ src/test/java/FunctionDefinitionTest.java | 32 ++++++++++++++++ src/test/java/Helper.java | 36 ++++++++++++++++++ src/test/java/ModuloTest.java | 20 ++++++++++ src/test/java/OrTest.java | 21 +++++++++++ src/test/java/ParameterTest.java | 14 +++++++ src/test/java/StructFieldAccessTest.java | 31 ++++++++++++++++ src/test/java/VariableAssignmentTest.java | 21 +++++++++++ src/test/java/VariableDeclarationTest.java | 32 ++++++++++++++++ src/test/java/VariableTest.java | 32 ++++++++++++++++ 14 files changed, 399 insertions(+) create mode 100644 src/test/java/AndTest.java create mode 100644 src/test/java/ConstructorCallTest.java create mode 100644 src/test/java/DestroyStatementTest.java create mode 100644 src/test/java/FieldAssignmentTest.java create mode 100644 src/test/java/FunctionCallTest.java create mode 100644 src/test/java/FunctionDefinitionTest.java create mode 100644 src/test/java/Helper.java create mode 100644 src/test/java/ModuloTest.java create mode 100644 src/test/java/OrTest.java create mode 100644 src/test/java/ParameterTest.java create mode 100644 src/test/java/StructFieldAccessTest.java create mode 100644 src/test/java/VariableAssignmentTest.java create mode 100644 src/test/java/VariableDeclarationTest.java create mode 100644 src/test/java/VariableTest.java diff --git a/src/test/java/AndTest.java b/src/test/java/AndTest.java new file mode 100644 index 0000000..46dbd69 --- /dev/null +++ b/src/test/java/AndTest.java @@ -0,0 +1,21 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.jupiter.api.Test; + +import de.hsrm.compiler.Klang.ContextAnalysis; + +public class AndTest { + @Test + void onlyForBool() { + ParseTree tree = Helper.prepareParser("function foo(): bool { return 1 && 2; } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:30 && is only defined for bool.", e.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/ConstructorCallTest.java b/src/test/java/ConstructorCallTest.java new file mode 100644 index 0000000..99010bc --- /dev/null +++ b/src/test/java/ConstructorCallTest.java @@ -0,0 +1,43 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.jupiter.api.Test; + +import de.hsrm.compiler.Klang.ContextAnalysis; + +public class ConstructorCallTest { + + @Test + void structNotDefined() { + ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): bar { return create schwurbel(1); } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:52 Struct with name \"schwurbel\" not defined.", e.getMessage()); + } + + @Test + void numConstructorParameterMissmatch() { + ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): bar { return create bar(1, false); } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:52 Struct \"bar\" defined 1 fields, but got 2 constructor parameters.", e.getMessage()); + } + + @Test + void constructorParameterTypeMismatch() { + ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): bar { return create bar(false); } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:63 argument 0 Type missmatch: cannot combine bool and int", e.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/DestroyStatementTest.java b/src/test/java/DestroyStatementTest.java new file mode 100644 index 0000000..f157d2b --- /dev/null +++ b/src/test/java/DestroyStatementTest.java @@ -0,0 +1,21 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.jupiter.api.Test; + +import de.hsrm.compiler.Klang.ContextAnalysis; + + +public class DestroyStatementTest { + @Test + void variableNotDefined() { + ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): int { destroy x; return 1; } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:45 Variable with name \"x\" not defined.", e.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/FieldAssignmentTest.java b/src/test/java/FieldAssignmentTest.java new file mode 100644 index 0000000..879e4c8 --- /dev/null +++ b/src/test/java/FieldAssignmentTest.java @@ -0,0 +1,32 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.jupiter.api.Test; + +import de.hsrm.compiler.Klang.ContextAnalysis; + +public class FieldAssignmentTest { + + @Test + void variableNotDefined() { + ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { str.a = 1; return 1; } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:46 Variable with name str not defined.", e.getMessage()); + } + + @Test + void fieldAssignmentOnNonStruct() { + ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { let x: int = 0; x.a = 0; return 1; } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:62 Variable must reference a struct but references int.", e.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/FunctionCallTest.java b/src/test/java/FunctionCallTest.java new file mode 100644 index 0000000..d0e5126 --- /dev/null +++ b/src/test/java/FunctionCallTest.java @@ -0,0 +1,43 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.jupiter.api.Test; + +import de.hsrm.compiler.Klang.ContextAnalysis; + +public class FunctionCallTest { + + @Test + void funcNotDefined() { + ParseTree tree = Helper.prepareParser("function foo(): int { return 1; } bar();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:34 Function with name \"bar\" not defined.", e.getMessage()); + } + + @Test + void numParameterMismatch() { + ParseTree tree = Helper.prepareParser("function foo(): int { return 1; } foo(5);"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:34 Function \"foo\" expects 0 parameters, but got 1.", e.getMessage()); + } + + @Test + void parameterTypeMissmatch() { + ParseTree tree = Helper.prepareParser("function foo(x: int): int { return x; } foo(false);"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:40 argument 0 Expected int but got: bool", e.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/FunctionDefinitionTest.java b/src/test/java/FunctionDefinitionTest.java new file mode 100644 index 0000000..442e792 --- /dev/null +++ b/src/test/java/FunctionDefinitionTest.java @@ -0,0 +1,32 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.jupiter.api.Test; + +import de.hsrm.compiler.Klang.ContextAnalysis; + +public class FunctionDefinitionTest { + + @Test + void typeNotDefined() { + ParseTree tree = Helper.prepareParser("function foo(): schwurbel { return 1; } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:0 Type schwurbel not defined.", e.getMessage()); + } + + @Test + void noReturnExpression() { + ParseTree tree = Helper.prepareParser("function foo(): int { let x: int; x = 0; } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:0 Function foo has to return something of type int.", e.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/Helper.java b/src/test/java/Helper.java new file mode 100644 index 0000000..68b0ff6 --- /dev/null +++ b/src/test/java/Helper.java @@ -0,0 +1,36 @@ +import java.util.*; + +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.tree.*; + +import de.hsrm.compiler.Klang.*; +import de.hsrm.compiler.Klang.helper.*; +import de.hsrm.compiler.Klang.nodes.*; + +public class Helper { + public static ParseTree prepareParser(String input) { + CharStream inStream = CharStreams.fromString(input); + KlangLexer lexer = new KlangLexer(inStream); + CommonTokenStream tokens = new CommonTokenStream(lexer); + KlangParser parser = new KlangParser(tokens); + return parser.parse(); + } + + public static Map getFuncs(ParseTree tree) { + var functionDefinitions = new HashMap(); + new GetFunctions(functionDefinitions).visit(tree); + return functionDefinitions; + } + + public static Set getStructNames(ParseTree tree) { + var structNames = new HashSet(); + new GetStructNames(structNames).visit(tree); + return structNames; + } + + public static Map getStructs(ParseTree tree) { + var structs = new HashMap(); + new GetStructs(getStructNames(tree), structs).visit(tree); + return structs; + } +} \ No newline at end of file diff --git a/src/test/java/ModuloTest.java b/src/test/java/ModuloTest.java new file mode 100644 index 0000000..c11a87f --- /dev/null +++ b/src/test/java/ModuloTest.java @@ -0,0 +1,20 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.jupiter.api.Test; + +import de.hsrm.compiler.Klang.ContextAnalysis; + +public class ModuloTest { + @Test + void onlyForInt() { + ParseTree tree = Helper.prepareParser("function foo(): float { return 1.0 % 2.3; } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:31 Only integers are allowed for modulo.", e.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/OrTest.java b/src/test/java/OrTest.java new file mode 100644 index 0000000..07dfc33 --- /dev/null +++ b/src/test/java/OrTest.java @@ -0,0 +1,21 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.jupiter.api.Test; + +import de.hsrm.compiler.Klang.ContextAnalysis; + +public class OrTest { + + @Test + void onlyForBool() { + ParseTree tree = Helper.prepareParser("function foo(): bool { return 1 || 2; } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:30 || is only defined for bool.", e.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/ParameterTest.java b/src/test/java/ParameterTest.java new file mode 100644 index 0000000..9342ccc --- /dev/null +++ b/src/test/java/ParameterTest.java @@ -0,0 +1,14 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.jupiter.api.Test; + +public class ParameterTest { + @Test + void typeNotDefined() { + ParseTree tree = Helper.prepareParser("struct test { a: schwurbel; } function foo(): int { return 1; } foo();"); + Exception e = assertThrows(RuntimeException.class, () -> Helper.getStructs(tree)); + assertEquals("Error in line 1:14 Type schwurbel not defined.", e.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/StructFieldAccessTest.java b/src/test/java/StructFieldAccessTest.java new file mode 100644 index 0000000..79b9766 --- /dev/null +++ b/src/test/java/StructFieldAccessTest.java @@ -0,0 +1,31 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.jupiter.api.Test; + +import de.hsrm.compiler.Klang.ContextAnalysis; + +public class StructFieldAccessTest { + @Test + void variableNotDefined() { + ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { return str.a; } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:53 Variable with name str not defined.", e.getMessage()); + } + + @Test + void fieldAssignmentOnNonStruct() { + ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { let x: int = 0; return x.a; } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:69 Variable must reference a struct but references int.", e.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/VariableAssignmentTest.java b/src/test/java/VariableAssignmentTest.java new file mode 100644 index 0000000..faa338d --- /dev/null +++ b/src/test/java/VariableAssignmentTest.java @@ -0,0 +1,21 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.jupiter.api.Test; + +import de.hsrm.compiler.Klang.ContextAnalysis; + +public class VariableAssignmentTest { + + @Test + void variableNotDefined() { + ParseTree tree = Helper.prepareParser("function foo(): int { x = 1; return 1; } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:22 Variable with name \"x\" not defined.", e.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/VariableDeclarationTest.java b/src/test/java/VariableDeclarationTest.java new file mode 100644 index 0000000..a52ea2e --- /dev/null +++ b/src/test/java/VariableDeclarationTest.java @@ -0,0 +1,32 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.jupiter.api.Test; + +import de.hsrm.compiler.Klang.ContextAnalysis; + +public class VariableDeclarationTest { + @Test + void typeNotDefined() { + ParseTree tree = Helper.prepareParser("function foo(): int { let X: unk; return 1; } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:22 Type unk not defined.", e.getMessage()); + } + + @Test + void variableRedeclaration() + { + ParseTree tree = Helper.prepareParser("function foo(): int { let x: int; let x: bool; return 1; } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:34 Redeclaration of variable with name \"x\".", e.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/VariableTest.java b/src/test/java/VariableTest.java new file mode 100644 index 0000000..763226c --- /dev/null +++ b/src/test/java/VariableTest.java @@ -0,0 +1,32 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.jupiter.api.Test; + +import de.hsrm.compiler.Klang.ContextAnalysis; + +public class VariableTest { + + @Test + void variableNotDefined() { + ParseTree tree = Helper.prepareParser("function foo(): int { return x; } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:29 Variable with name \"x\" not defined.", e.getMessage()); + } + + @Test + void variableNotInitialized() { + ParseTree tree = Helper.prepareParser("function foo(): int { let x: int; return x; } foo();"); + var funcs = Helper.getFuncs(tree); + var structs = Helper.getStructs(tree); + ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs); + + Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree)); + assertEquals("Error in line 1:41 Variable with name \"x\" has not been initialized.", e.getMessage()); + } +} \ No newline at end of file