From 3c2e48ccde7e5cb7cdb99d59ae3c9b0e7916ac91 Mon Sep 17 00:00:00 2001 From: raj_mathe Date: Thu, 6 May 2021 12:44:29 +0200 Subject: [PATCH] master > master: struktur + unit tests --- code/.gitignore | 8 +- code/README.md | 65 ++++++++++ code/{ => aussagenlogik}/__init__.py | 0 code/aussagenlogik/rekursion.py | 79 ++++++++++++ code/{ => aussagenlogik}/schema.py | 2 +- code/data.env | 9 ++ code/main.py | 123 ++++++------------ code/requirements | 1 + code/run.sh | 22 +++- code/test.sh | 38 ++++++ code/utests/__init__.py | 0 code/utests/u_rekursion.py | 186 +++++++++++++++++++++++++++ 12 files changed, 442 insertions(+), 91 deletions(-) create mode 100644 code/README.md rename code/{ => aussagenlogik}/__init__.py (100%) create mode 100644 code/aussagenlogik/rekursion.py rename code/{ => aussagenlogik}/schema.py (98%) create mode 100644 code/data.env create mode 100755 code/test.sh create mode 100644 code/utests/__init__.py create mode 100644 code/utests/u_rekursion.py diff --git a/code/.gitignore b/code/.gitignore index b6b3640..eb7228e 100644 --- a/code/.gitignore +++ b/code/.gitignore @@ -1,6 +1,12 @@ * !/.gitignore -!/*.py +!/README.md !/run.sh +!/test.sh + +!/data.env !/requirements +!/aussagenlogik +!/utests +!/**/*.py diff --git a/code/README.md b/code/README.md new file mode 100644 index 0000000..bd7e3e3 --- /dev/null +++ b/code/README.md @@ -0,0 +1,65 @@ +# Code # + +Die Inhalte dieses Ordners sind absolut **kein Pflichtbestandteil** des Kurses. + +Diese dienen nur zur Demonstration / konkreten Verwirklichung von Verfahren, +die im Kurs auftauchen. Für Wissbegierige mit auch grundlegenden Programmierkenntnissen bietet sich dies als Möglichkeit, um sich selbst zu überzeugen, dass strukturelle Rekursion funktioniert. + +Der Gebrauch dieser Skripte unterliegt der Eigenverantwortung von Studierenden. + +Da ich kein Informatiker bin, sind auch einige Aspekt bestimmt nicht optimal programmiert/strukturiert. + +## Systemvoraussetzungen ## + +- bash (auch bash-for-windows). +- python (mind. 3.9.x) + +## Voreinstellungen ## + +- In einer bash-console zu diesem Ordner navigieren und folgenden Befehl ausführen: + ```bash + chmod +x run.sh test.sh + ## oder + chmod +x *.sh + ``` +- In `run.sh` gibt es eine Zeile, die zur Ausführung der Python-Skripte notwendigen Module über PIP installieren lässt. (Die Liste der Packages findet man in der Datei `requirements`). Diese Zeile kann man ruhig nach der ersten Ausführung rauskommentieren. + +## Daten ## + +In `data.env` kann man Daten (aktuell: auszuwertenden Ausdruck + Interpretation/Modell) eintragen. Man beachte dabei die Syntax. + +## Gebrauchshinweise ## + +In einer bash-console zu diesem Ordner navigieren und +```bash +./run.sh +## oder (für Linux) +python3 main.py +## oder (für Windows) +py -3 main.py +``` +ausführen. +Man kann natürlich alles ohne bash machen, wenn man PyCharm o.Ä. besitzt. + +## Offene Challenges ## + +In der Datei `aussagenlogik/rekursion.py` (relativ zu diesem Ordner) findet man mehrere leere Methoden (mit dem Kommentar `## Herausforderung...`). Wer es mag, kann versuchen, an seinem Rechner diese Methoden zu definieren und auszuprobieren. + +## Händisch testen ### + +Probiere es mit Stift-und-Zettel und anhand von Beispielen die Werte händisch zu berechnen. Vergleiche dies mit den durch den Code rekursiv berechneten Werten. Stimmt alles überein? + +### Automatisierte Tests ### + +Wer etwas standardisierter seine Methoden testen will, kann automatisiertes Testing tätigen. Diese Tests sind im Unterordner `utests` eingetragen. + +- In der Console +- In `utests/u_rekursion.py` beim relevanten Testteil eine oder mehrere der Zeilen + ```python + @unittest.skip('Methode noch nicht implementiert') + ``` + rauskommentieren/löschen. + +Jetzt `test.sh` ausführen. Die unittests testen Methoden gegen mehrere vorkonstruierte Testfälle samt erwarteten Ergebnissen geprüft. Sollten einige Tests scheitern, dann Fehlermeldung durchlesen,und Methode entsprechend der Kritik überarbeiten. + +Die geschriebenen Unittests sind natürlich nicht ausführlich. Man kann diese nach Bedarf ergänzen. Am sinnvollsten baut man welche, die wirklich scheitern können, sonst sagen die Tests nichts aus. diff --git a/code/__init__.py b/code/aussagenlogik/__init__.py similarity index 100% rename from code/__init__.py rename to code/aussagenlogik/__init__.py diff --git a/code/aussagenlogik/rekursion.py b/code/aussagenlogik/rekursion.py new file mode 100644 index 0000000..cc8bf92 --- /dev/null +++ b/code/aussagenlogik/rekursion.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# IMPORTS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from __future__ import annotations; +from lark import Tree; +from typing import List; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# GLOBALE KONSTANTEN +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# METHODEN +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +def rekursiv_atoms(fml: Tree) -> List[str]: + ## Herausforderung: schreibe diese Funktion! + return []; + +def rekursiv_depth(fml: Tree) -> int: + ## Herausforderung: schreibe diese Funktion! + return 0; + +def rekursiv_length(fml: Tree) -> int: + ## Herausforderung: schreibe diese Funktion! + return 0; + +def rekursiv_parentheses(fml: Tree) -> int: + ## Herausforderung: schreibe diese Funktion! + return 0 + +def rekursiv_eval(fml: Tree, I: List[str]) -> int: + teilfml = getTeilformeln(fml); + if fml.data in ['atom', 'beliebig']: + name = getText(fml); + return 1 if (name in I) else 0; + elif fml.data == 'wahr': + return 1; + elif fml.data == 'falsch': + return 0; + elif fml.data == 'negation': + val1 = rekursiv_eval(teilfml[0], I); + return 1 - val1; + elif fml.data == 'konjunktion': + val1 = rekursiv_eval(teilfml[0], I); + val2 = rekursiv_eval(teilfml[1], I); + return min(val1, val2); + elif fml.data == 'disjunktion': + val1 = rekursiv_eval(teilfml[0], I); + val2 = rekursiv_eval(teilfml[1], I); + return max(val1, val2); + elif fml.data == 'implikation': + val1 = rekursiv_eval(teilfml[0], I); + val2 = rekursiv_eval(teilfml[1], I); + return 0 if val1 == 1 and val2 == 0 else 1; + raise Exception('Evaluation nicht möglich!'); + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# HILFSMETHODEN +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +def getText(fml: Tree) -> str: + text = fml.children[0]; + if isinstance(text, str): + return text; + raise Exception('Konnte Textinhalt nicht ablesen!'); + +def getTeilformeln(fml: Tree) -> List[Tree]: + return [ + part for part in fml.children + if isinstance(part, Tree) + and not part.data == 'junktor' + ]; diff --git a/code/schema.py b/code/aussagenlogik/schema.py similarity index 98% rename from code/schema.py rename to code/aussagenlogik/schema.py index ccb778e..cf05f7a 100644 --- a/code/schema.py +++ b/code/aussagenlogik/schema.py @@ -13,7 +13,7 @@ from lark import Lark; from lark import Tree; # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# GLOBAL CONSTANTS +# GLOBALE KONSTANTEN # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## lexer diff --git a/code/data.env b/code/data.env new file mode 100644 index 0000000..1d4bb50 --- /dev/null +++ b/code/data.env @@ -0,0 +1,9 @@ +# expr = "A0" +# expr = "! A0" +# expr = "( A0 && A1 )" +# expr = "( A0 || A1 )" +# expr = "( A0 -> A1 )" +expr = "( A0 -> ((A0 && A3) || ! A2) )" +# expr = "( A0 -> ((A0 && A3) || A2) )" +# expr = "(( {G} || !{G} ) -> A5)" +interpretation = "[ 'A0', 'A2' ]" diff --git a/code/main.py b/code/main.py index 6fe8bbf..cd87a1a 100644 --- a/code/main.py +++ b/code/main.py @@ -8,43 +8,65 @@ from __future__ import annotations; import os; import sys; -sys.tracebacklimit = 0; +# sys.tracebacklimit = 0; +from dotenv import dotenv_values; from lark import Tree; from textwrap import dedent; from typing import List; sys.path.insert(0, os.getcwd()); -from schema import string_to_parts; +from aussagenlogik.schema import string_to_parts; +from aussagenlogik.rekursion import rekursiv_eval; +from aussagenlogik.rekursion import rekursiv_atoms; +from aussagenlogik.rekursion import rekursiv_depth; +from aussagenlogik.rekursion import rekursiv_length; +from aussagenlogik.rekursion import rekursiv_parentheses; # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# GLOBAL CONSTANTS +# GLOBALE KONSTANTEN # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# zeichenkette = 'A0'; -# zeichenkette = '! A0'; -# zeichenkette = '( A0 && A1 )'; -# zeichenkette = '( A0 || A1 )'; -# zeichenkette = '( A0 -> A1 )'; -zeichenkette = '( A0 -> ((A0 && A3) || ! A2) )'; -# zeichenkette = '( A0 -> ((A0 && A3) || A2) )'; -# zeichenkette = '(( {G} || !{G} ) -> A5)'; - -I = ['A0', 'A2']; +DATA_ENV = "data.env"; # Pfad zu Daten. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # HAUPTVORGANG # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def main(): - tree = string_to_parts(zeichenkette); + ## Daten einlesen: + expr, I = getData(); + ## Formel in Teilformeln zerlegen: + tree = string_to_parts(expr); + ## Methoden ausführen: + results = dict( + eval = rekursiv_eval(tree, I), + atoms = rekursiv_atoms(tree), + d = rekursiv_depth(tree), + l = rekursiv_length(tree), + p = rekursiv_parentheses(tree), + ); + ## Resultate anzeigen: + display_results(expr, tree, I, results); + return; + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# SONSTIGE METHODEN +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +def getData(): + data = dotenv_values(dotenv_path=DATA_ENV); + expr = data['expr'] or '0'; + I = eval(data['interpretation'] or '[]'); + return expr, I; + +def display_results(expr: str, tree: Tree, I: List[str], results: dict): print(dedent( ''' Syntaxbaum von F := \033[92;1m{F}\033[0m: - '''.format( - F=zeichenkette, - ) + '''.format(F=expr) )); print(tree.pretty()); print(dedent( @@ -56,74 +78,11 @@ def main(): \033[2m#parentheses(F) = \033[94;1m{p}\033[0m; \033[91;1m<- *\033[0m \033[91;1m*\033[0m \033[2mnoch nicht implementiert!\033[0m - \033[1;2;4mChallenge:\033[0m \033[2mschreibe diese Methoden. Probiere mit Stift-und-Zettel die Methoden händisch auszuführen und vergleiche mit dem Code-Output.\033[0m - '''.format( - eval = rekursiv_eval(tree, I), - atoms = rekursiv_atoms(tree), - d = rekursiv_depth(tree), - l = rekursiv_length(tree), - p = rekursiv_parentheses(tree), - ) + \033[1;2;4mChallenge:\033[0m \033[2mschreibe diese Methoden! (siehe README.md)\033[0m + '''.format(**results) )); return; -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# SEKUNDÄRVORGÄNGE -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -def rekursiv_atoms(fml: Tree) -> List[str]: - ## Herausforderung: schreibe diese Funktion! - return []; - -def rekursiv_depth(fml: Tree) -> int: - ## Herausforderung: schreibe diese Funktion! - return 0; - -def rekursiv_length(fml: Tree) -> int: - ## Herausforderung: schreibe diese Funktion! - return 0; - -def rekursiv_parentheses(fml: Tree) -> int: - ## Herausforderung: schreibe diese Funktion! - return 0; - -def rekursiv_eval(fml: Tree, I: List[str]) -> int: - teilfml = getTeilformeln(fml); - if fml.data in ['atom', 'beliebig']: - name = fml.children[0]; - return 1 if (name in I) else 0; - elif fml.data == 'wahr': - return 1; - elif fml.data == 'falsch': - return 0; - elif fml.data == 'negation': - val1 = rekursiv_eval(teilfml[0], I); - return 1 - val1; - elif fml.data == 'konjunktion': - val1 = rekursiv_eval(teilfml[0], I); - val2 = rekursiv_eval(teilfml[1], I); - return min(val1, val2); - elif fml.data == 'disjunktion': - val1 = rekursiv_eval(teilfml[0], I); - val2 = rekursiv_eval(teilfml[1], I); - return max(val1, val2); - elif fml.data == 'implikation': - val1 = rekursiv_eval(teilfml[0], I); - val2 = rekursiv_eval(teilfml[1], I); - return 0 if val1 == 1 and val2 == 0 else 1; - raise Exception('Evaluation nicht möglich!'); - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# SONSTIGE METHODEN -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -def getTeilformeln(fml: Tree) -> List[Tree]: - return [ - part for part in fml.children - if isinstance(part, Tree) - and not part.data == 'junktor' - ]; - # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # CODE AUSFÜHREN # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/code/requirements b/code/requirements index ca73856..fd31cf0 100644 --- a/code/requirements +++ b/code/requirements @@ -1,4 +1,5 @@ lark lark-parser lark-parser[regex] +python-dotenv typing diff --git a/code/run.sh b/code/run.sh index f1cdc38..f7e4520 100755 --- a/code/run.sh +++ b/code/run.sh @@ -1,23 +1,31 @@ #!/usr/bin/env bash ################################################################################################ -# NOTE: `chmod +x *.sh` vorher ausführen, um dieses Skript benutzen zu können. +# NOTE: `chmod +x run.sh` vorher ausführen, um dieses Skript benutzen zu können. ################################################################################################ -function run_python() { +################################ +# HILFSMETHODEN +################################ + +function call_python() { [ "$OSTYPE" == "msys" ] && py -3 $@ || python3 $@; } -function run_pip() { - run_python -m pip $@; +function run_check_requirements() { + call_python -m pip install "$( cat requirements )" >> /dev/null; } -function run_check_requirements() { - run_pip install "$( cat requirements )" >> /dev/null; +function run_code() { + call_python main.py; } +################################ +# HAUPTVORGÄNGE +################################ + # Kann auskommentiert werden, wenn nötige Module schon installiert: run_check_requirements; # Code ausführen: -run_python main.py; +run_code diff --git a/code/test.sh b/code/test.sh new file mode 100755 index 0000000..a564f68 --- /dev/null +++ b/code/test.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +################################################################################################ +# NOTE: `chmod +x test.sh` vorher ausführen, um dieses Skript benutzen zu können. +################################################################################################ + +################################ +# HILFSMETHODEN +################################ + +function call_python() { + [ "$OSTYPE" == "msys" ] && py -3 $@ || python3 $@; +} + +function run_check_requirements() { + call_python -m pip install "$( cat requirements )" >> /dev/null; +} + +function run_unittests(){ + echo -e "\033[1mUNITTESTS\033[0m\n"; + local output="$(call_python -m unittest discover -v --top-level-directory "." --start-directory "utests" --pattern "u_*.py" 2>&1)"; + echo -e "$output"; + if ( echo "$output" | grep -E -q "^[[:space:]]*(FAIL:|FAILED)" ); then + echo -e "[\033[91;1mERROR\033[0m] Unit tests versagt!" && return 1; + else + echo -e "[\033[94;1mINFO\033[0m] Unit tests erfolgreich!" && return 0; + fi +} + +################################ +# HAUPTVORGÄNGE +################################ + +# Kann auskommentiert werden, wenn nötige Module schon installiert: +run_check_requirements; + +# Code testen (unittests): +run_unittests; diff --git a/code/utests/__init__.py b/code/utests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/code/utests/u_rekursion.py b/code/utests/u_rekursion.py new file mode 100644 index 0000000..8dcc69b --- /dev/null +++ b/code/utests/u_rekursion.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# IMPORTS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +import unittest; +from unittest import TestCase; + +from aussagenlogik.schema import string_to_parts; +from aussagenlogik.rekursion import rekursiv_atoms; +from aussagenlogik.rekursion import rekursiv_depth; +from aussagenlogik.rekursion import rekursiv_length; +from aussagenlogik.rekursion import rekursiv_parentheses; +from aussagenlogik.rekursion import rekursiv_eval; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# GLOBALE KONSTANTEN +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# TESTFALL Atome(·) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +@unittest.skip("Methode noch nicht implementiert") +class TestRekursivAtoms(TestCase): + def test_noduplicates(self): + fml = string_to_parts('( A4 && ( A4 || A4 ) )'); + val = sorted(rekursiv_atoms(fml)); + assert len([_ for _ in val if _ == 'A4']) == 1, 'Atome dürfen nicht mehrfach vorkommen!'; + + def test_nononatoms(self): + fml = string_to_parts('( {F} || A3 )'); + val = sorted(rekursiv_atoms(fml)); + assert 'F' not in val, 'Nichtatomare Formeln dürfen nicht vorkommen!'; + + def test_calc1(self): + fml = string_to_parts('A0'); + val = sorted(rekursiv_atoms(fml)); + assert val == ['A0'], 'computed {}'.format(val); + + def test_calc2(self): + fml = string_to_parts('((( ! A0 && A3 ) || A4 ) && A8 )'); + val = sorted(rekursiv_atoms(fml)); + assert val == ['A0', 'A3', 'A4', 'A8'], 'computed {}'.format(val); + pass; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# TESTFALL Depth(·) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +@unittest.skip("Methode noch nicht implementiert") +class TestRekursivDepth(TestCase): + def test_calc1(self): + fml = string_to_parts('A0'); + val = rekursiv_depth(fml); + assert val == 0, 'computed {}'.format(val); + + def test_calc2(self): + fml = string_to_parts('!! A8'); + val = rekursiv_depth(fml); + assert val == 2, 'computed {}'.format(val); + + def test_calc3(self): + fml = string_to_parts('(! A0 && A3 )'); + val = rekursiv_depth(fml); + assert val == 2, 'computed {}'.format(val); + + def test_calc4(self): + fml = string_to_parts('((( ! A0 && A3 ) || A4 ) && A8 )'); + val = rekursiv_depth(fml); + assert val == 4, 'computed {}'.format(val); + + def test_calc5(self): + fml = string_to_parts('! ((( ! A0 && A3 ) || A4 ) && A8 )'); + val = rekursiv_depth(fml); + assert val == 5, 'computed {}'.format(val); + pass; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# TESTFALL Länge(·) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +@unittest.skip("Methode noch nicht implementiert") +class TestRekursivLength(TestCase): + def test_calc1(self): + fml = string_to_parts('A0'); + val = rekursiv_length(fml); + assert val == 1, 'computed {}'.format(val); + + def test_calc2(self): + fml = string_to_parts('!! A8'); + val = rekursiv_length(fml); + assert val == 3, 'computed {}'.format(val); + + def test_calc3(self): + fml = string_to_parts('(! A0 && A3 )'); + val = rekursiv_length(fml); + assert val == 4, 'computed {}'.format(val); + + def test_calc4(self): + fml = string_to_parts('((( ! A0 && A3 ) || A4 ) && A8 )'); + val = rekursiv_length(fml); + assert val == 8, 'computed {}'.format(val); + + def test_calc5(self): + fml = string_to_parts('! ((( ! A0 && A3 ) || A4 ) && A8 )'); + val = rekursiv_length(fml); + assert val == 9, 'computed {}'.format(val); + pass; + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# TESTFALL Anzahl Klammern(·) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +@unittest.skip("Methode noch nicht implementiert") +class TestRekursivParentheses(TestCase): + def test_calc1(self): + fml = string_to_parts('A0'); + val = rekursiv_parentheses(fml); + assert val == 0, 'computed {}'.format(val); + + def test_calc2(self): + fml = string_to_parts('!! A8'); + val = rekursiv_parentheses(fml); + assert val == 0, 'computed {}'.format(val); + + def test_calc3(self): + fml = string_to_parts('(! A0 && A3 )'); + val = rekursiv_parentheses(fml); + assert val == 2, 'computed {}'.format(val); + + def test_calc4(self): + fml = string_to_parts('((( ! A0 && A3 ) || A4 ) && A8 )'); + val = rekursiv_parentheses(fml); + assert val == 6, 'computed {}'.format(val); + + def test_calc5(self): + fml = string_to_parts('! ((( ! A0 && A3 ) || A4 ) && A8 )'); + val = rekursiv_parentheses(fml); + assert val == 6, 'computed {}'.format(val); + pass; + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# TESTFALL eval(·, ·) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# @unittest.skip("Methode noch nicht implementiert") +class TestRekursivEval(TestCase): + def test_literale(self): + fml = string_to_parts('A0'); + val = rekursiv_eval(fml, [ 'A0' ]); + assert val == 1; + fml = string_to_parts('A0'); + val = rekursiv_eval(fml, []); + assert val == 0; + fml = string_to_parts('! A0'); + val = rekursiv_eval(fml, [ 'A0' ]); + assert val == 0; + fml = string_to_parts('! A0'); + val = rekursiv_eval(fml, []); + assert val == 1; + + def test_complex1(self): + fml = string_to_parts('( ! A0 || (( A0 && A3 ) || A2 ) )'); + val = rekursiv_eval(fml, [ 'A0', 'A2' ]); + assert val == 1; + val = rekursiv_eval(fml, [ 'A0', 'A3' ]); + assert val == 1; + val = rekursiv_eval(fml, [ 'A0' ]); + assert val == 0; + val = rekursiv_eval(fml, [ 'A4', 'A8' ]); + assert val == 1; + + def test_complex2(self): + fml = string_to_parts('( ! A0 || (( A0 && A3 ) || ! A2) )'); + val = rekursiv_eval(fml, [ 'A0', 'A2' ]); + assert val == 0; + val = rekursiv_eval(fml, [ 'A0', 'A3' ]); + assert val == 1; + pass;