Coverage for src/extratools_core/testtools.py: 99%
77 statements
« prev ^ index » next coverage.py v7.8.1, created at 2025-06-24 04:41 -0700
« prev ^ index » next coverage.py v7.8.1, created at 2025-06-24 04:41 -0700
1from collections.abc import Callable, Mapping, MutableMapping
2from typing import Any
4from .typing import SearchableMapping
7def expect_exception(error_cls: type[Exception], f: Callable[[], Any]) -> None:
8 try:
9 f()
10 except error_cls:
11 return
13 raise AssertionError
16def is_proper_mapping[KT, VT](
17 cls: type[Mapping[KT, VT]] | Callable[[], Mapping[KT, VT]],
18 *,
19 key_cls: type[KT] | Callable[[], KT],
20 value_cls: type[VT] | Callable[[], VT],
21) -> None:
22 m: Mapping[KT, VT] = cls()
24 assert isinstance(m, Mapping)
26 assert len(m) >= 0
28 assert list(zip(m.keys(), m.values(), strict=True)) == list(m.items())
30 key: KT
31 value: VT
32 for key, value in m.items():
33 assert key in m
34 assert m[key] == value
35 assert m.get(key) == value
37 key = key_cls()
38 value = value_cls()
40 assert key not in m
41 expect_exception(KeyError, lambda: m[key])
42 assert m.get(key) is None
43 assert m.get(key, value) == value
46def is_proper_searchable_mapping[KT, VT, FT](
47 cls: type[SearchableMapping[KT, VT]] | Callable[[], SearchableMapping[KT, VT]],
48 *,
49 filter_cls: type[FT] | Callable[[], FT],
50 keys_func: Callable[[FT], list[KT]],
51) -> None:
52 m: SearchableMapping[KT, VT] = cls()
54 assert isinstance(m, SearchableMapping)
56 assert list(m) == list(m.search())
58 filter_body = filter_cls()
60 assert set(m.search(filter_body)) <= set(keys_func(filter_body))
63def is_proper_mutable_mapping[KT, VT](
64 cls: type[MutableMapping[KT, VT]] | Callable[[], MutableMapping[KT, VT]],
65 *,
66 key_cls: type[KT] | Callable[[], KT],
67 value_cls: type[VT] | Callable[[], VT],
68) -> None:
69 m: MutableMapping[KT, VT] = cls()
71 assert isinstance(m, MutableMapping)
73 assert len(m) >= 0
75 m.clear()
76 assert len(m) == 0
78 assert list(m.keys()) == []
79 assert list(m.values()) == []
80 assert list(m.items()) == []
82 key: KT = key_cls()
83 value: VT = value_cls()
84 assert key not in m
86 m[key] = value
87 assert key in m
88 assert len(m) == 1
89 assert m[key] == value
90 assert m.get(key) == value
92 assert list(m.keys()) == [key]
93 assert list(m.values()) == [value]
94 assert list(m.items()) == [(key, value)]
96 # No duplication
97 m[key] = value
98 assert len(m) == 1
100 del m[key]
101 assert key not in m
102 assert len(m) == 0
103 expect_exception(KeyError, lambda: m[key])
104 assert m.get(key) is None
105 assert m.get(key, value) == value
107 assert m.setdefault(key, value) == value
108 assert key in m
109 assert len(m) == 1
110 assert m[key] == value
112 assert m.pop(key) == value
113 assert key not in m
114 assert len(m) == 0
115 # `pop`` is special here that it would raise `KeyError` if `default` is not specified.
116 expect_exception(KeyError, lambda: m.pop(key))
117 assert m.pop(key, None) is None
118 assert m.pop(key, value) == value
120 m.update([(key, value)])
121 assert len(m) == 1
123 assert list(zip(m.keys(), m.values(), strict=True)) == list(m.items())
125 for key, value in m.items():
126 assert key in m
127 assert m[key] == value
128 assert m.get(key) == value
130 m.clear()
131 assert len(m) == 0