From c7175fc542285b739f79097d7e97356341b1b666 Mon Sep 17 00:00:00 2001
From: qwertzniki6 <104077966+bretzNiklas@users.noreply.github.com>
Date: Tue, 10 Jan 2023 19:03:20 +0100
Subject: [PATCH] Added tests

---
 .idea/compiler.xml                            |   1 +
 .idea/misc.xml                                |   7 ++
 Aufgabe4Maven/pom.xml                         |  39 +++++++++++
 {Aufgabe4 => Aufgabe4Maven/src}/Ast.java      |   2 +-
 .../src}/Evaluator.java                       |   2 +-
 .../src}/EvaluatorBackup.java                 |   2 +-
 Aufgabe4Maven/src/Exceptions.java             |  33 +++++++++
 {Aufgabe4 => Aufgabe4Maven/src}/Lexer.java    |   2 +
 {Aufgabe4 => Aufgabe4Maven/src}/Parser.java   |  66 +++++++++++-------
 {Aufgabe4 => Aufgabe4Maven/src}/Plotter.java  |   0
 .../src}/TokenType.java                       |   0
 .../src}/ValuesToDraw.java                    |   0
 .../src}/expressions.txt                      |   0
 {Aufgabe4 => Aufgabe4Maven/src}/main.java     |   7 +-
 {Aufgabe4 => Aufgabe4Maven/src}/test.java     |   0
 Aufgabe4Maven/tests/LexerTest.java            |  60 ++++++++++++++++
 out/production/inf3_git/Token.class           | Bin 832 -> 0 bytes
 out/production/inf3_git/TokenType.class       | Bin 971 -> 0 bytes
 out/production/inf3_git/main.class            | Bin 4310 -> 0 bytes
 19 files changed, 189 insertions(+), 32 deletions(-)
 create mode 100644 Aufgabe4Maven/pom.xml
 rename {Aufgabe4 => Aufgabe4Maven/src}/Ast.java (96%)
 rename {Aufgabe4 => Aufgabe4Maven/src}/Evaluator.java (97%)
 rename {Aufgabe4 => Aufgabe4Maven/src}/EvaluatorBackup.java (94%)
 create mode 100644 Aufgabe4Maven/src/Exceptions.java
 rename {Aufgabe4 => Aufgabe4Maven/src}/Lexer.java (97%)
 rename {Aufgabe4 => Aufgabe4Maven/src}/Parser.java (77%)
 rename {Aufgabe4 => Aufgabe4Maven/src}/Plotter.java (100%)
 rename {Aufgabe4 => Aufgabe4Maven/src}/TokenType.java (100%)
 rename {Aufgabe4 => Aufgabe4Maven/src}/ValuesToDraw.java (100%)
 rename {Aufgabe4 => Aufgabe4Maven/src}/expressions.txt (100%)
 rename {Aufgabe4 => Aufgabe4Maven/src}/main.java (94%)
 rename {Aufgabe4 => Aufgabe4Maven/src}/test.java (100%)
 create mode 100644 Aufgabe4Maven/tests/LexerTest.java
 delete mode 100644 out/production/inf3_git/Token.class
 delete mode 100644 out/production/inf3_git/TokenType.class
 delete mode 100644 out/production/inf3_git/main.class

diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 0a6e501..ea6c1b3 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -6,6 +6,7 @@
         <sourceOutputDir name="target/generated-sources/annotations" />
         <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
         <outputRelativeToContentRoot value="true" />
+        <module name="Aufgabe4Maven" />
       </profile>
     </annotationProcessing>
     <bytecodeTargetLevel>
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 1700c77..19804e8 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,13 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
   <component name="ExternalStorageConfigurationManager" enabled="true" />
+  <component name="MavenProjectsManager">
+    <option name="originalFiles">
+      <list>
+        <option value="$PROJECT_DIR$/Aufgabe4Maven/pom.xml" />
+      </list>
+    </option>
+  </component>
   <component name="ProjectRootManager" version="2" languageLevel="JDK_15" default="true" project-jdk-name="15" project-jdk-type="JavaSDK">
     <output url="file://$PROJECT_DIR$/out" />
   </component>
diff --git a/Aufgabe4Maven/pom.xml b/Aufgabe4Maven/pom.xml
new file mode 100644
index 0000000..ad36081
--- /dev/null
+++ b/Aufgabe4Maven/pom.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.example</groupId>
+    <artifactId>Aufgabe4Maven</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <properties>
+        <maven.compiler.source>15</maven.compiler.source>
+        <maven.compiler.target>15</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.13.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter</artifactId>
+            <version>5.9.0</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.google.java.contract</groupId>
+            <artifactId>cofoja</artifactId>
+            <version>1.1-r150</version>
+        </dependency>
+
+
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/Aufgabe4/Ast.java b/Aufgabe4Maven/src/Ast.java
similarity index 96%
rename from Aufgabe4/Ast.java
rename to Aufgabe4Maven/src/Ast.java
index 93ecf5b..2a14419 100644
--- a/Aufgabe4/Ast.java
+++ b/Aufgabe4Maven/src/Ast.java
@@ -68,5 +68,5 @@ class AstDecimal extends Ast {
 
 class AstOperator extends Ast {
 
-    String astOperator;
+    String astOperatorContent;
 }
diff --git a/Aufgabe4/Evaluator.java b/Aufgabe4Maven/src/Evaluator.java
similarity index 97%
rename from Aufgabe4/Evaluator.java
rename to Aufgabe4Maven/src/Evaluator.java
index dd17f19..8dfd35b 100644
--- a/Aufgabe4/Evaluator.java
+++ b/Aufgabe4Maven/src/Evaluator.java
@@ -31,7 +31,7 @@ public class Evaluator {
 
         visit(node.astExpression1);
 
-        switch(node.astOperator.astOperator) {
+        switch(node.astOperator.astOperatorContent) {
 
             case "+":
                 return visit(node.astExpression1) + visit(node.astExpression2);
diff --git a/Aufgabe4/EvaluatorBackup.java b/Aufgabe4Maven/src/EvaluatorBackup.java
similarity index 94%
rename from Aufgabe4/EvaluatorBackup.java
rename to Aufgabe4Maven/src/EvaluatorBackup.java
index ba22527..315984b 100644
--- a/Aufgabe4/EvaluatorBackup.java
+++ b/Aufgabe4Maven/src/EvaluatorBackup.java
@@ -24,7 +24,7 @@ public class EvaluatorBackup {
     public void visit(AstBinaryOp node) {
 
         visit(node.astExpression1);
-        System.out.print(node.astOperator.astOperator);
+        System.out.print(node.astOperator.astOperatorContent);
         visit(node.astExpression2);
 
     }
diff --git a/Aufgabe4Maven/src/Exceptions.java b/Aufgabe4Maven/src/Exceptions.java
new file mode 100644
index 0000000..e2e0429
--- /dev/null
+++ b/Aufgabe4Maven/src/Exceptions.java
@@ -0,0 +1,33 @@
+public class Exceptions {
+
+    public static Class<? extends Throwable> ParserException;
+
+    public static class ParserException extends RuntimeException {
+        private String message;
+
+        public ParserException(String string) {
+            this.message = string;
+        }
+
+        public String toString() {
+            return "parser failed: " + message;
+        }
+
+        /**
+         *
+         */
+        private static final long serialVersionUID = 1L;
+
+    }
+
+
+    @SuppressWarnings("serial")
+    public static class LexerException extends RuntimeException {
+        public LexerException() {
+        }
+
+        public LexerException(String string) {
+            super(string);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Aufgabe4/Lexer.java b/Aufgabe4Maven/src/Lexer.java
similarity index 97%
rename from Aufgabe4/Lexer.java
rename to Aufgabe4Maven/src/Lexer.java
index fc81483..73240a0 100644
--- a/Aufgabe4/Lexer.java
+++ b/Aufgabe4Maven/src/Lexer.java
@@ -1,9 +1,11 @@
 import java.util.ArrayList;
 import java.util.Objects;
+import com.google.java.contract.*;
 
 public class Lexer {
 
 
+    @Requires({"s != null"})
     public ArrayList<Token> lex(String s) {
 
         ArrayList<String> separatedChars = separateChars(s);
diff --git a/Aufgabe4/Parser.java b/Aufgabe4Maven/src/Parser.java
similarity index 77%
rename from Aufgabe4/Parser.java
rename to Aufgabe4Maven/src/Parser.java
index 63d0511..1bfbca2 100644
--- a/Aufgabe4/Parser.java
+++ b/Aufgabe4Maven/src/Parser.java
@@ -1,10 +1,11 @@
+import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
 public class Parser {
 
-    public AstExpression parse (ArrayList<Token> tokenList) {
+    public AstExpression parse (ArrayList<Token> tokenList) throws Exception {
 
         AstExpression root;
 
@@ -13,7 +14,7 @@ public class Parser {
         return root;
     }
 
-    private AstExpression parseAstExpression (ArrayList<Token> tokenList) {
+    private AstExpression parseAstExpression (ArrayList<Token> tokenList) throws Exception {
 
         AstExpression toReturn = new AstExpression();
 
@@ -56,50 +57,57 @@ public class Parser {
 
         // Check if first and last tokens have "(" and ")" strings
 
-        if(tokenList.get(0).tokenString.equals("(") && tokenList.get(tokenList.size() - 1).tokenString.equals(")")) {
+        try {
+
+            if (tokenList.get(0).tokenString.equals("(") && tokenList.get(tokenList.size() - 1).tokenString.equals(")")) {
 
 
-            // Check if "false alarm", e.g. ( 1 + 2 ) + ( 1 + 2 ) <- starts and ends with ( and ) but is to be treated as binaryOp
+                // Check if "false alarm", e.g. ( 1 + 2 ) + ( 1 + 2 ) <- starts and ends with ( and ) but is to be treated as binaryOp
 
-            boolean falseAlarm = false;
+                boolean falseAlarm = false;
 
-            for(int i = tokenList.size() - 2; i > 0; i--) {
+                for (int i = tokenList.size() - 2; i > 0; i--) {
 
-                if(tokenList.get(i).tokenString.equals(")") || tokenList.get(i).tokenString.equals("(")) {
+                    if (tokenList.get(i).tokenString.equals(")") || tokenList.get(i).tokenString.equals("(")) {
 
-                    if(tokenList.get(i).tokenString.equals(")")) {
-                        falseAlarm = false;
+                        if (tokenList.get(i).tokenString.equals(")")) {
+                            falseAlarm = false;
 
-                    } else {
-                        falseAlarm = true;
+                        } else {
+                            falseAlarm = true;
+                        }
+                        break;
                     }
-                    break;
                 }
-            }
 
-            // Parse tokenList without first and last object and save it in toReturns astExpression
+                // Parse tokenList without first and last object and save it in toReturns astExpression
 
-            if(!falseAlarm) {
+                if (!falseAlarm) {
+
+                    toReturn.astExpression = parseAstExpression(
+                            (ArrayList<Token>) IntStream.range(1, tokenList.size() - 1)
+                                    .mapToObj(i -> tokenList.get(i))
+                                    .collect(Collectors.toList()) // https://www.baeldung.com/java-stream-indices
+                    );
+                    return toReturn;
+                }
 
-                toReturn.astExpression = parseAstExpression(
-                        (ArrayList<Token>) IntStream.range(1, tokenList.size() - 1)
-                                .mapToObj(i -> tokenList.get(i))
-                                .collect(Collectors.toList()) // https://www.baeldung.com/java-stream-indices
-                );
-                return toReturn;
             }
 
+        } catch (IndexOutOfBoundsException indexOutOfBoundsException) {
+            throw new Exceptions.ParserException("String is not a valid function");
         }
 
+
         toReturn.astBinaryOp = parseBinaryOp(tokenList);
 
         return toReturn;
 
     }
 
-    //(5+2)+(1+2)
 
-    private AstBinaryOp parseBinaryOp (ArrayList<Token> tokenList) {
+
+    private AstBinaryOp parseBinaryOp (ArrayList<Token> tokenList) throws Exception {
 
 
         AstBinaryOp toReturn = new AstBinaryOp();
@@ -141,7 +149,7 @@ public class Parser {
     private AstOperator parseOperator (Token operator) {
 
         AstOperator toReturn = new AstOperator();
-        toReturn.astOperator = operator.tokenString;
+        toReturn.astOperatorContent = operator.tokenString;
 
         return toReturn;
     }
@@ -221,7 +229,15 @@ public class Parser {
 
         } else {
 
-            toReturn.astDigitBeforeComma = parseNumber(new ArrayList<> (decimalTokens.subList(0, positionOfDecimalPoint - 1)));
+
+            try {
+
+                toReturn.astDigitBeforeComma = parseNumber(new ArrayList<>(decimalTokens.subList(0, positionOfDecimalPoint - 1)));
+
+            } catch (IllegalArgumentException illegalArgumentException) {
+                throw new Exceptions.ParserException("String contains invalid char");
+            }
+
         }
 
 
diff --git a/Aufgabe4/Plotter.java b/Aufgabe4Maven/src/Plotter.java
similarity index 100%
rename from Aufgabe4/Plotter.java
rename to Aufgabe4Maven/src/Plotter.java
diff --git a/Aufgabe4/TokenType.java b/Aufgabe4Maven/src/TokenType.java
similarity index 100%
rename from Aufgabe4/TokenType.java
rename to Aufgabe4Maven/src/TokenType.java
diff --git a/Aufgabe4/ValuesToDraw.java b/Aufgabe4Maven/src/ValuesToDraw.java
similarity index 100%
rename from Aufgabe4/ValuesToDraw.java
rename to Aufgabe4Maven/src/ValuesToDraw.java
diff --git a/Aufgabe4/expressions.txt b/Aufgabe4Maven/src/expressions.txt
similarity index 100%
rename from Aufgabe4/expressions.txt
rename to Aufgabe4Maven/src/expressions.txt
diff --git a/Aufgabe4/main.java b/Aufgabe4Maven/src/main.java
similarity index 94%
rename from Aufgabe4/main.java
rename to Aufgabe4Maven/src/main.java
index dd2853f..4442789 100644
--- a/Aufgabe4/main.java
+++ b/Aufgabe4Maven/src/main.java
@@ -1,11 +1,10 @@
 import java.io.*;
-import java.lang.reflect.Array;
 import java.util.ArrayList;
 import java.util.Scanner;
 
 public class main {
 
-    public static void main(String[] args) throws IOException {
+    public static void main(String[] args) throws Exception {
 
 
 
@@ -13,7 +12,7 @@ public class main {
 
         ArrayList<String> stringsFromFile = new ArrayList<>();
 
-        String filePath = "./Aufgabe4/expressions.txt";
+        String filePath = "./Aufgabe4Maven/src/expressions.txt";
 
         Scanner scan = null;
         try {
@@ -116,7 +115,7 @@ public class main {
         }
 
         printAst(astExpression.astBinaryOp.astExpression1);
-        System.out.print(astExpression.astBinaryOp.astOperator.astOperator);
+        System.out.print(astExpression.astBinaryOp.astOperator.astOperatorContent);
         printAst(astExpression.astBinaryOp.astExpression2);
 
     }
diff --git a/Aufgabe4/test.java b/Aufgabe4Maven/src/test.java
similarity index 100%
rename from Aufgabe4/test.java
rename to Aufgabe4Maven/src/test.java
diff --git a/Aufgabe4Maven/tests/LexerTest.java b/Aufgabe4Maven/tests/LexerTest.java
new file mode 100644
index 0000000..29f24ac
--- /dev/null
+++ b/Aufgabe4Maven/tests/LexerTest.java
@@ -0,0 +1,60 @@
+import org.junit.Test;
+import org.junit.jupiter.api.DisplayName;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.stream.IntStream;
+
+public class LexerTest {
+
+    @Test
+    @DisplayName("simpleExpression")
+    public void testSimpleExpression() {
+
+        Lexer lexer = new Lexer();
+
+        String expression = "5";
+
+        ArrayList<Token> lexResult = lexer.lex(expression);
+
+        ArrayList<Token> lexExpectedResult = new ArrayList<>();
+        lexExpectedResult.add(new Token(TokenType.number, "5"));
+
+
+        assertEquals(lexExpectedResult.get(0).tokenType, lexResult.get(0).tokenType);
+        assertEquals(lexExpectedResult.get(0).tokenString, lexResult.get(0).tokenString);
+    }
+
+    @Test
+    public void testComplicatedExpression() {
+        Lexer lexer = new Lexer();
+
+        String expression2 = "((22+3x)*5/3)";
+        ArrayList<Token> lexResult2 = lexer.lex(expression2);
+
+        ArrayList<Token> lexExpectedResult2 = new ArrayList<>();
+        lexExpectedResult2.add(new Token(TokenType.special, "("));
+        lexExpectedResult2.add(new Token(TokenType.special, "("));
+        lexExpectedResult2.add(new Token(TokenType.number, "22"));
+        lexExpectedResult2.add(new Token(TokenType.special, "+"));
+        lexExpectedResult2.add(new Token(TokenType.number, "3"));
+        lexExpectedResult2.add(new Token(TokenType.var, "x"));
+        lexExpectedResult2.add(new Token(TokenType.special, ")"));
+        lexExpectedResult2.add(new Token(TokenType.special, "*"));
+        lexExpectedResult2.add(new Token(TokenType.number, "5"));
+        lexExpectedResult2.add(new Token(TokenType.special, "/"));
+        lexExpectedResult2.add(new Token(TokenType.number, "3"));
+        lexExpectedResult2.add(new Token(TokenType.special, ")"));
+
+        for (int i = 0; i < lexResult2.size() ; i++) {
+            assertEquals(lexResult2.get(i).getTokenString(), lexExpectedResult2.get(i).getTokenString());
+            assertEquals(lexResult2.get(i).getTokenType(), lexExpectedResult2.get(i).getTokenType());
+        }
+
+    }
+
+
+
+}
+
diff --git a/out/production/inf3_git/Token.class b/out/production/inf3_git/Token.class
deleted file mode 100644
index 6ac75ca8d00a94234fb7504e3c701205235d5dfa..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 832
zcmZ{i&rZTX5XQd++6t6{2&mv6xB(h@01OusPecz85|0HNEMhUGnD|zjNK8EV06vs)
zW?P^Nrs;HdcIKPk%=YX1;}bv=l>{P)YKZAjpbBJ0=9AeNo6fLt-5*&4Pe47l9ouUO
zM60!499xKMNa#pH7f`yBd&?1sd;IM_KUxCGwsi8Q$>D~MG&1CuF&)pfouNRsy{hE<
zngZo&D0e-e))R<bOm3-2x@|kw)$E~fxm~kACQr6K8JOdq>Ds&xoH6gto(gEbELG5l
zmbb(cNL6d0igY~vb!>!rxVo`OU$l`Ufenoq3!Oz=zPcX9f{D&#<_@e&n_EaovNP60
zg(erFE8>?%O%^;xvWk4SK`qnjhVPHh>hBQslR32d=^Uw7az(I1Hj5Zpl`P#HJqF3;
z$W!*ykVk=bEY4+wTydcYt#`2(lxfhH&y@Nbv=>_V;;M8SQqWIU0zrX&6ocdzMROmj
z<XfTfzsG<IfihCTk6I$B0g^xo2Z2@?B=r}huo2`CN1H%GGx9--1XB73geSriIF_xK
Fe*nj`ht~iA

diff --git a/out/production/inf3_git/TokenType.class b/out/production/inf3_git/TokenType.class
deleted file mode 100644
index f51f9e10ede5de0de035d649744243b0ba634ef8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 971
zcmZuv?@!ZU5PsgZUAIzTR%C)q6j9cpn^W*h7lI*>kSy|{bIIbTceT!9=}7k@@xRiM
z2+?Tx>>p*k_oYG!Zpq%=-E()(b9cZ0eE$W&!7CjZhJ364$&Xr}kNrFtR1+Gq4B2RO
z)b(SAspe(e5rCYDyZ|U;9t(TQgeh!&aO`^l4~1{W#4HNrTW!B?zTI^h%y+3W1}xmx
zQ7|!wI}Dl^_9LHRu533C`Iy&29`$Mm-9z6SItGfkt7E~$BJNS;E5I%>q!wcyj{JiU
z44dUt_D;wL11IHhhj9?~oOB0KK-MprxQ}Jh+z6szxWzD^E|p~N+wB}QgVdFB$md{+
zzmH8k!I}^%X$**9*-lHPqW>c5PX9froNWe?|3(hC#k(PSmjBbuPK}GfYW6)Iws{<g
zj3iBs_z`7WH$~DGhaUqXlXrt&#D}Apa7x*3)Akx(n20Q;62&MQsg_#~gW>i^vFGmv
zg5%8P5mdznw(BImNJpe@FNk{q=%ureFP#HWSQIBf2#x$@tP$QOYlU9%F(#P)hFj;b
zzL3RGq2H{G5o=oYdV=3TMtTj4Rn9Pf4kqxKYxt++F)vVfhN_IyJ_#i{)}hcB&@1ap
zr&#(b!|8Tc={jnHI-W~Ry<mvtCPZpb$qN*-KfyZ61d7{HC(zxFHlb17RFT6A>V2Vl
uFG;Tcpj_*La*Bs1P^7V<N<){%BTX8{8CFj)EvR0fOeUfB5*rlDVDm4PO0@w1

diff --git a/out/production/inf3_git/main.class b/out/production/inf3_git/main.class
deleted file mode 100644
index a4e8897c9a16d33fbd487695fe33cf6e329876c6..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 4310
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

-- 
GitLab