crosshair-tool 0.0.99__cp312-cp312-macosx_10_13_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- _crosshair_tracers.cpython-312-darwin.so +0 -0
- crosshair/__init__.py +42 -0
- crosshair/__main__.py +8 -0
- crosshair/_mark_stacks.h +790 -0
- crosshair/_preliminaries_test.py +18 -0
- crosshair/_tracers.h +94 -0
- crosshair/_tracers_pycompat.h +522 -0
- crosshair/_tracers_test.py +138 -0
- crosshair/abcstring.py +245 -0
- crosshair/auditwall.py +190 -0
- crosshair/auditwall_test.py +77 -0
- crosshair/codeconfig.py +113 -0
- crosshair/codeconfig_test.py +117 -0
- crosshair/condition_parser.py +1237 -0
- crosshair/condition_parser_test.py +497 -0
- crosshair/conftest.py +30 -0
- crosshair/copyext.py +155 -0
- crosshair/copyext_test.py +84 -0
- crosshair/core.py +1763 -0
- crosshair/core_and_libs.py +149 -0
- crosshair/core_regestered_types_test.py +82 -0
- crosshair/core_test.py +1316 -0
- crosshair/diff_behavior.py +314 -0
- crosshair/diff_behavior_test.py +261 -0
- crosshair/dynamic_typing.py +346 -0
- crosshair/dynamic_typing_test.py +210 -0
- crosshair/enforce.py +282 -0
- crosshair/enforce_test.py +182 -0
- crosshair/examples/PEP316/__init__.py +1 -0
- crosshair/examples/PEP316/bugs_detected/__init__.py +0 -0
- crosshair/examples/PEP316/bugs_detected/getattr_magic.py +16 -0
- crosshair/examples/PEP316/bugs_detected/hash_consistent_with_equals.py +31 -0
- crosshair/examples/PEP316/bugs_detected/shopping_cart.py +24 -0
- crosshair/examples/PEP316/bugs_detected/showcase.py +39 -0
- crosshair/examples/PEP316/correct_code/__init__.py +0 -0
- crosshair/examples/PEP316/correct_code/arith.py +60 -0
- crosshair/examples/PEP316/correct_code/chess.py +77 -0
- crosshair/examples/PEP316/correct_code/nesting_inference.py +17 -0
- crosshair/examples/PEP316/correct_code/numpy_examples.py +132 -0
- crosshair/examples/PEP316/correct_code/rolling_average.py +35 -0
- crosshair/examples/PEP316/correct_code/showcase.py +104 -0
- crosshair/examples/__init__.py +0 -0
- crosshair/examples/check_examples_test.py +146 -0
- crosshair/examples/deal/__init__.py +1 -0
- crosshair/examples/icontract/__init__.py +1 -0
- crosshair/examples/icontract/bugs_detected/__init__.py +0 -0
- crosshair/examples/icontract/bugs_detected/showcase.py +41 -0
- crosshair/examples/icontract/bugs_detected/wrong_sign.py +8 -0
- crosshair/examples/icontract/correct_code/__init__.py +0 -0
- crosshair/examples/icontract/correct_code/arith.py +51 -0
- crosshair/examples/icontract/correct_code/showcase.py +94 -0
- crosshair/fnutil.py +391 -0
- crosshair/fnutil_test.py +75 -0
- crosshair/fuzz_core_test.py +516 -0
- crosshair/libimpl/__init__.py +0 -0
- crosshair/libimpl/arraylib.py +161 -0
- crosshair/libimpl/binascii_ch_test.py +30 -0
- crosshair/libimpl/binascii_test.py +67 -0
- crosshair/libimpl/binasciilib.py +150 -0
- crosshair/libimpl/bisectlib_test.py +23 -0
- crosshair/libimpl/builtinslib.py +5228 -0
- crosshair/libimpl/builtinslib_ch_test.py +1191 -0
- crosshair/libimpl/builtinslib_test.py +3735 -0
- crosshair/libimpl/codecslib.py +86 -0
- crosshair/libimpl/codecslib_test.py +86 -0
- crosshair/libimpl/collectionslib.py +264 -0
- crosshair/libimpl/collectionslib_ch_test.py +252 -0
- crosshair/libimpl/collectionslib_test.py +332 -0
- crosshair/libimpl/copylib.py +23 -0
- crosshair/libimpl/copylib_test.py +18 -0
- crosshair/libimpl/datetimelib.py +2559 -0
- crosshair/libimpl/datetimelib_ch_test.py +354 -0
- crosshair/libimpl/datetimelib_test.py +112 -0
- crosshair/libimpl/decimallib.py +5257 -0
- crosshair/libimpl/decimallib_ch_test.py +78 -0
- crosshair/libimpl/decimallib_test.py +76 -0
- crosshair/libimpl/encodings/__init__.py +23 -0
- crosshair/libimpl/encodings/_encutil.py +187 -0
- crosshair/libimpl/encodings/ascii.py +44 -0
- crosshair/libimpl/encodings/latin_1.py +40 -0
- crosshair/libimpl/encodings/utf_8.py +93 -0
- crosshair/libimpl/encodings_ch_test.py +83 -0
- crosshair/libimpl/fractionlib.py +16 -0
- crosshair/libimpl/fractionlib_test.py +80 -0
- crosshair/libimpl/functoolslib.py +34 -0
- crosshair/libimpl/functoolslib_test.py +56 -0
- crosshair/libimpl/hashliblib.py +30 -0
- crosshair/libimpl/hashliblib_test.py +18 -0
- crosshair/libimpl/heapqlib.py +47 -0
- crosshair/libimpl/heapqlib_test.py +21 -0
- crosshair/libimpl/importliblib.py +18 -0
- crosshair/libimpl/importliblib_test.py +38 -0
- crosshair/libimpl/iolib.py +216 -0
- crosshair/libimpl/iolib_ch_test.py +128 -0
- crosshair/libimpl/iolib_test.py +19 -0
- crosshair/libimpl/ipaddresslib.py +8 -0
- crosshair/libimpl/itertoolslib.py +44 -0
- crosshair/libimpl/itertoolslib_test.py +44 -0
- crosshair/libimpl/jsonlib.py +984 -0
- crosshair/libimpl/jsonlib_ch_test.py +42 -0
- crosshair/libimpl/jsonlib_test.py +51 -0
- crosshair/libimpl/mathlib.py +179 -0
- crosshair/libimpl/mathlib_ch_test.py +44 -0
- crosshair/libimpl/mathlib_test.py +67 -0
- crosshair/libimpl/oslib.py +7 -0
- crosshair/libimpl/pathliblib_test.py +10 -0
- crosshair/libimpl/randomlib.py +178 -0
- crosshair/libimpl/randomlib_test.py +120 -0
- crosshair/libimpl/relib.py +846 -0
- crosshair/libimpl/relib_ch_test.py +169 -0
- crosshair/libimpl/relib_test.py +493 -0
- crosshair/libimpl/timelib.py +72 -0
- crosshair/libimpl/timelib_test.py +82 -0
- crosshair/libimpl/typeslib.py +15 -0
- crosshair/libimpl/typeslib_test.py +36 -0
- crosshair/libimpl/unicodedatalib.py +75 -0
- crosshair/libimpl/unicodedatalib_test.py +42 -0
- crosshair/libimpl/urlliblib.py +23 -0
- crosshair/libimpl/urlliblib_test.py +19 -0
- crosshair/libimpl/weakreflib.py +13 -0
- crosshair/libimpl/weakreflib_test.py +69 -0
- crosshair/libimpl/zliblib.py +15 -0
- crosshair/libimpl/zliblib_test.py +13 -0
- crosshair/lsp_server.py +261 -0
- crosshair/lsp_server_test.py +30 -0
- crosshair/main.py +973 -0
- crosshair/main_test.py +543 -0
- crosshair/objectproxy.py +376 -0
- crosshair/objectproxy_test.py +41 -0
- crosshair/opcode_intercept.py +601 -0
- crosshair/opcode_intercept_test.py +304 -0
- crosshair/options.py +218 -0
- crosshair/options_test.py +10 -0
- crosshair/patch_equivalence_test.py +75 -0
- crosshair/path_cover.py +209 -0
- crosshair/path_cover_test.py +138 -0
- crosshair/path_search.py +161 -0
- crosshair/path_search_test.py +52 -0
- crosshair/pathing_oracle.py +271 -0
- crosshair/pathing_oracle_test.py +21 -0
- crosshair/pure_importer.py +27 -0
- crosshair/pure_importer_test.py +16 -0
- crosshair/py.typed +0 -0
- crosshair/register_contract.py +273 -0
- crosshair/register_contract_test.py +190 -0
- crosshair/simplestructs.py +1165 -0
- crosshair/simplestructs_test.py +283 -0
- crosshair/smtlib.py +24 -0
- crosshair/smtlib_test.py +14 -0
- crosshair/statespace.py +1199 -0
- crosshair/statespace_test.py +108 -0
- crosshair/stubs_parser.py +352 -0
- crosshair/stubs_parser_test.py +43 -0
- crosshair/test_util.py +329 -0
- crosshair/test_util_test.py +26 -0
- crosshair/tools/__init__.py +0 -0
- crosshair/tools/check_help_in_doc.py +264 -0
- crosshair/tools/check_init_and_setup_coincide.py +119 -0
- crosshair/tools/generate_demo_table.py +127 -0
- crosshair/tracers.py +544 -0
- crosshair/tracers_test.py +154 -0
- crosshair/type_repo.py +151 -0
- crosshair/unicode_categories.py +589 -0
- crosshair/unicode_categories_test.py +27 -0
- crosshair/util.py +741 -0
- crosshair/util_test.py +173 -0
- crosshair/watcher.py +307 -0
- crosshair/watcher_test.py +107 -0
- crosshair/z3util.py +76 -0
- crosshair/z3util_test.py +11 -0
- crosshair_tool-0.0.99.dist-info/METADATA +144 -0
- crosshair_tool-0.0.99.dist-info/RECORD +176 -0
- crosshair_tool-0.0.99.dist-info/WHEEL +6 -0
- crosshair_tool-0.0.99.dist-info/entry_points.txt +3 -0
- crosshair_tool-0.0.99.dist-info/licenses/LICENSE +93 -0
- crosshair_tool-0.0.99.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,1191 @@
|
|
|
1
|
+
import operator
|
|
2
|
+
import sys
|
|
3
|
+
from math import isnan
|
|
4
|
+
from numbers import Integral
|
|
5
|
+
from typing import (
|
|
6
|
+
Any,
|
|
7
|
+
Callable,
|
|
8
|
+
Dict,
|
|
9
|
+
FrozenSet,
|
|
10
|
+
List,
|
|
11
|
+
Mapping,
|
|
12
|
+
Optional,
|
|
13
|
+
Sequence,
|
|
14
|
+
Set,
|
|
15
|
+
Tuple,
|
|
16
|
+
Union,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
import pytest # type: ignore
|
|
20
|
+
|
|
21
|
+
from crosshair.core import realize
|
|
22
|
+
from crosshair.core_and_libs import MessageType, analyze_function, run_checkables
|
|
23
|
+
from crosshair.test_util import ResultComparison, compare_results, compare_returns
|
|
24
|
+
|
|
25
|
+
_TRICKY_UNICODE = (
|
|
26
|
+
"A\u01f2", # upper followed by title cased character
|
|
27
|
+
"\ua770", # Lm, lower (superscript "9")
|
|
28
|
+
"\u01f2", # Lt, title-cased but not upper (compound "Dz" like char)
|
|
29
|
+
"\u2165", # Nl (roman numeral "VI")
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def check_abs(x: Union[int, bool, float]) -> ResultComparison:
|
|
34
|
+
"""post: _"""
|
|
35
|
+
return compare_returns(abs, x)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def check_ascii(x: object) -> ResultComparison:
|
|
39
|
+
"""post: _"""
|
|
40
|
+
return compare_results(ascii, x)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def check_bin(x: Integral) -> ResultComparison:
|
|
44
|
+
"""post: _"""
|
|
45
|
+
return compare_results(bin, x)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def check_callable(x: object) -> ResultComparison:
|
|
49
|
+
"""post: _"""
|
|
50
|
+
return compare_results(callable, x)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def check_chr(x: int) -> ResultComparison:
|
|
54
|
+
"""post: _"""
|
|
55
|
+
return compare_results(chr, x)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# NOTE: dir() is not expected to be compatible.
|
|
59
|
+
|
|
60
|
+
_NAN_SENTINAL: Tuple = tuple()
|
|
61
|
+
# (anything that is copyable and compares equal with itself)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def check_divmod(
|
|
65
|
+
numerator: Union[int, float], denominator: Union[int, float]
|
|
66
|
+
) -> ResultComparison:
|
|
67
|
+
"""post: _"""
|
|
68
|
+
if numerator == 0 or denominator == 0:
|
|
69
|
+
pass
|
|
70
|
+
return compare_returns(
|
|
71
|
+
lambda n, d: [_NAN_SENTINAL if isnan(x) else x for x in divmod(n, d)],
|
|
72
|
+
numerator,
|
|
73
|
+
denominator,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def check_eval(expr: str):
|
|
78
|
+
"""
|
|
79
|
+
pre: len(expr) == 1
|
|
80
|
+
post: _
|
|
81
|
+
"""
|
|
82
|
+
return compare_results(lambda e: eval(e, {}, {}), expr)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# NOTE: not patching exit()
|
|
86
|
+
|
|
87
|
+
# TODO: this fails; symbolic callables do not have correct behavior for
|
|
88
|
+
# inputs outside their expected domain.
|
|
89
|
+
# def check_filter(f: Callable[[int], bool], l: List[str]):
|
|
90
|
+
# ''' post: _ '''
|
|
91
|
+
# return compare_results(filter, f, l)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def check_float(o: Union[str, int, float]) -> ResultComparison:
|
|
95
|
+
"""post: _"""
|
|
96
|
+
# TODO this isn't hitting most of the branches we care about right now.
|
|
97
|
+
return compare_returns(float, o)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def check_float_sub(float_a: float, float_b: float) -> ResultComparison:
|
|
101
|
+
"""post: _"""
|
|
102
|
+
return compare_returns(lambda a, b: a - b, float_a, float_b)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def check_format(x: object, f: str) -> ResultComparison:
|
|
106
|
+
"""post: _"""
|
|
107
|
+
return compare_results(format, x, f)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
# TODO: Add str and other types to check here
|
|
111
|
+
def check_format_dunder(obj: Union[int, float], fmt: str) -> ResultComparison:
|
|
112
|
+
"""post: _"""
|
|
113
|
+
if fmt == "03d":
|
|
114
|
+
pass
|
|
115
|
+
elif fmt == "+.3f":
|
|
116
|
+
pass
|
|
117
|
+
# TODO: do not realize `fmt` here- instead we should intercept the native
|
|
118
|
+
# __format__ calls to check for a symbolic format string.
|
|
119
|
+
return compare_returns(lambda o, f: o.__format__(f), obj, realize(fmt))
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# CrossHair proxies don't have the same attributes as native:
|
|
123
|
+
# def check_getattr(o: object, n: str, d: object) -> ResultComparison:
|
|
124
|
+
|
|
125
|
+
# NOTE: not patching globals()
|
|
126
|
+
|
|
127
|
+
# CrossHair proxies don't have the same attributes as native:
|
|
128
|
+
# def check_hasattr(o: str, n: str) -> ResultComparison:
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def check_hash(o: Union[int, str, bytes, tuple]) -> ResultComparison:
|
|
132
|
+
"""post: _"""
|
|
133
|
+
return compare_results(hash, o)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
# We test frozenset explicitly because it's trickier:
|
|
137
|
+
def check_frozenset_hash(o: frozenset) -> ResultComparison:
|
|
138
|
+
"""post: _"""
|
|
139
|
+
return compare_results(hash, o)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
# NOTE: not patching help()
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def check_hex(o: int) -> ResultComparison:
|
|
146
|
+
"""post: _"""
|
|
147
|
+
return compare_results(hex, o)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# NOTE: not testing id()
|
|
151
|
+
# NOTE: not testing input()
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def check_int(o: Union[str, int, float]) -> ResultComparison:
|
|
155
|
+
"""post: _"""
|
|
156
|
+
return compare_returns(int, o)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def check_int_with_base(o: str, b: int) -> ResultComparison:
|
|
160
|
+
"""post: _"""
|
|
161
|
+
return compare_results(int, o, b)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def check_isinstance(o: object, t: type) -> ResultComparison:
|
|
165
|
+
"""post: _"""
|
|
166
|
+
return compare_results(isinstance, o, t)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def check_issubclass(o: object, t: type) -> ResultComparison:
|
|
170
|
+
"""post: _"""
|
|
171
|
+
return compare_results(issubclass, o, t)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def check_iter(obj: Union[str, List[int], Dict[int, int]]) -> ResultComparison:
|
|
175
|
+
"""post: _"""
|
|
176
|
+
# Note that we don't check Set[int] because of unstable ordering.
|
|
177
|
+
return compare_results(lambda o: list(iter(o)), obj)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def check_len(
|
|
181
|
+
s: Union[Dict[int, int], Tuple[int, ...], str, List[int], Set[int]],
|
|
182
|
+
) -> ResultComparison:
|
|
183
|
+
"""post: _"""
|
|
184
|
+
return compare_results(len, s)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
# NOTE: not testing license()
|
|
188
|
+
# NOTE: not testing locals()
|
|
189
|
+
|
|
190
|
+
# TODO: this fails; right now because symbolic callables have a bug that
|
|
191
|
+
# let's them realize inconsistently.
|
|
192
|
+
# def check_map(f: Callable[[int], str], l: List[int]):
|
|
193
|
+
# ''' post: _ '''
|
|
194
|
+
# return compare_results(map, f, l)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def check_max(
|
|
198
|
+
x: Sequence, k: Optional[Callable[[Any], Any]], d: object
|
|
199
|
+
) -> ResultComparison:
|
|
200
|
+
"""post: _"""
|
|
201
|
+
kw = {"default": d}
|
|
202
|
+
if k is not None:
|
|
203
|
+
kw["key"] = k
|
|
204
|
+
return compare_results(max, x, **kw)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def check_min(x: Sequence) -> ResultComparison:
|
|
208
|
+
"""post: _"""
|
|
209
|
+
return compare_results(min, x)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
# NOTE: not testing next()
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def check_oct(x: int) -> ResultComparison:
|
|
216
|
+
"""post: _"""
|
|
217
|
+
return compare_results(oct, x)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
# NOTE: not testing open()
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def check_ord(x: str) -> ResultComparison:
|
|
224
|
+
"""post: _"""
|
|
225
|
+
return compare_results(ord, x)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def check_print(o: object) -> ResultComparison:
|
|
229
|
+
"""post: _"""
|
|
230
|
+
return compare_results(print, o)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def check_pow_function(
|
|
234
|
+
b: Union[int, float], e: Union[int, float], m: Optional[int]
|
|
235
|
+
) -> ResultComparison:
|
|
236
|
+
"""post: _"""
|
|
237
|
+
# crosshair: max_uninteresting_iterations=150
|
|
238
|
+
# (running this a little longer for various float representations)
|
|
239
|
+
return compare_returns(pow, b, e, m)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def check_pow_operator(b: Union[int, float], e: Union[int, float]) -> ResultComparison:
|
|
243
|
+
"""post: _"""
|
|
244
|
+
# crosshair: max_uninteresting_iterations=150
|
|
245
|
+
# (running this a little longer for various float representations)
|
|
246
|
+
return compare_returns(operator.pow, b, e)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
# NOTE: not testing quit()
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def check_range_len(start: int, stop: int, step: int) -> ResultComparison:
|
|
253
|
+
"""post: _"""
|
|
254
|
+
return compare_results(lambda a, o, e: len(range(a, o, e)), start, stop, step)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def check_range_reversed(start: int, stop: int, step: int) -> ResultComparison:
|
|
258
|
+
"""post: _"""
|
|
259
|
+
return compare_results(
|
|
260
|
+
lambda a, o, e: list(reversed(range(a, o, e))), start, stop, step
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def check_reversed(obj: Union[List[int], Tuple[int]]) -> ResultComparison:
|
|
265
|
+
"""post: _"""
|
|
266
|
+
return compare_results(lambda o: list(reversed(o)), obj)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def check_repr(o: object) -> ResultComparison:
|
|
270
|
+
"""post: _"""
|
|
271
|
+
return compare_results(repr, o)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def check_round_float(o: float, d: Optional[int]) -> ResultComparison:
|
|
275
|
+
"""post: _"""
|
|
276
|
+
return compare_returns(round, o, d)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def check_round_int(o: int, d: Optional[int]) -> ResultComparison:
|
|
280
|
+
"""post: _"""
|
|
281
|
+
return compare_results(round, o, d)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
# CrossHair proxies don't have the same attributes as native:
|
|
285
|
+
# def check_setattr(o: object, n: str, v: object) -> ResultComparison:
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def check_sorted(s: Sequence) -> ResultComparison:
|
|
289
|
+
"""post: _"""
|
|
290
|
+
return compare_results(sorted, s)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def check_sum(
|
|
294
|
+
s: Union[Sequence[int], Sequence[float]],
|
|
295
|
+
# i: Union[None, int, float]
|
|
296
|
+
) -> ResultComparison:
|
|
297
|
+
"""post: _"""
|
|
298
|
+
return compare_returns(sum, s)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
# NOTE: not testing vars()
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def check_zip(s: Sequence[Sequence[int]]) -> ResultComparison:
|
|
305
|
+
"""post: _"""
|
|
306
|
+
return compare_results(lambda args: zip(*args), s)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
# Check list methods
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def check_list_index(
|
|
313
|
+
lst: List[int], item: int, start: int, stop: int
|
|
314
|
+
) -> ResultComparison:
|
|
315
|
+
"""post: _"""
|
|
316
|
+
return compare_results(lambda ln, *a: ln.index(*a), lst, item, start, stop)
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def check_list_extend_and_slice(container: Union[List[int], bytearray]):
|
|
320
|
+
"""
|
|
321
|
+
pre: len(container) <= 4
|
|
322
|
+
post: _
|
|
323
|
+
"""
|
|
324
|
+
|
|
325
|
+
def f(c):
|
|
326
|
+
addition = [1, 2] if isinstance(container, list) else bytearray([1, 2])
|
|
327
|
+
c += addition
|
|
328
|
+
c = c[:3]
|
|
329
|
+
del addition[0] # This mutation hopefully doesn't change the result!
|
|
330
|
+
return (c, type(c))
|
|
331
|
+
|
|
332
|
+
return compare_results(f, container)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def check_list_setitem_slice(container: List[int], key: slice, replacement: List[int]):
|
|
336
|
+
"""
|
|
337
|
+
pre: len(container) <= 3 and len(replacement) <= 3
|
|
338
|
+
post: _
|
|
339
|
+
"""
|
|
340
|
+
# crosshair: max_iterations=100
|
|
341
|
+
|
|
342
|
+
def f(c, k, r):
|
|
343
|
+
c[k] = r
|
|
344
|
+
r.append(42)
|
|
345
|
+
return c
|
|
346
|
+
|
|
347
|
+
return compare_results(f, container, key, replacement)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
# Check dict methods
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def check_dict___init__(
|
|
354
|
+
pos_args: List[Tuple[int, int]], kw_args: Dict[str, int]
|
|
355
|
+
) -> ResultComparison:
|
|
356
|
+
"""post: _"""
|
|
357
|
+
return compare_results(lambda a, kw: dict(*a, **kw), pos_args, kw_args)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def check_dict_get(dictionary: Dict[int, int], key: int) -> ResultComparison:
|
|
361
|
+
"""post: _"""
|
|
362
|
+
return compare_results(lambda d, k: d.get(k), dictionary, key)
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def check_dict_iter(dictionary: Dict[int, int]) -> ResultComparison:
|
|
366
|
+
"""post: _"""
|
|
367
|
+
return compare_results(lambda d: list(d), dictionary)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def check_dict_clear(dictionary: Dict[int, int]) -> ResultComparison:
|
|
371
|
+
"""post: _"""
|
|
372
|
+
|
|
373
|
+
def checker(d):
|
|
374
|
+
d.clear()
|
|
375
|
+
return d
|
|
376
|
+
|
|
377
|
+
return compare_results(checker, dictionary)
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def check_dict_pop(dictionary: Dict[int, int], key: int) -> ResultComparison:
|
|
381
|
+
"""post: _"""
|
|
382
|
+
|
|
383
|
+
def checker(d, k):
|
|
384
|
+
x = d.pop(k)
|
|
385
|
+
return (x, d)
|
|
386
|
+
|
|
387
|
+
return compare_results(checker, dictionary, key)
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def check_dict_popitem(dictionary: Dict[int, int]) -> ResultComparison:
|
|
391
|
+
"""post: _"""
|
|
392
|
+
|
|
393
|
+
def checker(d):
|
|
394
|
+
x = d.popitem()
|
|
395
|
+
return (x, d)
|
|
396
|
+
|
|
397
|
+
return compare_results(checker, dictionary)
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def check_dict_update(left: Dict[int, int], right: Dict[int, int]) -> ResultComparison:
|
|
401
|
+
"""post: _"""
|
|
402
|
+
|
|
403
|
+
def checker(d1, d2):
|
|
404
|
+
d1.update(d2)
|
|
405
|
+
return d1
|
|
406
|
+
|
|
407
|
+
return compare_results(checker, left, right)
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def check_dict_values(dictionary: Dict[int, int]) -> ResultComparison:
|
|
411
|
+
"""post: _"""
|
|
412
|
+
# TODO: value views compare false even with new views from the same dict.
|
|
413
|
+
# Ensure we match this behavior.
|
|
414
|
+
return compare_results(lambda d: list(d.values()), dictionary)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
# check set/frozenset methods
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def check_set_eq(setobj: Set[int]) -> ResultComparison:
|
|
421
|
+
"""post: _"""
|
|
422
|
+
return compare_results(lambda s: s, setobj)
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def check_set_clear(setobj: Set[int]) -> ResultComparison:
|
|
426
|
+
"""post: _"""
|
|
427
|
+
|
|
428
|
+
def checker(s):
|
|
429
|
+
s.clear()
|
|
430
|
+
return s
|
|
431
|
+
|
|
432
|
+
return compare_results(checker, setobj)
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def check_set_remove(setobj: Set[int], item: int) -> ResultComparison:
|
|
436
|
+
"""post: _"""
|
|
437
|
+
|
|
438
|
+
def checker(s, i):
|
|
439
|
+
s.remove(i)
|
|
440
|
+
return realize(s)
|
|
441
|
+
|
|
442
|
+
return compare_results(checker, setobj, item)
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def check_set_add(setobj: Set[int], item: int) -> ResultComparison:
|
|
446
|
+
"""post: _"""
|
|
447
|
+
|
|
448
|
+
def checker(s, i):
|
|
449
|
+
s.add(i)
|
|
450
|
+
return realize(s)
|
|
451
|
+
|
|
452
|
+
return compare_results(checker, setobj, item)
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def check_set_symmetric_difference_update(
|
|
456
|
+
left: Set[int], right: Set[int]
|
|
457
|
+
) -> ResultComparison:
|
|
458
|
+
"""post: _"""
|
|
459
|
+
|
|
460
|
+
def checker(left, right):
|
|
461
|
+
left ^= right
|
|
462
|
+
return sorted(left)
|
|
463
|
+
|
|
464
|
+
return compare_results(checker, left, right)
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
def check_set_union_sorted(
|
|
468
|
+
left: Union[Set[int], FrozenSet[int]], right: Union[Set[int], FrozenSet[int]]
|
|
469
|
+
) -> ResultComparison:
|
|
470
|
+
"""post: _"""
|
|
471
|
+
# We check union-sorted, because realizing the set contents would suppress duplicates
|
|
472
|
+
return compare_results(lambda lt, r: sorted(lt | r), left, right)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def check_set_difference(
|
|
476
|
+
left: Union[Set[int], FrozenSet[int]], right: Union[Set[int], FrozenSet[int]]
|
|
477
|
+
) -> ResultComparison:
|
|
478
|
+
"""post: _"""
|
|
479
|
+
return compare_results(lambda lt, r: lt - r, left, right)
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def check_set_intersection(
|
|
483
|
+
left: Union[Set[int], FrozenSet[int]],
|
|
484
|
+
# unlike operators, named methods (set.intersection) can take iterables:
|
|
485
|
+
right: List[int],
|
|
486
|
+
) -> ResultComparison:
|
|
487
|
+
"""post: _"""
|
|
488
|
+
return compare_results(lambda lt, r: lt.intersection(r), left, right)
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
def check_set_compare(
|
|
492
|
+
left: Union[Set[int], FrozenSet[int]], right: Union[Set[int], FrozenSet[int]]
|
|
493
|
+
) -> ResultComparison:
|
|
494
|
+
"""
|
|
495
|
+
pre: len(left) + len(right) <= 4
|
|
496
|
+
post: _
|
|
497
|
+
"""
|
|
498
|
+
# crosshair: max_uninteresting_iterations=75
|
|
499
|
+
# (running this a little longer - it's been able to detect deepcopy memo
|
|
500
|
+
# keepalive issues in the past)
|
|
501
|
+
return compare_results(lambda lt, r: lt <= r, left, right)
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
def check_set_bool(setobj: Union[Set[int], FrozenSet[int]]) -> ResultComparison:
|
|
505
|
+
"""post: _"""
|
|
506
|
+
return compare_results(lambda s: s, bool(setobj))
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def check_seq_concat_and_slice(seq1: List[int], seq2: List[int], slc: slice):
|
|
510
|
+
"""post: _"""
|
|
511
|
+
return compare_results(lambda s1, s2, c: (s1 + s2)[c], seq1, seq2, slc)
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
# Check int methods
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
if sys.version_info >= (3, 10):
|
|
518
|
+
|
|
519
|
+
def check_int_bit_count(val: int):
|
|
520
|
+
"""post: _"""
|
|
521
|
+
realize(val in range(-3, 3))
|
|
522
|
+
return compare_results(lambda v: v.bit_count(), val)
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
def check_int_bit_length(val: int):
|
|
526
|
+
"""post: _"""
|
|
527
|
+
realize(val in range(-3, 3))
|
|
528
|
+
return compare_results(lambda v: v.bit_length(), val)
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
def check_int_to_bytes(val: int, big: bool, signed: bool):
|
|
532
|
+
"""post: _"""
|
|
533
|
+
realize(val == 2**16)
|
|
534
|
+
return compare_results(
|
|
535
|
+
lambda v, b, s: v.to_bytes(2, "big" if b else "little", signed=s),
|
|
536
|
+
val,
|
|
537
|
+
big,
|
|
538
|
+
signed,
|
|
539
|
+
)
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
# Check string methods
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
def check_str_getitem_index(string: str, idx: int) -> ResultComparison:
|
|
546
|
+
"""post: _"""
|
|
547
|
+
return compare_results(lambda s: s[idx], string)
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
def check_str_getitem_slice(string: str, start: int, end: int) -> ResultComparison:
|
|
551
|
+
"""post: _"""
|
|
552
|
+
return compare_results(lambda s: s[start:end], string)
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
def check_str_capitalize(string: str) -> ResultComparison:
|
|
556
|
+
"""post: _"""
|
|
557
|
+
if string in _TRICKY_UNICODE:
|
|
558
|
+
pass
|
|
559
|
+
return compare_results(lambda s: s.capitalize(), string)
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
def check_str_casefold(string: str) -> ResultComparison:
|
|
563
|
+
"""
|
|
564
|
+
pre: len(string) <= 2
|
|
565
|
+
post: _
|
|
566
|
+
"""
|
|
567
|
+
return compare_results(lambda s: s.casefold(), string)
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
def check_str_center(string: str, size: int, fill: str) -> ResultComparison:
|
|
571
|
+
"""post: _"""
|
|
572
|
+
if not string:
|
|
573
|
+
pass
|
|
574
|
+
if len(string) % 2 == 0:
|
|
575
|
+
pass
|
|
576
|
+
if size % 2 == 0:
|
|
577
|
+
pass
|
|
578
|
+
if fill == " ":
|
|
579
|
+
pass
|
|
580
|
+
return compare_results(lambda s, *a: s.center(*a), string, size, fill)
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
def check_str_contains(needle: str, haystack: str) -> ResultComparison:
|
|
584
|
+
"""post: _"""
|
|
585
|
+
return compare_results(lambda n, h: n in h, needle, haystack)
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
def check_str_contains_against_literal(needle: str) -> ResultComparison:
|
|
589
|
+
"""post: _"""
|
|
590
|
+
return compare_results(lambda n: n in "abc", needle)
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
def check_str_count(
|
|
594
|
+
string: str, sub: str, start: Optional[int], end: Optional[int]
|
|
595
|
+
) -> ResultComparison:
|
|
596
|
+
"""post: _"""
|
|
597
|
+
return compare_results(lambda s, *a: s.count(*a), string, sub, start, end)
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
def check_str_encode_wild(string: str, encoding: str, errors: str) -> ResultComparison:
|
|
601
|
+
"""post: _"""
|
|
602
|
+
return compare_results(lambda s, *a: s.encode(*a), string, encoding, errors)
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
def check_str_endswith(
|
|
606
|
+
string: str, suffix: str, start: Optional[int], end: Optional[int]
|
|
607
|
+
) -> ResultComparison:
|
|
608
|
+
"""post: _"""
|
|
609
|
+
# crosshair: max_uninteresting_iterations=100
|
|
610
|
+
|
|
611
|
+
for i in (len(string), len(suffix), start, end):
|
|
612
|
+
if i is not None and abs(i) >= 1:
|
|
613
|
+
pass
|
|
614
|
+
|
|
615
|
+
return compare_results(
|
|
616
|
+
lambda s, *a, **kw: s.endswith(*a, **kw), string, suffix, start, end
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
def check_str_expandtabs(string: str, tabsize: int) -> ResultComparison:
|
|
621
|
+
"""post: _"""
|
|
622
|
+
return compare_results(lambda s, *a: s.expandtabs(*a), string, tabsize)
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
def check_str_find(
|
|
626
|
+
big: str, little: str, start: Optional[int], end: Optional[int]
|
|
627
|
+
) -> ResultComparison:
|
|
628
|
+
"""post: _"""
|
|
629
|
+
return compare_results(lambda s, *a: s.find(*a), big, little, start, end)
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
def check_str_find_empty(big: str, start: int, end: int):
|
|
633
|
+
"""post: _"""
|
|
634
|
+
# Lots of tricky edge cases when searching for an empty string.
|
|
635
|
+
# Target these cases more narrowly.
|
|
636
|
+
if big != "":
|
|
637
|
+
return True
|
|
638
|
+
return compare_results(lambda s, *a: s.find("", *a), big, start, end)
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
def check_str_fstring(string: str, num: int, lst: List[int]) -> ResultComparison:
|
|
642
|
+
"""post: _"""
|
|
643
|
+
return compare_results(lambda s, n, ls: f"{n:02d}{s}{ls!r}", string, num, lst)
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
def check_str_format(string: str, *args: object, **kwargs: object) -> ResultComparison:
|
|
647
|
+
"""post: _"""
|
|
648
|
+
return compare_results(
|
|
649
|
+
lambda s, *a, **kw: s.format(*a, **kw), string, *args, **kwargs
|
|
650
|
+
)
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
def check_str_format_map(string: str, mapping: Mapping) -> ResultComparison:
|
|
654
|
+
"""post: _"""
|
|
655
|
+
return compare_results(lambda s, *a: s.format_map(*a), string, mapping)
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
def check_str_index(
|
|
659
|
+
string: str, sub: str, start: Optional[int], end: Optional[int]
|
|
660
|
+
) -> ResultComparison:
|
|
661
|
+
"""post: _"""
|
|
662
|
+
return compare_results(lambda s, *a: s.index(*a), string, sub, start, end)
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
def check_str_isalpha(s: str) -> ResultComparison:
|
|
666
|
+
"""post: _"""
|
|
667
|
+
return compare_results(lambda s: s.isalpha(), s)
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
def check_str_isalnum(string: str) -> ResultComparison:
|
|
671
|
+
"""post: _"""
|
|
672
|
+
return compare_results(lambda s: s.isalnum(), string)
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
def check_str_isascii(string: str) -> ResultComparison:
|
|
676
|
+
"""post: _"""
|
|
677
|
+
return compare_results(lambda s: s.isascii(), string)
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
def check_str_isdecimal(string: str) -> ResultComparison:
|
|
681
|
+
"""post: _"""
|
|
682
|
+
return compare_results(lambda s: s.isdecimal(), string)
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
def check_str_isdigit(string: str) -> ResultComparison:
|
|
686
|
+
"""post: _"""
|
|
687
|
+
return compare_results(lambda s: s.isdigit(), string)
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
def check_str_isidentifier(string: str) -> ResultComparison:
|
|
691
|
+
"""post: _"""
|
|
692
|
+
return compare_results(lambda s: s.isidentifier(), string)
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
def check_str_islower(string: str) -> ResultComparison:
|
|
696
|
+
"""post: _"""
|
|
697
|
+
if string in _TRICKY_UNICODE:
|
|
698
|
+
pass
|
|
699
|
+
return compare_results(lambda s: s.islower(), string)
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
def check_str_isnumeric(string: str) -> ResultComparison:
|
|
703
|
+
"""post: _"""
|
|
704
|
+
return compare_results(lambda s: s.isnumeric(), string)
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
def check_str_isprintable(string: str) -> ResultComparison:
|
|
708
|
+
"""post: _"""
|
|
709
|
+
if string in (" ", "\n", "\x01"):
|
|
710
|
+
pass
|
|
711
|
+
return compare_results(lambda s: s.isprintable(), string)
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
def check_str_isspace(string: str) -> ResultComparison:
|
|
715
|
+
"""post: _"""
|
|
716
|
+
return compare_results(lambda s: s.isspace(), string)
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
def check_str_istitle(string: str) -> ResultComparison:
|
|
720
|
+
"""
|
|
721
|
+
pre: len(string) <= 3
|
|
722
|
+
post: _
|
|
723
|
+
"""
|
|
724
|
+
if string in _TRICKY_UNICODE:
|
|
725
|
+
pass
|
|
726
|
+
return compare_results(lambda s: s.istitle(), string)
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
def check_str_isupper(string: str) -> ResultComparison:
|
|
730
|
+
"""post: _"""
|
|
731
|
+
if string in _TRICKY_UNICODE:
|
|
732
|
+
pass
|
|
733
|
+
return compare_results(lambda s: s.isupper(), string)
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
def check_str_join(string: str, seq: Sequence[str]) -> ResultComparison:
|
|
737
|
+
"""post: _"""
|
|
738
|
+
return compare_results(lambda s, *a: s.join(*a), string, seq)
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
def check_str_ljust(string: str, width: int, fill: str) -> ResultComparison:
|
|
742
|
+
"""post: _"""
|
|
743
|
+
return compare_results(lambda s, *a: s.ljust(*a), string, width, fill)
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
def check_str_lower(string: str) -> ResultComparison:
|
|
747
|
+
"""
|
|
748
|
+
pre: len(string) <= 2
|
|
749
|
+
post: _
|
|
750
|
+
"""
|
|
751
|
+
return compare_results(lambda s, *a: s.lower(*a), string)
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
def check_str_lstrip(string: str, chars: str) -> ResultComparison:
|
|
755
|
+
"""post: _"""
|
|
756
|
+
return compare_results(lambda s, *a: s.lstrip(*a), string, chars)
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
def check_str_partition(string: str, sep: str) -> ResultComparison:
|
|
760
|
+
"""post: _"""
|
|
761
|
+
return compare_results(lambda s, *a: s.partition(*a), string, sep)
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
def check_str_replace(
|
|
765
|
+
string: str, old: str, new: str, maxsplit: int
|
|
766
|
+
) -> ResultComparison:
|
|
767
|
+
"""post: _"""
|
|
768
|
+
return compare_results(lambda s, *a: s.replace(*a), string, old, new, maxsplit)
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
def check_str_rfind(
|
|
772
|
+
string: str, substr: str, start: Optional[int], end: Optional[int]
|
|
773
|
+
) -> ResultComparison:
|
|
774
|
+
"""post: _"""
|
|
775
|
+
return compare_results(lambda s, *a: s.rfind(*a), string, substr, start, end)
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
def check_str_rfind_empty(big: str, start: int, end: int):
|
|
779
|
+
"""post: _"""
|
|
780
|
+
# Lots of tricky edge cases when searching for an empty string.
|
|
781
|
+
# Target these cases more narrowly.
|
|
782
|
+
if big != "":
|
|
783
|
+
return True
|
|
784
|
+
return compare_results(lambda s, *a: s.rfind("", *a), big, start, end)
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
def check_str_rindex(
|
|
788
|
+
string: str, sub: str, start: Optional[int], end: Optional[int]
|
|
789
|
+
) -> ResultComparison:
|
|
790
|
+
"""post: _"""
|
|
791
|
+
return compare_results(lambda s, *a: s.rindex(*a), string, sub, start, end)
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
def check_str_rjust(string: str, width: int, fill: str) -> ResultComparison:
|
|
795
|
+
"""post: _"""
|
|
796
|
+
return compare_results(lambda s, *a: s.rjust(*a), string, width, fill)
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
def check_str_rpartition(string: str, sep: str) -> ResultComparison:
|
|
800
|
+
"""post: _"""
|
|
801
|
+
return compare_results(lambda s, *a: s.rpartition(*a), string, sep)
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
def check_str_rsplit(string: str, sep: str, maxsplit: int) -> ResultComparison:
|
|
805
|
+
"""post: _"""
|
|
806
|
+
return compare_results(lambda s, *a: s.rsplit(*a), string, sep, maxsplit)
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
def check_str_rstrip(string: str, chars: str) -> ResultComparison:
|
|
810
|
+
"""post: _"""
|
|
811
|
+
return compare_results(lambda s, *a: s.rstrip(*a), string, chars)
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
def check_str_split(string: str, sep: str, maxsplit: int) -> ResultComparison:
|
|
815
|
+
"""post: _"""
|
|
816
|
+
return compare_results(lambda s, *a: s.split(*a), string, sep, maxsplit)
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
def check_str_splitlines(string: str, keepends: bool) -> ResultComparison:
|
|
820
|
+
"""post: _"""
|
|
821
|
+
if "\r" in string:
|
|
822
|
+
pass
|
|
823
|
+
return compare_results(lambda s, *a: s.splitlines(*a), string, keepends)
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
def check_str_startswith(
|
|
827
|
+
string: str,
|
|
828
|
+
prefix: Union[str, Tuple[str, ...]],
|
|
829
|
+
start: Optional[int],
|
|
830
|
+
end: Optional[int],
|
|
831
|
+
) -> ResultComparison:
|
|
832
|
+
"""post: _"""
|
|
833
|
+
# crosshair: max_uninteresting_iterations=100
|
|
834
|
+
|
|
835
|
+
for i in (len(string), len(prefix), start, end):
|
|
836
|
+
if i is not None and abs(i) >= 1:
|
|
837
|
+
pass
|
|
838
|
+
return compare_results(
|
|
839
|
+
lambda s, *a, **kw: s.startswith(*a, **kw), string, prefix, start, end
|
|
840
|
+
)
|
|
841
|
+
|
|
842
|
+
|
|
843
|
+
def check_str_strip(string: str, chars: str) -> ResultComparison:
|
|
844
|
+
"""post: _"""
|
|
845
|
+
return compare_results(lambda s, *a: s.strip(*a), string, chars)
|
|
846
|
+
|
|
847
|
+
|
|
848
|
+
def check_str_swapcase(string: str):
|
|
849
|
+
"""post: _"""
|
|
850
|
+
if string not in ("Ab", "\u01f2"):
|
|
851
|
+
return True
|
|
852
|
+
return compare_results(lambda s: s.swapcase(), string)
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
def check_str_title(string: str):
|
|
856
|
+
"""post: _"""
|
|
857
|
+
if string not in ("A\u01f2", "aA"):
|
|
858
|
+
return True
|
|
859
|
+
return compare_results(lambda s: s.title(), string)
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
def check_str_translate(
|
|
863
|
+
string: str, tbl: Union[Mapping[int, int], List[str]]
|
|
864
|
+
) -> ResultComparison:
|
|
865
|
+
"""post: _"""
|
|
866
|
+
return compare_results(lambda s, *a: s.translate(*a), string, tbl)
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
def check_str_upper(string: str) -> ResultComparison:
|
|
870
|
+
"""
|
|
871
|
+
pre: len(string) <= 2
|
|
872
|
+
post: _
|
|
873
|
+
"""
|
|
874
|
+
return compare_results(lambda s: s.upper(), string)
|
|
875
|
+
|
|
876
|
+
|
|
877
|
+
def check_str_zfill(string: str, width: int) -> ResultComparison:
|
|
878
|
+
"""post: _"""
|
|
879
|
+
return compare_results(lambda s, *a: s.zfill(*a), string, width)
|
|
880
|
+
|
|
881
|
+
|
|
882
|
+
if sys.version_info >= (3, 9):
|
|
883
|
+
|
|
884
|
+
def check_str_removeprefix(s: str, prefix: str):
|
|
885
|
+
"""post: _"""
|
|
886
|
+
return compare_results(lambda s, *a: s.removeprefix(*a), s, prefix)
|
|
887
|
+
|
|
888
|
+
def check_str_removesuffix(s: str, suffix: str):
|
|
889
|
+
"""post: _"""
|
|
890
|
+
return compare_results(lambda s, *a: s.removesuffix(*a), s, suffix)
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
# Check bytes, bytearray, memoryview methods
|
|
894
|
+
|
|
895
|
+
|
|
896
|
+
def check_buffer_getitem_return_type(container: Union[bytes, bytearray, memoryview]):
|
|
897
|
+
"""post: _"""
|
|
898
|
+
return compare_results(lambda c: type(c[:1]), container)
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
def check_buffer_hex_noargs(container: Union[bytes, bytearray, memoryview]):
|
|
902
|
+
"""post: _"""
|
|
903
|
+
return compare_results(lambda c: c.hex(), container)
|
|
904
|
+
|
|
905
|
+
|
|
906
|
+
def check_buffer_hex(
|
|
907
|
+
container: Union[bytes, bytearray, memoryview], sep: str, bytes_per_sep: int
|
|
908
|
+
):
|
|
909
|
+
"""post: _"""
|
|
910
|
+
return compare_results(lambda c, s, b: c.hex(s, b), container, sep, bytes_per_sep)
|
|
911
|
+
|
|
912
|
+
|
|
913
|
+
def check_buffer_fromhex(hexstr: str):
|
|
914
|
+
"""post: _"""
|
|
915
|
+
return compare_results(lambda s: bytes.fromhex(s), hexstr)
|
|
916
|
+
|
|
917
|
+
|
|
918
|
+
def check_buffer_setitem_splice(container: bytearray):
|
|
919
|
+
"""post: _"""
|
|
920
|
+
|
|
921
|
+
def setter(c):
|
|
922
|
+
c[0:0] = [42]
|
|
923
|
+
return c
|
|
924
|
+
|
|
925
|
+
return compare_results(setter, container)
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
def check_buffer_setitem_add_self(container: memoryview):
|
|
929
|
+
"""post: _"""
|
|
930
|
+
|
|
931
|
+
def setter(c):
|
|
932
|
+
c[0:0] = c
|
|
933
|
+
return c
|
|
934
|
+
|
|
935
|
+
return compare_results(setter, container)
|
|
936
|
+
|
|
937
|
+
|
|
938
|
+
def check_buffer_setitem_replace(
|
|
939
|
+
container: Union[memoryview, bytearray],
|
|
940
|
+
replacement: Union[memoryview, bytearray, bytes],
|
|
941
|
+
realize_at: int,
|
|
942
|
+
):
|
|
943
|
+
"""post: _"""
|
|
944
|
+
|
|
945
|
+
def setter(c, r):
|
|
946
|
+
if r == 0:
|
|
947
|
+
c = realize(c)
|
|
948
|
+
elif r == 1:
|
|
949
|
+
r = realize(r)
|
|
950
|
+
c[0:1] = r
|
|
951
|
+
return c
|
|
952
|
+
|
|
953
|
+
return compare_results(setter, container, replacement)
|
|
954
|
+
|
|
955
|
+
|
|
956
|
+
def check_buffer_crosstype_addition(
|
|
957
|
+
buffer1: Union[bytes, bytearray, memoryview],
|
|
958
|
+
buffer2: Union[bytes, bytearray, memoryview],
|
|
959
|
+
realize_at: int,
|
|
960
|
+
):
|
|
961
|
+
"""post: _"""
|
|
962
|
+
|
|
963
|
+
def adder(b1, b2, r):
|
|
964
|
+
if r == 0:
|
|
965
|
+
b1 = realize(b1)
|
|
966
|
+
elif r == 1:
|
|
967
|
+
b2 = realize(b2)
|
|
968
|
+
return b1 + b2
|
|
969
|
+
|
|
970
|
+
return compare_results(adder, buffer1, buffer2, realize_at)
|
|
971
|
+
|
|
972
|
+
|
|
973
|
+
def check_buffer_add_return_type(container: Union[bytearray, memoryview]):
|
|
974
|
+
"""post: _"""
|
|
975
|
+
return compare_results(lambda c: type(c + b"abc"), container)
|
|
976
|
+
|
|
977
|
+
|
|
978
|
+
def check_bytes___init__(source: Union[int, List[int], bytes, bytearray, memoryview]):
|
|
979
|
+
"""
|
|
980
|
+
post: _
|
|
981
|
+
raises: KeyError
|
|
982
|
+
"""
|
|
983
|
+
return compare_results(lambda c, s: c(s), bytes, source)
|
|
984
|
+
|
|
985
|
+
|
|
986
|
+
def check_bytearray___init__(
|
|
987
|
+
source: Union[int, List[int], bytes, bytearray, memoryview],
|
|
988
|
+
):
|
|
989
|
+
"""
|
|
990
|
+
post: _
|
|
991
|
+
raises: KeyError
|
|
992
|
+
"""
|
|
993
|
+
return compare_results(lambda c, s: c(s), bytearray, source)
|
|
994
|
+
|
|
995
|
+
|
|
996
|
+
def check_memoryview___init__(
|
|
997
|
+
source: Union[int, List[int], bytes, bytearray, memoryview],
|
|
998
|
+
):
|
|
999
|
+
"""
|
|
1000
|
+
post: _
|
|
1001
|
+
raises: KeyError
|
|
1002
|
+
"""
|
|
1003
|
+
return compare_results(lambda c, s: c(s), memoryview, source)
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
def check_buffer_iter(container: Union[bytes, bytearray, memoryview]):
|
|
1007
|
+
"""post: _"""
|
|
1008
|
+
return compare_results(list, container)
|
|
1009
|
+
|
|
1010
|
+
|
|
1011
|
+
def check_buffer_equal(
|
|
1012
|
+
buffer1: Union[bytes, bytearray, memoryview],
|
|
1013
|
+
buffer2: Union[bytes, bytearray, memoryview],
|
|
1014
|
+
realize_at: int,
|
|
1015
|
+
):
|
|
1016
|
+
"""post: _"""
|
|
1017
|
+
|
|
1018
|
+
def compare(b1, b2, r):
|
|
1019
|
+
if r == 0:
|
|
1020
|
+
b1 = realize(b1)
|
|
1021
|
+
elif r == 1:
|
|
1022
|
+
b2 = realize(b2)
|
|
1023
|
+
return b1 == b2
|
|
1024
|
+
|
|
1025
|
+
return compare_results(compare, buffer1, buffer2, realize_at)
|
|
1026
|
+
|
|
1027
|
+
|
|
1028
|
+
def check_buffer_compare(
|
|
1029
|
+
buffer1: Union[bytes, bytearray, memoryview],
|
|
1030
|
+
buffer2: Union[bytes, bytearray, memoryview],
|
|
1031
|
+
realize_at: int,
|
|
1032
|
+
):
|
|
1033
|
+
"""post: _"""
|
|
1034
|
+
|
|
1035
|
+
def compare(b1, b2, r):
|
|
1036
|
+
if r == 0:
|
|
1037
|
+
b1 = realize(b1)
|
|
1038
|
+
elif r == 1:
|
|
1039
|
+
b2 = realize(b2)
|
|
1040
|
+
# A lot of esotric Python behaviors in (<); see comments in BytesLike._cmp_op.
|
|
1041
|
+
return b1 < b2
|
|
1042
|
+
|
|
1043
|
+
return compare_results(compare, buffer1, buffer2, realize_at)
|
|
1044
|
+
|
|
1045
|
+
|
|
1046
|
+
def check_buffer_percent_format(buffer: Union[bytes, bytearray, memoryview]):
|
|
1047
|
+
"""post: _"""
|
|
1048
|
+
return compare_results(lambda b: b"%04b" % b, buffer)
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
def check_memoryview_conversions(view: memoryview):
|
|
1052
|
+
"""post: _"""
|
|
1053
|
+
if len(view) == 1:
|
|
1054
|
+
pass
|
|
1055
|
+
return compare_results(
|
|
1056
|
+
lambda mv: (mv.tobytes(), mv.tolist(), mv.hex(), mv.cast("b")), view
|
|
1057
|
+
)
|
|
1058
|
+
|
|
1059
|
+
|
|
1060
|
+
# Check operators
|
|
1061
|
+
|
|
1062
|
+
|
|
1063
|
+
def check_add_seqs(seq: Union[str, bytes, bytearray, List[int], Tuple[int, ...]]):
|
|
1064
|
+
"""
|
|
1065
|
+
pre: len(seq) == 1
|
|
1066
|
+
post: _
|
|
1067
|
+
"""
|
|
1068
|
+
|
|
1069
|
+
def f(s):
|
|
1070
|
+
combined = s + s
|
|
1071
|
+
return (combined, type(combined))
|
|
1072
|
+
|
|
1073
|
+
return compare_results(f, seq)
|
|
1074
|
+
|
|
1075
|
+
|
|
1076
|
+
def check_and(left: int):
|
|
1077
|
+
"""post: _"""
|
|
1078
|
+
return compare_results(lambda lt: (lt & 3, 4 & lt), left)
|
|
1079
|
+
|
|
1080
|
+
|
|
1081
|
+
def check_xor(left: Union[int, bool], right: Union[int, bool]):
|
|
1082
|
+
"""post: _"""
|
|
1083
|
+
return compare_results(operator.xor, left, right)
|
|
1084
|
+
|
|
1085
|
+
|
|
1086
|
+
def check_truediv(left: Union[int, float], right: Union[int, float]):
|
|
1087
|
+
"""post: _"""
|
|
1088
|
+
return compare_returns(operator.truediv, left, right)
|
|
1089
|
+
|
|
1090
|
+
|
|
1091
|
+
def check_lt_strings(left: str, right: str):
|
|
1092
|
+
"""post: _"""
|
|
1093
|
+
return compare_results(operator.lt, left, right)
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
def check_ge_numeric(
|
|
1097
|
+
left: Union[int, bool, float, complex], right: Union[int, bool, float, complex]
|
|
1098
|
+
):
|
|
1099
|
+
"""post: _"""
|
|
1100
|
+
return compare_returns(operator.ge, left, right)
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
def check_mod(
|
|
1104
|
+
left: Union[int, bool, float, complex], right: Union[int, bool, float, complex]
|
|
1105
|
+
):
|
|
1106
|
+
"""post: _"""
|
|
1107
|
+
if left == 0 or right == 0:
|
|
1108
|
+
pass
|
|
1109
|
+
return compare_returns(operator.mod, left, right)
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
def check_floordiv(x: Union[int, float], y: Union[int, float]) -> ResultComparison:
|
|
1113
|
+
"""post: _"""
|
|
1114
|
+
if y == 0 or x == 0:
|
|
1115
|
+
pass
|
|
1116
|
+
return compare_returns(operator.floordiv, x, y)
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
def check_getitem(
|
|
1120
|
+
container: Union[Dict[int, int], List[int], Tuple[int, ...]], key: int
|
|
1121
|
+
):
|
|
1122
|
+
"""post: _"""
|
|
1123
|
+
return compare_results(lambda d, k: d[k], container, key)
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
def check_getitem_slice(
|
|
1127
|
+
container: Union[List[int], Tuple[int, ...], str, bytes, bytearray], key: slice
|
|
1128
|
+
):
|
|
1129
|
+
"""post: _"""
|
|
1130
|
+
|
|
1131
|
+
def f(d, s):
|
|
1132
|
+
ret = d[s]
|
|
1133
|
+
return (ret, type(ret))
|
|
1134
|
+
|
|
1135
|
+
return compare_results(f, container, key)
|
|
1136
|
+
|
|
1137
|
+
|
|
1138
|
+
def check_delitem_int(container: Union[Dict[int, int], List[int]], key: int):
|
|
1139
|
+
"""post: _"""
|
|
1140
|
+
|
|
1141
|
+
def checker(d, k):
|
|
1142
|
+
del d[k]
|
|
1143
|
+
return d
|
|
1144
|
+
|
|
1145
|
+
return compare_results(checker, container, key)
|
|
1146
|
+
|
|
1147
|
+
|
|
1148
|
+
def check_delitem_slice(container: List[int], key: slice):
|
|
1149
|
+
"""post: _"""
|
|
1150
|
+
|
|
1151
|
+
def checker(d, k):
|
|
1152
|
+
del d[k]
|
|
1153
|
+
return d
|
|
1154
|
+
|
|
1155
|
+
return compare_results(checker, container, key)
|
|
1156
|
+
|
|
1157
|
+
|
|
1158
|
+
def check_inplace_mutation(container: Union[bytearray, List[int], Dict[int, int]]):
|
|
1159
|
+
"""post: _"""
|
|
1160
|
+
|
|
1161
|
+
def setter(c):
|
|
1162
|
+
if c:
|
|
1163
|
+
c[0] &= 42
|
|
1164
|
+
return c
|
|
1165
|
+
|
|
1166
|
+
return compare_results(setter, container)
|
|
1167
|
+
|
|
1168
|
+
|
|
1169
|
+
def check_eq_atomic(
|
|
1170
|
+
left: Union[bool, int, float, str], right: Union[bool, int, float, str]
|
|
1171
|
+
):
|
|
1172
|
+
"""post: _"""
|
|
1173
|
+
return compare_returns(lambda a, b: a == b, left, right)
|
|
1174
|
+
|
|
1175
|
+
|
|
1176
|
+
def check_trunc(num: Union[bool, int, float]):
|
|
1177
|
+
"""post: _"""
|
|
1178
|
+
if num >= 0:
|
|
1179
|
+
pass
|
|
1180
|
+
return compare_returns(lambda n: n.__trunc__(), num)
|
|
1181
|
+
|
|
1182
|
+
|
|
1183
|
+
# This is the only real test definition.
|
|
1184
|
+
# It runs crosshair on each of the "check" functions defined above.
|
|
1185
|
+
@pytest.mark.parametrize("fn_name", [fn for fn in dir() if fn.startswith("check_")])
|
|
1186
|
+
def test_builtin(fn_name: str) -> None:
|
|
1187
|
+
this_module = sys.modules[__name__]
|
|
1188
|
+
fn = getattr(this_module, fn_name)
|
|
1189
|
+
messages = run_checkables(analyze_function(fn))
|
|
1190
|
+
errors = [m for m in messages if m.state > MessageType.PRE_UNSAT]
|
|
1191
|
+
assert errors == []
|