Compare commits

..

2 Commits

Author SHA1 Message Date
66711f61dd tests for a and b 2025-03-21 00:37:14 +01:00
5f1cc196c8 tests for a and b 2025-03-21 00:36:58 +01:00
5 changed files with 497 additions and 964 deletions

23
ex6_recursion.md Normal file
View File

@ -0,0 +1,23 @@
# Aufgabe 6 - Rekursion - 20P
## a - `sum_of_subtree` - 10P
- Basisfall `None` [3P]
- Rekursiver Fall:
- Aufruf der Funktion auf `left` und `right` [3P]
- Addition der Teilbaum Summen [1P]
- Setzen von `tree.mark` [2P]
- Rückgabe der Summe [1P]
- Pattern Matching nicht verwendet [0P]
## b - `cut_at` - 10P
- Basisfall `None` [3P]
- Basisfall `mark == at` [3P]
- Dieser Fall konnte auch mit dem Rekursiven Fall kombiniert werden (`if mark == at` ist okay :))
- Rekursiver Fall:
- Aufruf der Funktion auf `left` und `right` [3P]
- Rückgabe des neuen Baumes [1P]
- Pattern Matching nicht verwendet [0P]

49
ex6_recursion.py Normal file
View File

@ -0,0 +1,49 @@
# Aufgabe 6: Rekursion
from dataclasses import dataclass
from typing import Optional
@dataclass
class Node[T]:
mark: T
left: Optional["Node[T]"] = None
right: Optional["Node[T]"] = None
type BTree[T] = Optional[Node[T]]
# a)
def sum_of_subtree(tree: BTree[int]) -> int:
match tree:
case None:
return 0
case Node(_, left, right):
tree.mark += sum_of_subtree(left) + sum_of_subtree(right)
return tree.mark
# b)
def cut_at[T](tree: BTree[T], at: T) -> BTree[T]:
match tree:
case None:
return None
case Node(mark, _, _) if mark == at:
return None
case Node(mark, left, right): # f(mark)
return Node(mark, cut_at(left, at), cut_at(right, at))
if __name__ == "__main__":
t1 = None
assert sum_of_subtree(t1) == 0
assert t1 is None
t3 = Node(1, Node(2, Node(3), Node(4)), Node(5, Node(6)))
assert sum_of_subtree(t3) == 21
assert t3 == Node(21, Node(9, Node(3), Node(4)), Node(11, Node(6)))
assert cut_at(None, 42) is None
t = Node(1, Node(2, Node(3), Node(4)), Node(3, Node(3), Node(6)))
assert cut_at(t, 1) is None
assert cut_at(t, 3) == Node(1, Node(2, None, Node(4)))

BIN
exam.pdf Normal file

Binary file not shown.

964
test14.py
View File

@ -1,964 +0,0 @@
from dataclasses import dataclass, field, fields, is_dataclass, InitVar
from types import NoneType, FunctionType, GenericAlias
from typing import get_args, Callable, Iterable, Iterator, Type, Optional, TypeAliasType, ForwardRef, Any, Literal
from enum import Enum
import unittest
from unittest import mock
from unittest.mock import patch
from functools import wraps
import signal
import io
import importlib
import importlib.util
import sys
import subprocess
import os
import shutil
import re
import math
import inspect
import json
import ast
import copy
import functools
import itertools
output = ""
class TimeoutException(Exception):
pass
class Timeout:
def __init__(self, seconds, msg=None) -> None:
if msg is None:
msg = f"Test timed out after {seconds} seconds."
self.seconds = seconds
self.msg = msg
def handle_timeout(self, signal, frame):
raise TimeoutException(self.msg)
def __enter__(self):
signal.signal(signal.SIGALRM, self.handle_timeout)
signal.alarm(self.seconds)
def __exit__(self, exc_type, exc_val, exc_tb):
signal.alarm(0)
class IterablePure:
def __init__(self, i: Optional[Iterable] = None, repeat: bool = False):
if i is not None:
self.i = i
else:
def endless():
c = 0
while True:
yield c
c += 1
self.i = endless()
self.repeat = repeat
def __iter__(self):
if self.repeat:
while True:
yield from self.i
else:
yield from self.i
def resolve_type_alias(t: Type) -> Type:
while isinstance(t, TypeAliasType | GenericAlias) and hasattr(t, "__value__"):
if isinstance(t, TypeAliasType):
t = t.__value__
elif isinstance(t, GenericAlias):
t = t.__value__[*t.__args__]
return t
def check_annot(function: Callable, expected: list[Type], ret=None):
actual = function.__annotations__
if "self" in actual:
del actual["self"]
return_type = actual["return"] if "return" in actual else None
actual = list(actual.values())[:-1] if "return" in actual else list(actual.values())
for a, e in zip(actual, expected):
a = resolve_type_alias(a)
e = resolve_type_alias(e)
if a != e:
return False
return resolve_type_alias(ret) == resolve_type_alias(return_type)
def check_lambda_annotations(module, f_name: str, param_types: list[object], return_type: object = None) -> bool:
annotation = module.__annotations__[f_name]
if annotation.__name__ != 'Callable':
return False
all_types = annotation.__args__
types, ret_type = all_types[:-1], all_types[-1]
if ret_type != return_type:
return False
for param, param_type in zip(types, param_types):
while isinstance(param, TypeAliasType):
param = param.__value__
while isinstance(param_type, TypeAliasType):
param_type = param_type.__value__
if param != param_type:
return False
return True
def check_attributes(o: object, inherited_attr: list[str], new_attr: list[str]) -> bool:
attr = [f.name for f in fields(o)]
if attr != inherited_attr + new_attr:
return False
for attr in inherited_attr:
if attr in o.__annotations__:
return False
return True
def check_no_if_used(f: Callable) -> bool:
tree = ast.parse(inspect.getsource(f))
for node in ast.walk(tree):
if isinstance(node, ast.If):
return False
return True
def check_comprehension_used(f: Callable) -> bool:
source = inspect.getsource(f)
tree = ast.parse(source)
for node in ast.walk(tree):
if isinstance(node, (ast.ListComp, ast.SetComp, ast.DictComp, ast.GeneratorExp)):
return True
return False
def check_no_sideeffects(f: Callable, *args) -> bool:
args_copy = tuple(copy.deepcopy(a) for a in args)
f(*args)
return args == args_copy
def check_function_used(f: Callable, name: str) -> bool:
source = inspect.getsource(f)
if source.startswith(4 * " "):
source = "\n".join(l[4:] for l in source.split("\n"))
return name in [c.func.id for c in ast.walk(ast.parse(source)) if isinstance(c, ast.Call) and isinstance(c.func, ast.Name)]
def check_function_not_used(f: Callable, name: str) -> bool:
source = inspect.getsource(f)
if source.startswith(4 * " "):
source = "\n".join(l[4:] for l in source.split("\n"))
return name not in [c.func.id for c in ast.walk(ast.parse(source)) if isinstance(c, ast.Call) and isinstance(c.func, ast.Name)]
def check_pattern_matching_used(f: Callable) -> bool:
source = inspect.getsource(f)
tree = ast.parse(source)
return any(isinstance(node, ast.Match) for node in ast.walk(tree))
def check_gen(g: Iterator, res: Iterable, check_end: bool = True, max: int = 100) -> bool:
if not isinstance(g, Iterator):
return False
for i, x in enumerate(res):
el = next(g)
if el != x:
return False
if i >= max:
break
if check_end:
try:
next(g)
except StopIteration:
return True
return False
return True
def check_only_one_line(f: Callable) -> bool:
if f.__name__ == '<lambda>':
return True
inspect.getsource(f)
lines = [line for line in inspect.getsource(f).split('\n') if not line.strip().startswith('#') and line.strip() != '']
return len(lines) == 2
def mock_print(*args, sep=None, end=None, **_kwargs):
global output
if sep is None:
sep = " "
if end is None:
end = "\n"
args = [str(a) for a in args]
output += str(sep.join(args)) + end
def mock_input(*arg: str):
inputs = [s for s in arg]
def input_function(arg=None):
if arg is None:
arg = ""
nonlocal inputs
if len(inputs) == 0:
raise Exception("More input asked than given")
p = inputs[0]
inputs = inputs[1:]
mock_print(arg, p, sep="")
return p
return input_function
def input_error(*arg):
raise Exception("Input is not allowed here")
@patch("builtins.print", mock_print)
@patch("builtins.input", input_error)
def check_global_statements(unit: unittest.TestCase, module_name: str):
global output
output = ""
with Timeout(2):
if module_name in sys.modules.keys():
del sys.modules[module_name]
module = importlib.import_module(module_name)
unit.assertEqual(output, "")
has_global_asserts = any(isinstance(node, ast.Assert)
for node in ast.iter_child_nodes(ast.parse(inspect.getsource(module))))
unit.assertFalse(has_global_asserts)
def no_input_test(test_function: Callable) -> Callable:
@wraps(test_function)
@patch("builtins.print", mock_print)
@patch("builtins.input", input_error)
def inner(self):
global output
output = ""
with Timeout(2):
test_function(self)
return inner
class Ex1_sequences(unittest.TestCase):
def test1_global_statements(self):
check_global_statements(self, "ex1_sequences")
@no_input_test
def test1_annot(self):
global output
output = ""
with Timeout(2):
import ex1_sequences
self.assertTrue(check_annot(ex1_sequences.count_iterations, [int, int], int))
@no_input_test
def test1_count_iterations(self):
global output
output = ""
with Timeout(2):
import ex1_sequences
self.assertEqual(ex1_sequences.count_iterations(10, 6), 1)
self.assertEqual(ex1_sequences.count_iterations(7, 6), 3)
self.assertEqual(ex1_sequences.count_iterations(4, 2), 1)
self.assertEqual(ex1_sequences.count_iterations(70, 2), 204)
self.assertEqual(ex1_sequences.count_iterations(3, 2), 3)
self.assertEqual(ex1_sequences.count_iterations(7, 4), 11)
self.assertEqual(ex1_sequences.count_iterations(37, 20), 6)
self.assertEqual(ex1_sequences.count_iterations(14, 4), 23)
self.assertEqual(ex1_sequences.count_iterations(8, 2), 2)
self.assertEqual(ex1_sequences.count_iterations(4, 3), 1)
class Ex2_dicts(unittest.TestCase):
def test2_global_statements(self):
check_global_statements(self, "ex2_dicts")
@no_input_test
def test2_annot(self):
global output
output = ""
with Timeout(2):
import ex2_dicts
self.assertTrue(check_annot(ex2_dicts.lines, [dict[int, set[str]], str], set[int]))
self.assertTrue(check_annot(ex2_dicts.invert, [dict[int, set[str]]], dict[str, set[int]]))
self.assertTrue(check_annot(ex2_dicts.add_line, [dict[int, set[str]], set[str]], None))
@no_input_test
def test2_lines(self):
global output
output = ""
with Timeout(2):
import ex2_dicts
example1 = {
1: {"Hauptbahnhof", "Paduaallee", "Stadttheater"},
2: {"Hauptbahnhof", "Stadttheater", "Hornusstraße", "Johanneskirche"},
3: {"Am Lindenwäldle", "Hauptbahnhof", "Stadttheater", "Johanneskirche"},
5: {"Europaplatz", "Stadttheater", "Am Lindenwäldle"},
}
example2 = {
1: {"stat1", "stat2", "stat3"},
3: {"stat3", "stat4"},
19: {"stat1", "stat2", "stat3", "stat4"}
}
self.assertEqual(ex2_dicts.lines(example1, "Hauptbahnhof"), {1, 2, 3})
self.assertEqual(ex2_dicts.lines(example1, "Paduaallee"), {1})
self.assertEqual(ex2_dicts.lines(example1, "Stadttheater"), {1, 2, 3, 5})
self.assertEqual(ex2_dicts.lines(example1, "Stadttheater"), {1, 2, 3, 5})
self.assertEqual(ex2_dicts.lines(example1, "Johanneskirche"), {2, 3})
self.assertEqual(ex2_dicts.lines(example1, "Hornusstraße"), {2})
self.assertEqual(ex2_dicts.lines(example1, "Am Lindenwäldle"), {3, 5})
self.assertEqual(ex2_dicts.lines(example1, "Europaplatz"), {5})
self.assertEqual(ex2_dicts.lines(example2, "stat1"), {1, 19})
self.assertEqual(ex2_dicts.lines(example2, "stat2"), {1, 19})
self.assertEqual(ex2_dicts.lines(example2, "stat3"), {1, 3, 19})
self.assertEqual(ex2_dicts.lines(example2, "stat4"), {3, 19})
self.assertEqual(ex2_dicts.lines(example1, "Anywhere"), set())
self.assertEqual(ex2_dicts.lines(example2, "Hauptbahnhof"), set())
self.assertEqual(ex2_dicts.lines({}, "Hauptbahnhof"), set())
self.assertEqual(ex2_dicts.lines({}, "Anywhere"), set())
self.assertTrue(check_no_sideeffects(ex2_dicts.lines, example1, "Hauptbahnhof"))
@no_input_test
def test2_invert(self):
global output
output = ""
with Timeout(2):
import ex2_dicts
example1 = {
1: {"Hauptbahnhof", "Paduaallee", "Stadttheater"},
2: {"Hauptbahnhof", "Stadttheater", "Hornusstraße", "Johanneskirche"},
3: {"Am Lindenwäldle", "Hauptbahnhof", "Stadttheater", "Johanneskirche"},
5: {"Europaplatz", "Stadttheater", "Am Lindenwäldle"},
}
example2 = {
1: {"stat1", "stat2", "stat3"},
3: {"stat3", "stat4"},
19: {"stat1", "stat2", "stat3", "stat4"}
}
self.assertDictEqual(ex2_dicts.invert(example1),{
'Stadttheater': {1, 2, 3, 5},
'Hauptbahnhof': {1, 2, 3},
'Paduaallee': {1},
'Johanneskirche': {2, 3},
'Hornusstraße': {2},
'Am Lindenwäldle': {3, 5},
'Europaplatz': {5}
})
self.assertDictEqual(ex2_dicts.invert(example2), {
'stat1': {1, 19},
'stat2': {1, 19},
'stat3': {1, 3, 19},
'stat4': {3, 19}
})
self.assertEqual(ex2_dicts.invert({}), {})
self.assertTrue(check_no_sideeffects(ex2_dicts.invert, example1))
@no_input_test
def test2_add_line(self):
global output
output = ""
with Timeout(2):
import ex2_dicts
example1 = {
1: {"Hauptbahnhof", "Paduaallee", "Stadttheater"},
2: {"Hauptbahnhof", "Stadttheater", "Hornusstraße", "Johanneskirche"},
3: {"Am Lindenwäldle", "Hauptbahnhof", "Stadttheater", "Johanneskirche"},
5: {"Europaplatz", "Stadttheater", "Am Lindenwäldle"},
}
example2 = {
1: {"stat1", "stat2", "stat3"},
3: {"stat3", "stat4"},
19: {"stat1", "stat2", "stat3", "stat4"}
}
ex2_dicts.add_line(
example1,
{
"Technische Fakultät",
"Hauptbahnhof",
"Stadttheater",
"Europaplatz",
"Hornusstraße",
},
)
self.assertDictEqual(example1, {
1: {"Hauptbahnhof", "Paduaallee", "Stadttheater"},
2: {"Hauptbahnhof", "Stadttheater", "Hornusstraße", "Johanneskirche"},
3: {"Am Lindenwäldle", "Hauptbahnhof", "Stadttheater", "Johanneskirche"},
4: {"Technische Fakultät", "Hauptbahnhof", "Stadttheater", "Europaplatz", "Hornusstraße"},
5: {"Europaplatz", "Stadttheater", "Am Lindenwäldle"}
})
ex2_dicts.add_line(example2, {"stat1", "stat2", "stat3"})
self.assertDictEqual(example2, {
1: {"stat1", "stat2", "stat3"},
2: {"stat1", "stat2", "stat3"},
3: {"stat3", "stat4"},
19: {"stat1", "stat2", "stat3", "stat4"}
})
ex2_dicts.add_line(example2, {"foo", "bar"})
self.assertDictEqual(example2, {
1: {"stat1", "stat2", "stat3"},
2: {"stat1", "stat2", "stat3"},
3: {"stat3", "stat4"},
4: {"foo", "bar"},
19: {"stat1", "stat2", "stat3", "stat4"}
})
example3 = {}
for i in range(1, 100):
ex2_dicts.add_line(example3, {f"stat{i}"})
for j in range(1, i + 1):
self.assertEqual(example3[j], {f"stat{j}"})
self.assertIsNone(ex2_dicts.add_line({}, {"foo"}))
class Ex3_strings(unittest.TestCase):
def test3_global_statements(self):
check_global_statements(self, "ex3_strings")
@no_input_test
def test3_annot(self):
global output
output = ""
with Timeout(2):
import ex3_strings
self.assertTrue(check_annot(ex3_strings.s2_in_s1, [str, str], bool))
self.assertTrue(check_annot(ex3_strings.split_text, [str], list[str]))
@no_input_test
def test3_s2_in_s1(self):
global output
output = ""
with Timeout(2):
import ex3_strings
self.assertTrue(ex3_strings.s2_in_s1("function", "fn") is True)
self.assertTrue(ex3_strings.s2_in_s1("function", "ufnction") is False)
self.assertTrue(ex3_strings.s2_in_s1("function", "fnn") is True)
self.assertTrue(ex3_strings.s2_in_s1("function", "fcc") is False)
self.assertTrue(ex3_strings.s2_in_s1("teststring", "tssr") is True)
self.assertTrue(ex3_strings.s2_in_s1("test", "test") is True)
self.assertTrue(ex3_strings.s2_in_s1("cons", "cs") is True)
self.assertTrue(ex3_strings.s2_in_s1("co", "oc") is False)
self.assertTrue(ex3_strings.s2_in_s1("false", "flase") is False)
self.assertTrue(ex3_strings.s2_in_s1("foo", "") is True)
self.assertTrue(ex3_strings.s2_in_s1("", "bar") is False)
@no_input_test
def test3_split_text(self):
global output
output = ""
with Timeout(2):
import ex3_strings
self.assertListEqual(ex3_strings.split_text("You're a lizard, Harry!"), [
'You', "'", 're', ' ', 'a', ' ', 'lizard', ', ', 'Harry', '!'
])
self.assertListEqual(ex3_strings.split_text("Luke! I'm your father!!"), [
'Luke', '! ', 'I', "'", 'm', ' ', 'your', ' ', 'father', '!!'
])
self.assertListEqual(ex3_strings.split_text("*Stay away from her, you $!#@!*"), [
'*', 'Stay', ' ', 'away', ' ', 'from', ' ', 'her', ', ', 'you', ' $!#@!*'
])
self.assertListEqual(ex3_strings.split_text("hello world"), ["hello", " ", "world"])
self.assertListEqual(ex3_strings.split_text("test$$case"), ["test", "$$", "case"])
self.assertListEqual(ex3_strings.split_text(""), [])
self.assertListEqual(ex3_strings.split_text("word"), ["word"])
self.assertListEqual(ex3_strings.split_text("138904642&(/%$)(=)"), ["138904642&(/%$)(=)"])
class Ex4_dataclasses(unittest.TestCase):
def test4_global_statements(self):
check_global_statements(self, "ex5_dataclasses")
@no_input_test
def test4_annot(self):
global output
output = ""
with Timeout(2):
import ex5_dataclasses
self.assertTrue(is_dataclass(ex5_dataclasses.Vehicle))
self.assertTrue(check_attributes(ex5_dataclasses.Vehicle, [], ["seats", "hp", "ccm", "weight"]))
self.assertDictEqual(ex5_dataclasses.Vehicle.__annotations__, {
"seats": int,
"hp": int,
"ccm": int,
"weight": int
})
@no_input_test
def test4_Vehicle(self):
global output
output = ""
with Timeout(2):
import ex5_dataclasses
# seats
self.assertRaises(BaseException, ex5_dataclasses.Vehicle.__init__, 0, 5, 5, 5)
self.assertRaises(BaseException, ex5_dataclasses.Vehicle.__init__, -5, 5, 5, 5)
self.assertRaises(BaseException, ex5_dataclasses.Vehicle.__init__, 10, 5, 5, 5)
self.assertRaises(BaseException, ex5_dataclasses.Vehicle.__init__, 165, 5, 5, 5)
ex5_dataclasses.Vehicle(1, 5, 5, 5)
ex5_dataclasses.Vehicle(5, 5, 5, 5)
ex5_dataclasses.Vehicle(9, 5, 5, 5)
# hp
self.assertRaises(BaseException, ex5_dataclasses.Vehicle.__init__, 5, 0, 5, 5)
self.assertRaises(BaseException, ex5_dataclasses.Vehicle.__init__, 5, -5, 5, 5)
ex5_dataclasses.Vehicle(5, 1, 5, 5)
ex5_dataclasses.Vehicle(5, 5, 5, 5)
ex5_dataclasses.Vehicle(5, 9, 5, 5)
# ccm
self.assertRaises(BaseException, ex5_dataclasses.Vehicle.__init__, 5, 5, 0, 5)
self.assertRaises(BaseException, ex5_dataclasses.Vehicle.__init__, 5, 5, -5, 5)
ex5_dataclasses.Vehicle(5, 5, 1, 5)
ex5_dataclasses.Vehicle(5, 5, 5, 5)
ex5_dataclasses.Vehicle(5, 5, 9, 5)
# weight
self.assertRaises(BaseException, ex5_dataclasses.Vehicle.__init__, 5, 5, 5, 0)
self.assertRaises(BaseException, ex5_dataclasses.Vehicle.__init__, 5, 5, 5, -5)
ex5_dataclasses.Vehicle(5, 5, 5, 1)
ex5_dataclasses.Vehicle(5, 5, 5, 5)
ex5_dataclasses.Vehicle(5, 5, 5, 9)
@no_input_test
def test4_Vehicle_fun_factor(self):
global output
output = ""
with Timeout(2):
import ex5_dataclasses
v1 = ex5_dataclasses.Vehicle(1, 1, 1, 1)
v2 = ex5_dataclasses.Vehicle(2, 1, 4, 2)
v3 = ex5_dataclasses.Vehicle(1, 4, 5, 2)
v4 = ex5_dataclasses.Vehicle(5, 6, 3, 9)
v5 = ex5_dataclasses.Vehicle(3, 1, 6, 2)
v6 = ex5_dataclasses.Vehicle(4, 2, 7, 1)
self.assertEqual(v1.fun_factor(), 11)
self.assertEqual(v2.fun_factor(), 7)
self.assertEqual(v3.fun_factor(), 22.5)
self.assertEqual(v4.fun_factor(), 7)
self.assertEqual(v5.fun_factor(), 8)
self.assertEqual(v6.fun_factor(), 27)
@no_input_test
def test4_Vehicle_gt(self):
global output
output = ""
with Timeout(2):
import ex5_dataclasses
v1 = ex5_dataclasses.Vehicle(1, 1, 1, 1)
v2 = ex5_dataclasses.Vehicle(2, 1, 4, 2)
v3 = ex5_dataclasses.Vehicle(1, 4, 5, 2)
v4 = ex5_dataclasses.Vehicle(5, 6, 3, 9)
v5 = ex5_dataclasses.Vehicle(3, 1, 6, 2)
v6 = ex5_dataclasses.Vehicle(4, 2, 7, 1)
self.assertTrue(v1 > v2)
self.assertTrue(v3 > v2)
self.assertTrue(v6 > v3)
self.assertTrue(v5 > v4)
self.assertTrue(v5 > v2)
@no_input_test
def test4_Car(self):
global output
output = ""
with Timeout(2):
import ex5_dataclasses
self.assertTrue(is_dataclass(ex5_dataclasses.Car))
self.assertTrue(issubclass(ex5_dataclasses.Car, ex5_dataclasses.Vehicle))
self.assertTrue(check_attributes(ex5_dataclasses.Car, ["seats", "hp", "ccm", "weight"], ["spoiler"]))
self.assertDictEqual(ex5_dataclasses.Car.__annotations__, {"spoiler": bool})
self.assertTrue(ex5_dataclasses.Car.__post_init__ is ex5_dataclasses.Vehicle.__post_init__)
self.assertTrue(check_function_used(ex5_dataclasses.Car.fun_factor, "super"))
c1 = ex5_dataclasses.Car(5, 5, 5, 5, True)
c2 = ex5_dataclasses.Car(5, 5, 5, 5, False)
with patch.object(ex5_dataclasses.Vehicle, "fun_factor", return_value=1337):
self.assertEqual(c1.fun_factor(), 1337.2)
self.assertEqual(c2.fun_factor(), 1337)
@no_input_test
def test4_Motorcycle(self):
global output
output = ""
with Timeout(2):
import ex5_dataclasses
self.assertTrue(is_dataclass(ex5_dataclasses.Motorcycle))
self.assertTrue(issubclass(ex5_dataclasses.Motorcycle, ex5_dataclasses.Vehicle))
self.assertTrue(check_attributes(ex5_dataclasses.Motorcycle, ["seats", "hp", "ccm", "weight"], ["sidecar"]))
self.assertDictEqual(ex5_dataclasses.Motorcycle.__annotations__, {"sidecar": bool})
self.assertTrue(check_function_used(ex5_dataclasses.Motorcycle.fun_factor, "super"))
with patch("ex5_dataclasses.Vehicle.__post_init__") as vehicle_post_init:
ex5_dataclasses.Motorcycle(3, 1, 1, 1, True)
vehicle_post_init.assert_called_once()
self.assertRaises(BaseException, ex5_dataclasses.Motorcycle.__init__, 3, 1, 1, 1, False)
self.assertRaises(BaseException, ex5_dataclasses.Motorcycle.__init__, 6, 1, 1, 1, False)
self.assertRaises(BaseException, ex5_dataclasses.Motorcycle.__init__, 1, 1, 1, 1, True)
self.assertRaises(BaseException, ex5_dataclasses.Motorcycle.__init__, 4, 1, 1, 1, True)
with patch.object(ex5_dataclasses.Vehicle, "fun_factor", return_value=1337):
m1 = ex5_dataclasses.Motorcycle(3, 5, 5, 5, True)
m2 = ex5_dataclasses.Motorcycle(2, 5, 5, 5, False)
self.assertAlmostEqual(m1.fun_factor(), 3208.8)
self.assertAlmostEqual(m2.fun_factor(), 668.5)
class Ex5_automaton(unittest.TestCase):
def test5_global_statements(self):
check_global_statements(self, "ex4_automaton")
@no_input_test
def test5_State(self):
global output
output = ""
with Timeout(2):
import ex4_automaton
self.assertTrue(issubclass(ex4_automaton.State, Enum))
self.assertFalse(is_dataclass(ex4_automaton.State))
states = ex4_automaton.State._member_names_
self.assertTrue(states == ["q0", "q1", "q2", "qe"] or states == ["Q0", "Q1", "Q2", "QE"])
@no_input_test
def test5_delta_annot(self):
global output
output = ""
with Timeout(2):
from ex4_automaton import delta, Alphabet, State
self.assertTrue(check_annot(delta, [State, Alphabet], ret=State))
@no_input_test
def test5_delta_match(self):
global output
output = ""
with Timeout(2):
import ex4_automaton
self.assertTrue(check_pattern_matching_used(ex4_automaton.delta))
@no_input_test
def test5_delta(self):
global output
output = ""
with Timeout(2):
import ex4_automaton
q0 = ex4_automaton.State.q0 if "q0" in ex4_automaton.State._member_names_ else ex4_automaton.State.Q0
q1 = ex4_automaton.State.q1 if "q1" in ex4_automaton.State._member_names_ else ex4_automaton.State.Q1
q2 = ex4_automaton.State.q2 if "q2" in ex4_automaton.State._member_names_ else ex4_automaton.State.Q2
qe = ex4_automaton.State.qe if "qe" in ex4_automaton.State._member_names_ else ex4_automaton.State.QE
self.assertEqual(ex4_automaton.delta(q0, "a"), q1)
self.assertEqual(ex4_automaton.delta(q1, "a"), q0)
self.assertEqual(ex4_automaton.delta(q1, "b"), q1)
self.assertEqual(ex4_automaton.delta(q0, "b"), q2)
self.assertEqual(ex4_automaton.delta(q2, "a"), q2)
self.assertEqual(ex4_automaton.delta(q2, "c"), q1)
self.assertEqual(ex4_automaton.delta(q2, "b"), qe)
@no_input_test
def test5_automaton(self):
global output
output = ""
with Timeout(2):
import ex4_automaton
M = ex4_automaton.automaton()
self.assertEqual(resolve_type_alias(ex4_automaton.Alphabet), resolve_type_alias(Literal["a", "b", "c"]))
self.assertEqual(M.delta, ex4_automaton.delta)
self.assertEqual(M.start, ex4_automaton.State.q0 if "q0" in ex4_automaton.State._member_names_ else ex4_automaton.State.Q0)
self.assertEqual(M.finals, frozenset({ex4_automaton.State.q0 if "q0" in ex4_automaton.State._member_names_ else ex4_automaton.State.Q0}))
self.assertTrue(check_annot(ex4_automaton.automaton, [], ex4_automaton.Automaton[ex4_automaton.State, ex4_automaton.Alphabet]))
class Ex6_recursion(unittest.TestCase):
def test6_global_statements(self):
check_global_statements(self, "ex6_recursion")
@no_input_test
def test6_annot(self):
global output
output = ""
with Timeout(2):
import ex6_recursion
type_params = ex6_recursion.filter_tree.__type_params__
self.assertEqual(len(type_params), 1)
T = type_params[0]
self.assertTrue(check_annot(ex6_recursion.filter_tree, [Callable[[T], bool], ex6_recursion.Tree[T]], list[T]))
self.assertTrue(check_annot(ex6_recursion.mirror_tree, [ex6_recursion.Tree[Any]], None))
@no_input_test
def test6_filter_tree(self):
global output
output = ""
with Timeout(2):
import ex6_recursion
Node = ex6_recursion.Node
example_node1 = Node("zero", Node("one"), Node("two", Node("three"), Node("four")))
example_node2 = Node(0, Node(5, Node(3)), Node(1))
example_node3 = None
example_node4 = Node(0)
example_node5 = Node(1, Node(2), Node(3))
self.assertListEqual(ex6_recursion.filter_tree(lambda x: 'e' in x, example_node1), ['zero', 'one', 'three'])
self.assertListEqual(ex6_recursion.filter_tree(lambda x: 'o' in x, example_node1), ['zero', 'one', 'two', 'four'])
self.assertListEqual(ex6_recursion.filter_tree(lambda _: False, example_node1), [])
self.assertListEqual(ex6_recursion.filter_tree(lambda _: True, None), [])
self.assertListEqual(ex6_recursion.filter_tree(lambda x: x % 2 == 0, example_node5), [2])
self.assertListEqual(ex6_recursion.filter_tree(lambda x: x < 0, example_node4), [])
self.assertListEqual(ex6_recursion.filter_tree(lambda x: True, example_node3), [])
self.assertTrue(check_no_sideeffects(ex6_recursion.filter_tree, lambda x: len(x) == 3, example_node1))
@no_input_test
def test6_mirror_tree(self):
global output
output = ""
with Timeout(2):
import ex6_recursion
Node = ex6_recursion.Node
example_node1 = Node("zero", Node("one"), Node("two", Node("three"), Node("four")))
example_node2 = Node(0, Node(5, Node(3)), Node(1))
example_node3 = None
example_node4 = Node(0)
example_node5 = Node(1, Node(2), Node(3))
self.assertIsNone(ex6_recursion.mirror_tree(example_node1))
example_node1 = Node("zero", Node("one"), Node("two", Node("three"), Node("four")))
ex6_recursion.mirror_tree(example_node2)
self.assertEqual(example_node2, Node(0, Node(1), Node(5, None, Node(3))))
ex6_recursion.mirror_tree(example_node2)
self.assertEqual(example_node2, Node(0, Node(5, Node(3)), Node(1)))
ex6_recursion.mirror_tree(example_node1)
self.assertEqual(example_node1, Node("zero", Node("two", Node("four"), Node("three")), Node("one")))
x = None
ex6_recursion.mirror_tree(x)
self.assertIsNone(x)
# mirror twice
ex6_recursion.mirror_tree(example_node5)
ex6_recursion.mirror_tree(example_node5)
self.assertEqual(example_node5, Node(1, Node(2), Node(3)))
class Ex7_generators(unittest.TestCase):
def test7_global_statements(self):
check_global_statements(self, "ex7_generators")
@no_input_test
def test7_annot(self):
global output
output = ""
with Timeout(2):
import ex7_generators
type_params = ex7_generators.drop.__type_params__
self.assertEqual(len(type_params), 1)
T = type_params[0]
self.assertTrue(check_annot(ex7_generators.drop, [Iterable[T], int], Iterator[T]))
type_params = ex7_generators.split.__type_params__
self.assertEqual(len(type_params), 1)
T = type_params[0]
self.assertTrue(check_annot(ex7_generators.split, [Iterable[T], T], Iterator[list[T]]))
type_params = ex7_generators.apply_pairs.__type_params__
self.assertEqual(len(type_params), 2)
T, R = type_params
self.assertTrue(check_annot(ex7_generators.apply_pairs, [Iterable[T], Callable[[T, T], R]], Iterator[R]))
@no_input_test
def test7_drop(self):
global output
output = ""
with Timeout(2):
import ex7_generators
self.assertTrue(check_function_not_used(ex7_generators.drop, "list"))
self.assertTrue(check_gen(ex7_generators.drop(IterablePure([2, 4, 6, 8, 10, 12]), 3), [8, 10, 12]))
self.assertTrue(check_gen(ex7_generators.drop(IterablePure([True, False, False]), 0), [True, False, False]))
self.assertTrue(check_gen(ex7_generators.drop(IterablePure(["a", "b", "c", "d"]), 8), []))
self.assertTrue(check_gen(ex7_generators.drop(IterablePure(range(1, 4)), 1), [2, 3]))
self.assertTrue(check_gen(ex7_generators.drop(IterablePure([1, 1, 1, 1]), 0), [1, 1, 1, 1]))
self.assertTrue(check_gen(ex7_generators.drop(IterablePure([]), 0), []))
self.assertTrue(check_gen(ex7_generators.drop(IterablePure(), 178), range(178, 1000), False, 1000))
@no_input_test
def test7_split(self):
global output
output = ""
with Timeout(2):
import ex7_generators
g1 = ex7_generators.split(IterablePure([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), 5)
self.assertTrue(check_gen(g1, [list(range(1, 5)), list(range(6, 11))]))
g2 = ex7_generators.split(IterablePure("abcdefghij", True), "e")
self.assertTrue(check_gen(g2, [list("abcd")] + [list("fghijabcd")] * 999, False, 1000))
g3 = ex7_generators.split(IterablePure("mississippiXXX", False), "i")
self.assertTrue(check_gen(g3, [list("m"), list("ss"), list("ss"), list("pp"), list("XXX")]))
g4 = ex7_generators.split(IterablePure(("Hallo", "Welt", "asdfa", "?", "asdfa", "wsgd", "Nöö", "asdfa", "Nix da"), False), "asdfa")
self.assertTrue(check_gen(g4, [["Hallo", "Welt"], ["?"], ["wsgd", "Nöö"], ["Nix da"]]))
g5 = ex7_generators.split(IterablePure("abcdefghij", True), "a")
self.assertTrue(check_gen(g5, [[]] + [list("bcdefghij")] * 999, False, 1000))
g1 = ex7_generators.split(IterablePure([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), 10)
self.assertTrue(check_gen(g1, [list(range(1, 10)), []]))
g2 = ex7_generators.split(IterablePure("abcdjjefjjghi"), "j")
self.assertTrue(check_gen(g2, [list("abcd"), [], list("ef"), [], list("ghi")]))
@no_input_test
def test7_apply_pairs(self):
global output
output = ""
with Timeout(2):
import ex7_generators
check_function_not_used(ex7_generators.apply_pairs, "list")
sub = lambda x, y: x - y
eq = lambda x, y: x == y
add_1 = lambda x, y: x + y + 1
g1 = ex7_generators.apply_pairs(IterablePure([5, 2, 7, 9, 1]), sub)
self.assertTrue(check_gen(g1, [3, -5, -2, 8]))
g2 = ex7_generators.apply_pairs(IterablePure("abaabbc", repeat=True), eq)
self.assertTrue(check_gen(g2, [False, False, True, False, True, False, False] * 100, False, 700))
g3 = ex7_generators.apply_pairs(IterablePure([1]), sub)
self.assertTrue(check_gen(g3, []))
g4 = ex7_generators.apply_pairs(IterablePure([None, None, "", None]), eq)
self.assertTrue(check_gen(g4, [True, False, False]))
g5 = ex7_generators.apply_pairs(IterablePure([0, 1, 1, 0, 1]), lambda x, y: (x + y) % 2)
self.assertTrue(check_gen(g5, [1, 0, 1, 1]))
g6 = ex7_generators.apply_pairs(IterablePure([0, 1, 1, 0, 1]), lambda x, y: x * y)
self.assertTrue(check_gen(g6, [0, 1, 0, 0]))
g7 = ex7_generators.apply_pairs(IterablePure([1, 0]), sub)
self.assertTrue(check_gen(g7, [1]))
g8 = ex7_generators.apply_pairs(IterablePure([1, 0], True), add_1)
self.assertTrue(check_gen(g8, [2, 2] * 1000, False, 1000))
class Ex8_fp(unittest.TestCase):
def test8_global_statements(self):
check_global_statements(self, "ex8_fp")
@no_input_test
def test8_annot(self):
global output
output = ""
with Timeout(2):
import ex8_fp
if ex8_fp.sum_0.__name__ == '<lambda>':
self.assertTrue(check_lambda_annotations(ex8_fp, 'sum_0', [list[Callable[[float], float]]], float))
else:
self.assertTrue(check_annot(ex8_fp.sum_0, [list[Callable[[float], float]]], float))
type_params = ex8_fp.extensionally_equal.__type_params__
self.assertEqual(len(type_params), 2)
T, R = type_params
self.assertTrue(check_annot(ex8_fp.extensionally_equal, [Callable[[T], R], Callable[[T], R], list[T]], bool))
if ex8_fp.map_matrix.__name__ == '<lambda>':
self.assertTrue(check_lambda_annotations(ex8_fp, 'map_matrix', [Callable[[float], float], list[list[float]]], list[list[float]]))
else:
self.assertTrue(check_annot(ex8_fp.map_matrix, [Callable[[float], float], list[list[float]]], list[list[float]]))
@no_input_test
def test8_sum_0(self):
global output
output = ""
with Timeout(2):
import ex8_fp
self.assertTrue(check_only_one_line(ex8_fp.sum_0))
f = lambda x: x + 1
self.assertEqual(ex8_fp.sum_0([f]), 1)
self.assertEqual(ex8_fp.sum_0([f, f, f]), 3)
f = lambda x: x + 1
g = lambda x: x**2
self.assertEqual(ex8_fp.sum_0([f, g]), 1)
f = lambda x: x % 12
g = lambda x: x**x
h = lambda _: 1337.333
self.assertTrue(math.isclose(ex8_fp.sum_0([f, g, h]), 1338.333))
self.assertEqual(ex8_fp.sum_0([]), 0)
@no_input_test
def test8_extensionally_equal(self):
global output
output = ""
with Timeout(2):
import ex8_fp
self.assertTrue(check_only_one_line(ex8_fp.extensionally_equal))
f = lambda x: x * 2 - 1
g = lambda y: y * (4 / 2) - 1
self.assertTrue(ex8_fp.extensionally_equal(f, g, [1, 2, 3, 4, 5]))
h = lambda x: x ** 2 - 4
k = lambda x: (x - 2) * (x + 2)
self.assertTrue(ex8_fp.extensionally_equal(h, k, [1, 5, 3, 7, 3]))
l = lambda y: y < 4
le = lambda x: x <= 4
self.assertTrue(ex8_fp.extensionally_equal(l, le, [1, 2, 3]))
g = lambda y: y * (4 / 2) - 1
k = lambda x: (x - 2) * (x + 2)
self.assertFalse(ex8_fp.extensionally_equal(g, k, [1]))
self.assertFalse(ex8_fp.extensionally_equal(g, k, [0]))
self.assertFalse(ex8_fp.extensionally_equal(g, k, [1, 3]))
l = lambda y: y < 4
le = lambda x: x <= 4
self.assertFalse(ex8_fp.extensionally_equal(l, le, [1, 2, 3, 4]))
@no_input_test
def test8_map_matrix(self):
global output
output = ""
with Timeout(2):
import ex8_fp
self.assertTrue(check_only_one_line(ex8_fp.map_matrix))
self.assertFalse(check_comprehension_used(ex8_fp.map_matrix))
self.assertTrue(check_function_used(ex8_fp.map_matrix, "map"))
self.assertTrue(check_function_used(ex8_fp.map_matrix, "list"))
example = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]
self.assertListEqual(ex8_fp.map_matrix(lambda x: x * 2, example), [[2, 4, 6], [8, 10, 12]])
example2 = [[2, 5], [5, 6]]
self.assertListEqual(ex8_fp.map_matrix(lambda x: x ** 2, example2), [[4, 25], [25, 36]])
self.assertListEqual(ex8_fp.map_matrix(lambda y: y < 5, example2), [[True, False], [False, False]])
self.assertListEqual(ex8_fp.map_matrix(lambda x: x, []), [])
def get_results():
result_data = {}
output = io.StringIO("")
test_classes = [(name, cls) for name, cls in inspect.getmembers(sys.modules[__name__], lambda x: inspect.isclass(
x) and (x.__module__ == __name__)) if unittest.TestCase in cls.__mro__]
suite = unittest.TestLoader().loadTestsFromTestCase(test_classes[0][1])
for other in test_classes[1:]:
suite.addTest(unittest.TestLoader().loadTestsFromTestCase(other[1]))
testResult = unittest.TextTestRunner(stream=output, verbosity=2).run(suite)
result_data["tests"] = [str(test_method) for test in test_classes
for test_method in unittest.TestLoader().loadTestsFromTestCase(test[1])]
result_data["failure"] = not testResult.wasSuccessful()
result_data["tests_run"] = testResult.testsRun
result_data["failures"] = [(str(func), str(err))
for func, err in testResult.failures]
result_data["errors"] = [(str(func), str(err))
for func, err in testResult.errors]
return result_data
if __name__ == "__main__":
docker_run = True
try:
with open("/output/output.json", "w", encoding="utf-8") as f:
result = get_results()
json.dump(result, f)
except FileNotFoundError:
docker_run = False
if not docker_run:
unittest.main()

425
test_ex6.py Normal file
View File

@ -0,0 +1,425 @@
from dataclasses import dataclass, field, fields, is_dataclass, InitVar
from types import NoneType, FunctionType, GenericAlias
from typing import get_args, Callable, Iterable, Iterator, Type, Optional, TypeAliasType, ForwardRef, Any, Literal
from enum import Enum
import unittest
from unittest import mock
from unittest.mock import patch
from functools import wraps
import signal
import io
import importlib
import importlib.util
import sys
import subprocess
import os
import shutil
import re
import math
import inspect
import json
import ast
import copy
import functools
import itertools
output = ""
class TimeoutException(Exception):
pass
class Timeout:
def __init__(self, seconds, msg=None) -> None:
if msg is None:
msg = f"Test timed out after {seconds} seconds."
self.seconds = seconds
self.msg = msg
def handle_timeout(self, signal, frame):
raise TimeoutException(self.msg)
def __enter__(self):
signal.signal(signal.SIGALRM, self.handle_timeout)
signal.alarm(self.seconds)
def __exit__(self, exc_type, exc_val, exc_tb):
signal.alarm(0)
class IterablePure:
def __init__(self, i: Optional[Iterable] = None, repeat: bool = False):
if i is not None:
self.i = i
else:
def endless():
c = 0
while True:
yield c
c += 1
self.i = endless()
self.repeat = repeat
def __iter__(self):
if self.repeat:
while True:
yield from self.i
else:
yield from self.i
def resolve_type_alias(t: Type) -> Type:
while isinstance(t, TypeAliasType | GenericAlias) and hasattr(t, "__value__"):
if isinstance(t, TypeAliasType):
t = t.__value__
elif isinstance(t, GenericAlias):
t = t.__value__[*t.__args__]
return t
def check_annot(function: Callable, expected: list[Type], ret=None):
actual = function.__annotations__
if "self" in actual:
del actual["self"]
return_type = actual["return"] if "return" in actual else None
actual = list(actual.values())[
:-1] if "return" in actual else list(actual.values())
for a, e in zip(actual, expected):
a = resolve_type_alias(a)
e = resolve_type_alias(e)
if a != e:
return False
return resolve_type_alias(ret) == resolve_type_alias(return_type)
def check_lambda_annotations(module, f_name: str, param_types: list[object], return_type: object = None) -> bool:
annotation = module.__annotations__[f_name]
if annotation.__name__ != 'Callable':
return False
all_types = annotation.__args__
types, ret_type = all_types[:-1], all_types[-1]
if ret_type != return_type:
return False
for param, param_type in zip(types, param_types):
while isinstance(param, TypeAliasType):
param = param.__value__
while isinstance(param_type, TypeAliasType):
param_type = param_type.__value__
if param != param_type:
return False
return True
def check_attributes(o: object, inherited_attr: list[str], new_attr: list[str]) -> bool:
attr = [f.name for f in fields(o)]
if attr != inherited_attr + new_attr:
return False
for attr in inherited_attr:
if attr in o.__annotations__:
return False
return True
def check_no_if_used(f: Callable) -> bool:
tree = ast.parse(inspect.getsource(f))
for node in ast.walk(tree):
if isinstance(node, ast.If):
return False
return True
def check_comprehension_used(f: Callable) -> bool:
source = inspect.getsource(f)
tree = ast.parse(source)
for node in ast.walk(tree):
if isinstance(node, (ast.ListComp, ast.SetComp, ast.DictComp, ast.GeneratorExp)):
return True
return False
def check_no_sideeffects(f: Callable, *args) -> bool:
args_copy = tuple(copy.deepcopy(a) for a in args)
f(*args)
return args == args_copy
def check_function_used(f: Callable, name: str) -> bool:
source = inspect.getsource(f)
if source.startswith(4 * " "):
source = "\n".join(l[4:] for l in source.split("\n"))
return name in [c.func.id for c in ast.walk(ast.parse(source)) if isinstance(c, ast.Call) and isinstance(c.func, ast.Name)]
def check_function_not_used(f: Callable, name: str) -> bool:
source = inspect.getsource(f)
if source.startswith(4 * " "):
source = "\n".join(l[4:] for l in source.split("\n"))
return name not in [c.func.id for c in ast.walk(ast.parse(source)) if isinstance(c, ast.Call) and isinstance(c.func, ast.Name)]
def check_pattern_matching_used(f: Callable) -> bool:
source = inspect.getsource(f)
tree = ast.parse(source)
return any(isinstance(node, ast.Match) for node in ast.walk(tree))
def check_gen(g: Iterator, res: Iterable, check_end: bool = True, max: int = 100) -> bool:
if not isinstance(g, Iterator):
return False
for i, x in enumerate(res):
el = next(g)
if el != x:
return False
if i >= max:
break
if check_end:
try:
next(g)
except StopIteration:
return True
return False
return True
def check_only_one_line(f: Callable) -> bool:
if f.__name__ == '<lambda>':
return True
inspect.getsource(f)
lines = [line for line in inspect.getsource(f).split(
'\n') if not line.strip().startswith('#') and line.strip() != '']
return len(lines) == 2
def mock_print(*args, sep=None, end=None, **_kwargs):
global output
if sep is None:
sep = " "
if end is None:
end = "\n"
args = [str(a) for a in args]
output += str(sep.join(args)) + end
def mock_input(*arg: str):
inputs = [s for s in arg]
def input_function(arg=None):
if arg is None:
arg = ""
nonlocal inputs
if len(inputs) == 0:
raise Exception("More input asked than given")
p = inputs[0]
inputs = inputs[1:]
mock_print(arg, p, sep="")
return p
return input_function
def input_error(*arg):
raise Exception("Input is not allowed here")
@patch("builtins.print", mock_print)
@patch("builtins.input", input_error)
def check_global_statements(unit: unittest.TestCase, module_name: str):
global output
output = ""
with Timeout(2):
if module_name in sys.modules.keys():
del sys.modules[module_name]
module = importlib.import_module(module_name)
unit.assertEqual(output, "")
has_global_asserts = any(isinstance(node, ast.Assert)
for node in ast.iter_child_nodes(ast.parse(inspect.getsource(module))))
unit.assertFalse(has_global_asserts)
def no_input_test(test_function: Callable) -> Callable:
@wraps(test_function)
@patch("builtins.print", mock_print)
@patch("builtins.input", input_error)
def inner(self):
global output
output = ""
with Timeout(2):
test_function(self)
return inner
class Ex6a_sum_of_subtree(unittest.TestCase):
def test6_global_statements(self):
check_global_statements(self, "ex6_recursion")
def test6_test_pattern_matching_sum_of_subtree(self):
with Timeout(2):
import ex6_recursion
check_pattern_matching_used(ex6_recursion.cut_at)
@no_input_test
def test6_annot_sum_of_subtree(self):
global output
output = ""
with Timeout(2):
import ex6_recursion
self.assertTrue(check_annot(ex6_recursion.sum_of_subtree, [
ex6_recursion.BTree[int]], int))
@no_input_test
def test6_sum_of_subtree_basisfall(self):
global output
output = ""
with Timeout(2):
import ex6_recursion
sum_of_subtree = ex6_recursion.sum_of_subtree
tree = None
self.assertEqual(sum_of_subtree(tree), 0)
self.assertIsNone(tree)
@no_input_test
def test6_sum_of_subtree(self):
global output
output = ""
with Timeout(2):
import ex6_recursion
sum_of_subtree = ex6_recursion.sum_of_subtree
Node = ex6_recursion.Node
tree = Node(1, Node(2, Node(3), Node(4)), Node(5, Node(6)))
self.assertEqual(sum_of_subtree(tree), 21)
self.assertEqual(tree, Node(mark=21, left=Node(mark=9, left=Node(mark=3, left=None, right=None), right=Node(
mark=4, left=None, right=None)), right=Node(mark=11, left=Node(mark=6, left=None, right=None), right=None)))
single_node_tree = Node(5)
self.assertEqual(sum_of_subtree(single_node_tree), 5)
simple_tree = Node(1, Node(2), Node(3))
total_sum = sum_of_subtree(simple_tree)
self.assertEqual(total_sum, 6) # 1 + 2 + 3 = 6
self.assertEqual(simple_tree.mark, 6)
self.assertEqual(simple_tree.left.mark, 2)
self.assertEqual(simple_tree.right.mark, 3)
complex_tree = Node(1, Node(2, Node(3), Node(4)), Node(5, Node(6)))
total_sum = sum_of_subtree(complex_tree)
self.assertEqual(total_sum, 21) # 1 + 2 + 3 + 4 + 5 + 6 = 21
self.assertEqual(complex_tree.mark, 21)
self.assertEqual(complex_tree.left.mark, 9) # 2 + 3 + 4 = 9
self.assertEqual(complex_tree.right.mark, 11) # 5 + 6 = 11
self.assertEqual(complex_tree.left.left.mark, 3)
self.assertEqual(complex_tree.left.right.mark, 4)
self.assertEqual(complex_tree.right.left.mark, 6)
class Ex6b_cut_at(unittest.TestCase):
def test6_global_statements(self):
check_global_statements(self, "ex6_recursion")
def test6_test_pattern_matching_cut_at(self):
with Timeout(2):
import ex6_recursion
check_pattern_matching_used(ex6_recursion.cut_at)
def test6_test_no_side_effects_cut_at(self):
with Timeout(2):
import ex6_recursion
Node = ex6_recursion.Node
tree = Node(1, Node(2, Node(3), Node(4)),
Node(3, Node(3), Node(6)))
check_no_sideeffects(ex6_recursion.cut_at, tree, 3)
@no_input_test
def test6_annot_cut_at(self):
global output
output = ""
with Timeout(2):
import ex6_recursion
self.assertTrue(check_annot(ex6_recursion.sum_of_subtree, [
ex6_recursion.BTree[int]], int))
type_params = ex6_recursion.cut_at.__type_params__
self.assertEqual(len(type_params), 1)
T = type_params[0]
self.assertTrue(check_annot(ex6_recursion.cut_at, [
ex6_recursion.BTree[T]], ex6_recursion.BTree[T]))
@no_input_test
def test6_cut_at_basisfall(self):
global output
output = ""
with Timeout(2):
import ex6_recursion
cut_at = ex6_recursion.cut_at
tree = None
self.assertIsNone(cut_at(tree, 42))
@no_input_test
def test6_cut_at(self):
global output
output = ""
with Timeout(2):
import ex6_recursion
Node = ex6_recursion.Node
cut_at = ex6_recursion.cut_at
tree = Node(1, Node(2, Node(3), Node(4)),
Node(3, Node(3), Node(6)))
self.assertIsNone(cut_at(tree, 1))
self.assertEqual(cut_at(tree, 3), Node(mark=1, left=Node(
mark=2, left=None, right=Node(mark=4, left=None, right=None)), right=None))
single_node_tree = Node(5)
new_tree = cut_at(single_node_tree, 10)
self.assertIsNotNone(new_tree)
self.assertEqual(new_tree.mark, 5)
self.assertIsNone(new_tree.left)
self.assertIsNone(new_tree.right)
tree_without_cut = Node(
1, Node(2, Node(3), Node(4)), Node(5, Node(6)))
new_tree = cut_at(tree_without_cut, 42) # No node has value 42
self.assertIsNotNone(new_tree)
self.assertEqual(new_tree.mark, 1)
self.assertIsNotNone(new_tree.left)
self.assertIsNotNone(new_tree.right)
tree_with_cut = Node(
1, Node(2, Node(3), Node(4)), Node(3, Node(3), Node(6)))
new_tree = cut_at(tree_with_cut, 3) # Cut all nodes with value 3
self.assertIsNotNone(new_tree)
self.assertEqual(new_tree.mark, 1)
self.assertEqual(new_tree.left.mark, 2)
self.assertIsNone(new_tree.right) # The right subtree is removed
self.assertIsNone(new_tree.left.left) # Node(3) is removed
self.assertIsNotNone(new_tree.left.right)
self.assertEqual(new_tree.left.right.mark, 4) # Node(4) remains
def get_results():
result_data = {}
output = io.StringIO("")
test_classes = [(name, cls) for name, cls in inspect.getmembers(sys.modules[__name__], lambda x: inspect.isclass(
x) and (x.__module__ == __name__)) if unittest.TestCase in cls.__mro__]
suite = unittest.TestLoader().loadTestsFromTestCase(test_classes[0][1])
for other in test_classes[1:]:
suite.addTest(unittest.TestLoader().loadTestsFromTestCase(other[1]))
testResult = unittest.TextTestRunner(stream=output, verbosity=2).run(suite)
result_data["tests"] = [str(test_method) for test in test_classes
for test_method in unittest.TestLoader()
.loadTestsFromTestCase(test[1])]
result_data["failure"] = not testResult.wasSuccessful()
result_data["tests_run"] = testResult.testsRun
result_data["failures"] = [(str(func), str(err))
for func, err in testResult.failures]
result_data["errors"] = [(str(func), str(err))
for func, err in testResult.errors]
return result_data
if __name__ == "__main__":
docker_run = True
try:
with open("/output/output.json", "w", encoding="utf-8") as f:
result = get_results()
json.dump(result, f)
except FileNotFoundError:
docker_run = False
if not docker_run:
unittest.main()