From 274f633f2cd966b4ac8ca2155747c6a4a036bc86 Mon Sep 17 00:00:00 2001 From: raj_mathe Date: Mon, 18 Apr 2022 19:16:28 +0200 Subject: [PATCH] master > master: code-py - unittests --- code/python/tests/__init__.py | 0 code/python/tests/conftest.py | 26 ++++++ code/python/tests/core/__init__.py | 0 code/python/tests/core/log.py | 17 ++++ code/python/tests/test_core/__init__.py | 0 code/python/tests/test_core/conftest.py | 21 +++++ code/python/tests/test_core/test_log.py | 21 +++++ code/python/tests/test_graphs/__init__.py | 0 code/python/tests/test_graphs/conftest.py | 24 +++++ code/python/tests/test_graphs/test_graph.py | 60 ++++++++++++ code/python/tests/test_graphs/test_tarjan.py | 98 ++++++++++++++++++++ code/python/tests/test_stacks/__init__.py | 0 code/python/tests/test_stacks/conftest.py | 15 +++ code/python/tests/test_stacks/test_stack.py | 63 +++++++++++++ 14 files changed, 345 insertions(+) create mode 100644 code/python/tests/__init__.py create mode 100644 code/python/tests/conftest.py create mode 100644 code/python/tests/core/__init__.py create mode 100644 code/python/tests/core/log.py create mode 100644 code/python/tests/test_core/__init__.py create mode 100644 code/python/tests/test_core/conftest.py create mode 100644 code/python/tests/test_core/test_log.py create mode 100644 code/python/tests/test_graphs/__init__.py create mode 100644 code/python/tests/test_graphs/conftest.py create mode 100644 code/python/tests/test_graphs/test_graph.py create mode 100644 code/python/tests/test_graphs/test_tarjan.py create mode 100644 code/python/tests/test_stacks/__init__.py create mode 100644 code/python/tests/test_stacks/conftest.py create mode 100644 code/python/tests/test_stacks/test_stack.py diff --git a/code/python/tests/__init__.py b/code/python/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/code/python/tests/conftest.py b/code/python/tests/conftest.py new file mode 100644 index 0000000..953327c --- /dev/null +++ b/code/python/tests/conftest.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# IMPORTS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from unittest import TestCase; +from pytest import mark; +from pytest import fixture; + +from tests.core.log import *; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# CONSTANTS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# FIXTURES +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +@fixture(scope='module') +def test(): + return TestCase(); diff --git a/code/python/tests/core/__init__.py b/code/python/tests/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/code/python/tests/core/log.py b/code/python/tests/core/log.py new file mode 100644 index 0000000..9d555cc --- /dev/null +++ b/code/python/tests/core/log.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# IMPORTS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# METHODS - logging +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +def log(*lines: str): + with open('logs/debug.log', 'a') as fp: + for line in lines: + print(line, end='\n', file=fp); diff --git a/code/python/tests/test_core/__init__.py b/code/python/tests/test_core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/code/python/tests/test_core/conftest.py b/code/python/tests/test_core/conftest.py new file mode 100644 index 0000000..09cfa75 --- /dev/null +++ b/code/python/tests/test_core/conftest.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# IMPORTS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from pytest import mark; +from pytest import fixture; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# CONSTANTS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# FIXTURES +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# diff --git a/code/python/tests/test_core/test_log.py b/code/python/tests/test_core/test_log.py new file mode 100644 index 0000000..e36299a --- /dev/null +++ b/code/python/tests/test_core/test_log.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# IMPORTS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from pytest import mark; +from pytest import fixture; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# FIXTURES +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Test logging +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# diff --git a/code/python/tests/test_graphs/__init__.py b/code/python/tests/test_graphs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/code/python/tests/test_graphs/conftest.py b/code/python/tests/test_graphs/conftest.py new file mode 100644 index 0000000..83cbdfe --- /dev/null +++ b/code/python/tests/test_graphs/conftest.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# IMPORTS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from unittest import TestCase; +from pytest import mark; +from pytest import fixture; + +from tests.core.log import *; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# CONSTANTS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# FIXTURES +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# diff --git a/code/python/tests/test_graphs/test_graph.py b/code/python/tests/test_graphs/test_graph.py new file mode 100644 index 0000000..bff35c2 --- /dev/null +++ b/code/python/tests/test_graphs/test_graph.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# IMPORTS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from contextlib import nullcontext as does_not_raise +from collections import Counter; +from pytest import mark; +from pytest import fixture; +from unittest import TestCase; + +from src.graphs.graph import *; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# FIXTURES +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +@fixture(scope='module') +def graph1() -> Graph: + return Graph( + nodes=[1,2,3,4,5,6,7,8], + edges=[(1,2), (1, 3), (2,3), (3,4), (4, 5), (5, 6), (6, 2), (6, 7), (6, 8)], + ); + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Test Graph +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +@mark.usefixtures('test') +def test_graph_creation(test: TestCase): + with does_not_raise(): + G = Graph( + [5, 7, 8], + [(5,7), (7, 8)] + ); + test.assertEqual(len(G), 3); + G = Graph( + ["5", "7", "8", "10"], + [("5", "7"), ("7", "8")] + ); + test.assertEqual(len(G), 4); + G = Graph(nodes=[], edges=[]); + test.assertEqual(len(G), 0); + +@mark.usefixtures('test', 'graph1') +def test_graph_subgraph(test: TestCase, graph1: Graph): + sub_gph = graph1.subgraph([2,4,5,6,8]); + test.assertCountEqual(sub_gph.edges, [(6,2), (4,5), (5,6), (6,8)]); + +@mark.usefixtures('test', 'graph1') +def test_graph_successors_and_predecessors(test: TestCase, graph1: Graph): + test.assertCountEqual(graph1.successors(1), [2, 3]); + test.assertEqual(len(graph1.successors(8)), 0); + test.assertCountEqual(graph1.successors(6), [2, 7, 8]); + + test.assertEqual(len(graph1.predecessors(1)), 0); + test.assertCountEqual(graph1.predecessors(8), [6]); + test.assertCountEqual(graph1.predecessors(6), [5]); diff --git a/code/python/tests/test_graphs/test_tarjan.py b/code/python/tests/test_graphs/test_tarjan.py new file mode 100644 index 0000000..d20e6b4 --- /dev/null +++ b/code/python/tests/test_graphs/test_tarjan.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# IMPORTS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from contextlib import nullcontext as does_not_raise +from collections import Counter; +from pytest import mark; +from pytest import fixture; +from pytest import lazy_fixture; +from unittest import TestCase; + +from src.local.typing import *; +from src.graphs.graph import *; +from src.graphs.tarjan import *; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# FIXTURES +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +@fixture(scope='module') +def graph1() -> Graph: + return Graph( + nodes=[1,2,3,4], + edges=[(1,2), (2,4), (4,2)], + ); + +@fixture(scope='module') +def graph2() -> Graph: + return Graph( + nodes=[1,2,3,4,5,6,7], + edges=[(1,2), (1,3), (2,3), (3,4), (4,5), (5,2), (5,6), (5,7), (6,7)], + ); + +@fixture(scope='module') +def graph3() -> Graph: + return Graph( + nodes=[1,2,3,4,5,6,7,8], + edges=[ + (1,2), + (1,3), + (2,4), + (2,5), + (3,5), + (3,6), + (3,8), + (4,5), + (4,7), + (5,1), + (5,8), + (6,8), + (7,8), + (8,6), + ], + ); + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Test Tarjan-Algorithm +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +@mark.parametrize( + ('G', 'expected'), + [ + (lazy_fixture('graph1'), [[1], [3], [2,4]]), + (lazy_fixture('graph2'), [[1], [6], [7], [2,3,4,5]]), + (lazy_fixture('graph3'), [[1,2,3,4,5], [7], [6,8]]), + ], +) +@mark.usefixtures('test') +def test_tarjan(test, G, expected): + components = tarjan_algorithm(G, False); + assert_components_eq(test, components, expected); + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# AUXILIARY METHODS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +def assert_components_eq(test: TestCase, components1: list[list[Any]], components2: list[list[Any]]): + result = check_components_eq(test, components1, components2); + test.assertTrue(result); + +def check_components_eq(test: TestCase, components1: list[list[Any]], components2: list[list[Any]]) -> bool: + if len(components1) != len(components2): + return False; + for component1 in components1: + found = False; + for component2 in components2: + try: + test.assertCountEqual(component1, component2); + found = True; + break; + except: + continue; + if not found: + return False; + return True; diff --git a/code/python/tests/test_stacks/__init__.py b/code/python/tests/test_stacks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/code/python/tests/test_stacks/conftest.py b/code/python/tests/test_stacks/conftest.py new file mode 100644 index 0000000..ca2f70a --- /dev/null +++ b/code/python/tests/test_stacks/conftest.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# IMPORTS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from pytest import mark; +from pytest import fixture; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# FIXTURES +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# diff --git a/code/python/tests/test_stacks/test_stack.py b/code/python/tests/test_stacks/test_stack.py new file mode 100644 index 0000000..e8f2514 --- /dev/null +++ b/code/python/tests/test_stacks/test_stack.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# IMPORTS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from contextlib import nullcontext as does_not_raise +import pytest; +from pytest import mark; +from unittest import TestCase; + +from src.stacks.stack import Stack; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Fixtures +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +def format_data_for_display(data): + return [ '{given_name} {family_name}: {title}'.format(**row) for row in data ]; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Test stack +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +@mark.usefixtures('test') +def test_stack_initialisation(test: TestCase): + stack = Stack(); + test.assertEqual(len(stack), 0); + +@mark.usefixtures('test') +def test_stack_push(test: TestCase): + stack = Stack(); + test.assertEqual(len(stack), 0); + stack.push('hallo'); + test.assertEqual(len(stack), 1); + stack.push('welt'); + test.assertEqual(len(stack), 2); + stack.push('!'); + test.assertEqual(len(stack), 3); + +@mark.usefixtures('test') +def test_stack_no_error(test: TestCase): + stack = Stack(); + stack.push('hallo'); + stack.push('welt'); + stack.push('!'); + with does_not_raise(): + stack.pop(); + stack.pop(); + stack.pop(); + +@mark.usefixtures('test') +def test_stack_error_po(test: TestCase): + stack = Stack(); + stack.push('hallo'); + stack.push('welt'); + stack.push('!'); + with pytest.raises(Exception): + stack.pop(); + stack.pop(); + stack.pop(); + stack.pop();