Compare commits
2 Commits
69053634be
...
66711f61dd
Author | SHA1 | Date | |
---|---|---|---|
66711f61dd | |||
5f1cc196c8 |
23
ex6_recursion.md
Normal file
23
ex6_recursion.md
Normal 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
49
ex6_recursion.py
Normal 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)))
|
964
test14.py
964
test14.py
@ -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
425
test_ex6.py
Normal 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()
|
Reference in New Issue
Block a user