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,354 @@
|
|
|
1
|
+
import operator
|
|
2
|
+
import sys
|
|
3
|
+
from datetime import date, datetime, time, timedelta, timezone, tzinfo
|
|
4
|
+
from typing import Tuple, Union
|
|
5
|
+
|
|
6
|
+
import pytest # type: ignore
|
|
7
|
+
|
|
8
|
+
from crosshair.core_and_libs import MessageType, analyze_function, run_checkables
|
|
9
|
+
from crosshair.test_util import ResultComparison, compare_results, compare_returns
|
|
10
|
+
|
|
11
|
+
# crosshair: max_uninteresting_iterations=10
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _invoker(method_name):
|
|
15
|
+
def invoke(obj, *args):
|
|
16
|
+
return getattr(obj, method_name)(*args)
|
|
17
|
+
|
|
18
|
+
return invoke
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# TODO: test replace(); test realize?
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# special methods
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def check_datetimelib_lt(
|
|
28
|
+
p: Union[
|
|
29
|
+
Tuple[timedelta, timedelta],
|
|
30
|
+
Tuple[date, datetime],
|
|
31
|
+
Tuple[datetime, datetime],
|
|
32
|
+
],
|
|
33
|
+
) -> ResultComparison:
|
|
34
|
+
"""post: _"""
|
|
35
|
+
return compare_results(operator.lt, *p)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def check_datetimelib_add(
|
|
39
|
+
p: Union[
|
|
40
|
+
Tuple[timedelta, timedelta],
|
|
41
|
+
Tuple[date, timedelta],
|
|
42
|
+
Tuple[timedelta, datetime],
|
|
43
|
+
],
|
|
44
|
+
) -> ResultComparison:
|
|
45
|
+
"""post: _"""
|
|
46
|
+
return compare_results(operator.add, *p)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def check_datetimelib_subtract(
|
|
50
|
+
p: Union[
|
|
51
|
+
Tuple[timedelta, timedelta],
|
|
52
|
+
Tuple[date, timedelta],
|
|
53
|
+
Tuple[datetime, timedelta],
|
|
54
|
+
Tuple[datetime, datetime],
|
|
55
|
+
],
|
|
56
|
+
) -> ResultComparison:
|
|
57
|
+
"""post: _"""
|
|
58
|
+
return compare_results(operator.sub, *p)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def check_datetimelib_str(
|
|
62
|
+
obj: Union[timedelta, timezone, date, time, datetime],
|
|
63
|
+
) -> ResultComparison:
|
|
64
|
+
"""post: _"""
|
|
65
|
+
return compare_results(_invoker("__str__"), obj)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def check_datetimelib_repr(
|
|
69
|
+
# TODO: re-enable time, datetime repr checking after fixing in Python 3.11
|
|
70
|
+
obj: Union[timedelta, timezone, date],
|
|
71
|
+
) -> ResultComparison:
|
|
72
|
+
"""post: _"""
|
|
73
|
+
return compare_results(_invoker("__repr__"), obj)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# timedelta
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def check_timedelta_new(
|
|
80
|
+
# `days` and `secs` can be floats but imprecision can cause this test to fail
|
|
81
|
+
# right now. Start testing floats once we fix this issue:
|
|
82
|
+
# https://github.com/pschanely/CrossHair/issues/230
|
|
83
|
+
days: int,
|
|
84
|
+
secs: int,
|
|
85
|
+
microsecs: Union[int, float],
|
|
86
|
+
) -> ResultComparison:
|
|
87
|
+
"""post: _"""
|
|
88
|
+
if days % 1 != 0 or secs % 1 != 0 or microsecs % 1 != 0:
|
|
89
|
+
pass
|
|
90
|
+
return compare_returns(lambda *a: timedelta(*a), days, secs, microsecs)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def check_timedelta_bool(td: timedelta) -> ResultComparison:
|
|
94
|
+
"""post: _"""
|
|
95
|
+
return compare_results(_invoker("__bool__"), td)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def check_timedelta_neg(td: timedelta) -> ResultComparison:
|
|
99
|
+
"""post: _"""
|
|
100
|
+
return compare_results(_invoker("__neg__"), td)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def check_timedelta_abs(td: timedelta) -> ResultComparison:
|
|
104
|
+
"""post: _"""
|
|
105
|
+
return compare_results(_invoker("__abs__"), td)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def check_timedelta_truediv(
|
|
109
|
+
numerator: timedelta, denominator: Union[timedelta, int]
|
|
110
|
+
) -> ResultComparison:
|
|
111
|
+
"""post: _"""
|
|
112
|
+
return compare_results(operator.truediv, numerator, denominator)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def check_timedelta_floordiv(
|
|
116
|
+
numerator: timedelta, denominator: Union[timedelta, int]
|
|
117
|
+
) -> ResultComparison:
|
|
118
|
+
"""post: _"""
|
|
119
|
+
return compare_results(operator.floordiv, numerator, denominator)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def check_timedelta_multiply(td: timedelta, factor: int) -> ResultComparison:
|
|
123
|
+
"""post: _"""
|
|
124
|
+
return compare_results(operator.mul, td, factor)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def check_timedelta_divmod(
|
|
128
|
+
numerator: timedelta, denominator: timedelta
|
|
129
|
+
) -> ResultComparison:
|
|
130
|
+
"""post: _"""
|
|
131
|
+
return compare_results(divmod, numerator, denominator)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def check_timedelta_total_seconds(td: timedelta) -> ResultComparison:
|
|
135
|
+
"""post: _"""
|
|
136
|
+
return compare_results(_invoker("total_seconds"), td)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# date
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def check_date_replace(dt: date, year: int) -> ResultComparison:
|
|
143
|
+
"""post: _"""
|
|
144
|
+
return compare_results(lambda d, m, u: dt.replace(year=year), dt, year)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def check_date_timetuple(dt: date) -> ResultComparison:
|
|
148
|
+
"""post: _"""
|
|
149
|
+
return compare_results(_invoker("timetuple"), dt)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def check_date_toordinal(dt: date) -> ResultComparison:
|
|
153
|
+
"""post: _"""
|
|
154
|
+
return compare_results(_invoker("toordinal"), dt)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def check_date_weekday(dt: date) -> ResultComparison:
|
|
158
|
+
"""post: _"""
|
|
159
|
+
return compare_results(_invoker("weekday"), dt)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def check_date_isoweekday(dt: date) -> ResultComparison:
|
|
163
|
+
"""post: _"""
|
|
164
|
+
return compare_results(_invoker("isoweekday"), dt)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def check_date_isocalendar(dt: date) -> ResultComparison:
|
|
168
|
+
"""post: _"""
|
|
169
|
+
return compare_results(_invoker("isocalendar"), dt)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def check_date_isoformat(dt: date) -> ResultComparison:
|
|
173
|
+
"""post: _"""
|
|
174
|
+
return compare_results(_invoker("isoformat"), dt)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def check_date_ctime(dt: date) -> ResultComparison:
|
|
178
|
+
"""post: _"""
|
|
179
|
+
return compare_results(_invoker("ctime"), dt)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def check_date_strftime(dt: date, fmt: str) -> ResultComparison:
|
|
183
|
+
"""post: _"""
|
|
184
|
+
return compare_results(_invoker("strftime"), dt, fmt)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
# datetime
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def check_datetime_date(dt: datetime) -> ResultComparison:
|
|
191
|
+
"""post: _"""
|
|
192
|
+
return compare_results(_invoker("date"), dt)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def check_datetime_time(dt: datetime) -> ResultComparison:
|
|
196
|
+
"""post: _"""
|
|
197
|
+
return compare_results(_invoker("time"), dt)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def check_datetime_timetz(dt: datetime) -> ResultComparison:
|
|
201
|
+
"""post: _"""
|
|
202
|
+
return compare_results(_invoker("timetz"), dt)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def check_datetime_replace(
|
|
206
|
+
dt: datetime, month: int, microsecond: int
|
|
207
|
+
) -> ResultComparison:
|
|
208
|
+
"""post: _"""
|
|
209
|
+
return compare_results(
|
|
210
|
+
lambda d, m, u: d.replace(month=m, microsecond=u), dt, month, microsecond
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def check_datetime_astimezone(dt: datetime, tz: tzinfo) -> ResultComparison:
|
|
215
|
+
"""post: _"""
|
|
216
|
+
# crosshair: max_uninteresting_iterations=3
|
|
217
|
+
return compare_results(_invoker("astimezone"), dt, tz)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def check_datetime_utcoffset(dt: datetime) -> ResultComparison:
|
|
221
|
+
"""post: _"""
|
|
222
|
+
return compare_results(_invoker("utcoffset"), dt)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def check_datetime_dst(dt: datetime) -> ResultComparison:
|
|
226
|
+
"""post: _"""
|
|
227
|
+
return compare_results(_invoker("dst"), dt)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def check_datetime_tzname(dt: datetime) -> ResultComparison:
|
|
231
|
+
"""post: _"""
|
|
232
|
+
return compare_results(_invoker("tzname"), dt)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def check_datetime_timetuple(dt: datetime) -> ResultComparison:
|
|
236
|
+
"""post: _"""
|
|
237
|
+
return compare_results(_invoker("timetuple"), dt)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def check_datetime_utctimetuple(dt: datetime) -> ResultComparison:
|
|
241
|
+
"""post: _"""
|
|
242
|
+
# crosshair: max_uninteresting_iterations=5
|
|
243
|
+
return compare_results(_invoker("utctimetuple"), dt)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def check_datetime_toordinal(dt: datetime) -> ResultComparison:
|
|
247
|
+
"""post: _"""
|
|
248
|
+
return compare_results(_invoker("toordinal"), dt)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def check_datetime_timestamp(dt: datetime) -> ResultComparison:
|
|
252
|
+
"""post: _"""
|
|
253
|
+
return compare_results(_invoker("timestamp"), dt)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def check_datetime_weekday(dt: datetime) -> ResultComparison:
|
|
257
|
+
"""post: _"""
|
|
258
|
+
return compare_results(_invoker("weekday"), dt)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def check_datetime_isoweekday(dt: datetime) -> ResultComparison:
|
|
262
|
+
"""post: _"""
|
|
263
|
+
return compare_results(_invoker("isoweekday"), dt)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def check_datetime_isocalendar(dt: datetime) -> ResultComparison:
|
|
267
|
+
"""post: _"""
|
|
268
|
+
return compare_results(_invoker("isocalendar"), dt)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def check_datetime_isoformat(dt: datetime) -> ResultComparison:
|
|
272
|
+
"""post: _"""
|
|
273
|
+
return compare_results(_invoker("isoformat"), dt)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def check_datetime_ctime(dt: datetime) -> ResultComparison:
|
|
277
|
+
"""post: _"""
|
|
278
|
+
return compare_results(_invoker("ctime"), dt)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def check_datetime_strftime(dt: datetime, fmt: str) -> ResultComparison:
|
|
282
|
+
"""post: _"""
|
|
283
|
+
# not using skipIf because this is invoked via `test_builtin`:
|
|
284
|
+
if sys.version_info < (3, 13):
|
|
285
|
+
# strftime null character handling aligned between python and C
|
|
286
|
+
# implementations in https://github.com/python/cpython/pull/125657
|
|
287
|
+
return True
|
|
288
|
+
return compare_results(_invoker("strftime"), dt, fmt)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
# time
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def check_time_replace(tm: time, hour: int) -> ResultComparison:
|
|
295
|
+
"""post: _"""
|
|
296
|
+
return compare_results(lambda t, h: t.replace(hour=h), tm, hour)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def check_time_isoformat(tm: time) -> ResultComparison:
|
|
300
|
+
"""post: _"""
|
|
301
|
+
return compare_results(_invoker("isoformat"), tm)
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def check_time_strftime(tm: time, fmt: str) -> ResultComparison:
|
|
305
|
+
"""post: _"""
|
|
306
|
+
return compare_results(_invoker("strftime"), tm, fmt)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def check_time_utcoffset(tm: time) -> ResultComparison:
|
|
310
|
+
"""post: _"""
|
|
311
|
+
return compare_results(_invoker("utcoffset"), tm)
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def check_time_dst(tm: time) -> ResultComparison:
|
|
315
|
+
"""post: _"""
|
|
316
|
+
return compare_results(_invoker("dst"), tm)
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def check_time_tzname(tm: time) -> ResultComparison:
|
|
320
|
+
"""post: _"""
|
|
321
|
+
return compare_results(_invoker("tzname"), tm)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
# timezone
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def check_timezone_utcoffset(tz: timezone, dt: datetime) -> ResultComparison:
|
|
328
|
+
"""post: _"""
|
|
329
|
+
return compare_results(_invoker("utcoffset"), tz, dt)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def check_timezone_dst(tz: timezone, dt: datetime) -> ResultComparison:
|
|
333
|
+
"""post: _"""
|
|
334
|
+
return compare_results(_invoker("dst"), tz, dt)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def check_timezone_tzname(tz: timezone, dt: datetime) -> ResultComparison:
|
|
338
|
+
"""post: _"""
|
|
339
|
+
return compare_results(_invoker("tzname"), tz, dt)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def check_timezone_fromutc(tz: timezone, dt: datetime) -> ResultComparison:
|
|
343
|
+
"""post: _"""
|
|
344
|
+
return compare_results(_invoker("fromutc"), tz, dt)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
# This is the only real test definition.
|
|
348
|
+
# It runs crosshair on each of the "check" functions defined above.
|
|
349
|
+
@pytest.mark.parametrize("fn_name", [fn for fn in dir() if fn.startswith("check_")])
|
|
350
|
+
def test_builtin(fn_name: str) -> None:
|
|
351
|
+
this_module = sys.modules[__name__]
|
|
352
|
+
messages = run_checkables(analyze_function(getattr(this_module, fn_name)))
|
|
353
|
+
errors = [m for m in messages if m.state > MessageType.PRE_UNSAT]
|
|
354
|
+
assert errors == []
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from crosshair.statespace import CONFIRMED, EXEC_ERR, POST_FAIL
|
|
6
|
+
from crosshair.test_util import check_states
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_timedelta_symbolic_months_fail() -> None:
|
|
10
|
+
def f(num_months: int) -> datetime.date:
|
|
11
|
+
"""
|
|
12
|
+
pre: 0 <= num_months <= 100
|
|
13
|
+
post: _.year != 2003
|
|
14
|
+
"""
|
|
15
|
+
dt = datetime.date(2000, 1, 1)
|
|
16
|
+
return dt + datetime.timedelta(days=30 * num_months)
|
|
17
|
+
|
|
18
|
+
check_states(f, POST_FAIL)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.mark.demo
|
|
22
|
+
def test_date___init___method() -> None:
|
|
23
|
+
def f(dt: datetime.date) -> datetime.date:
|
|
24
|
+
"""
|
|
25
|
+
Is February 29th ever part of a valid date?
|
|
26
|
+
(it is on leap years)
|
|
27
|
+
|
|
28
|
+
post: (dt.month, dt.day) != (2, 29)
|
|
29
|
+
"""
|
|
30
|
+
return dt
|
|
31
|
+
|
|
32
|
+
check_states(f, POST_FAIL)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_time_fail() -> None:
|
|
36
|
+
def f(dt: datetime.time) -> int:
|
|
37
|
+
"""
|
|
38
|
+
post: _ != 14
|
|
39
|
+
"""
|
|
40
|
+
return dt.hour
|
|
41
|
+
|
|
42
|
+
check_states(f, POST_FAIL)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_datetime_fail() -> None:
|
|
46
|
+
def f(dtime: datetime.datetime) -> int:
|
|
47
|
+
"""
|
|
48
|
+
post: _ != 22
|
|
49
|
+
"""
|
|
50
|
+
return dtime.second
|
|
51
|
+
|
|
52
|
+
check_states(f, POST_FAIL)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_timedelta_fail() -> None:
|
|
56
|
+
def f(d: datetime.timedelta) -> int:
|
|
57
|
+
"""
|
|
58
|
+
post: _ != 9
|
|
59
|
+
"""
|
|
60
|
+
return d.seconds
|
|
61
|
+
|
|
62
|
+
check_states(f, POST_FAIL)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_date_plus_delta_fail() -> None:
|
|
66
|
+
def f(delta: datetime.timedelta) -> datetime.date:
|
|
67
|
+
"""
|
|
68
|
+
post: _.year != 2033
|
|
69
|
+
raises: OverflowError
|
|
70
|
+
"""
|
|
71
|
+
return datetime.date(2000, 1, 1) + delta
|
|
72
|
+
|
|
73
|
+
check_states(f, POST_FAIL)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_date_plus_delta_overflow_err() -> None:
|
|
77
|
+
def f(delta: datetime.timedelta) -> datetime.date:
|
|
78
|
+
"""
|
|
79
|
+
post: True
|
|
80
|
+
"""
|
|
81
|
+
return datetime.date(2000, 1, 1) + delta
|
|
82
|
+
|
|
83
|
+
check_states(f, EXEC_ERR)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@pytest.mark.demo("yellow")
|
|
87
|
+
def test_timedelta___add___method() -> None:
|
|
88
|
+
def f(delta: datetime.timedelta) -> datetime.date:
|
|
89
|
+
"""
|
|
90
|
+
Can we increment 2000-01-01 by some time delta to reach 2001?
|
|
91
|
+
|
|
92
|
+
NOTE: Although this counterexample is found relatively quickly,
|
|
93
|
+
most date arithmetic solutions will require at least a minute
|
|
94
|
+
of processing time.
|
|
95
|
+
|
|
96
|
+
post: _.year != 2001
|
|
97
|
+
raises: OverflowError
|
|
98
|
+
"""
|
|
99
|
+
return datetime.date(2000, 1, 1) + delta
|
|
100
|
+
|
|
101
|
+
check_states(f, POST_FAIL)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def TODO_test_leap_year() -> None:
|
|
105
|
+
# The solver returns unknown when adding a delta to a symbolic date. (nonlinear I think)
|
|
106
|
+
def f(start: datetime.date) -> datetime.date:
|
|
107
|
+
"""
|
|
108
|
+
post: _.year == start.year + 1
|
|
109
|
+
"""
|
|
110
|
+
return start + datetime.timedelta(days=365)
|
|
111
|
+
|
|
112
|
+
check_states(f, POST_FAIL)
|