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.
Files changed (176) hide show
  1. _crosshair_tracers.cpython-312-darwin.so +0 -0
  2. crosshair/__init__.py +42 -0
  3. crosshair/__main__.py +8 -0
  4. crosshair/_mark_stacks.h +790 -0
  5. crosshair/_preliminaries_test.py +18 -0
  6. crosshair/_tracers.h +94 -0
  7. crosshair/_tracers_pycompat.h +522 -0
  8. crosshair/_tracers_test.py +138 -0
  9. crosshair/abcstring.py +245 -0
  10. crosshair/auditwall.py +190 -0
  11. crosshair/auditwall_test.py +77 -0
  12. crosshair/codeconfig.py +113 -0
  13. crosshair/codeconfig_test.py +117 -0
  14. crosshair/condition_parser.py +1237 -0
  15. crosshair/condition_parser_test.py +497 -0
  16. crosshair/conftest.py +30 -0
  17. crosshair/copyext.py +155 -0
  18. crosshair/copyext_test.py +84 -0
  19. crosshair/core.py +1763 -0
  20. crosshair/core_and_libs.py +149 -0
  21. crosshair/core_regestered_types_test.py +82 -0
  22. crosshair/core_test.py +1316 -0
  23. crosshair/diff_behavior.py +314 -0
  24. crosshair/diff_behavior_test.py +261 -0
  25. crosshair/dynamic_typing.py +346 -0
  26. crosshair/dynamic_typing_test.py +210 -0
  27. crosshair/enforce.py +282 -0
  28. crosshair/enforce_test.py +182 -0
  29. crosshair/examples/PEP316/__init__.py +1 -0
  30. crosshair/examples/PEP316/bugs_detected/__init__.py +0 -0
  31. crosshair/examples/PEP316/bugs_detected/getattr_magic.py +16 -0
  32. crosshair/examples/PEP316/bugs_detected/hash_consistent_with_equals.py +31 -0
  33. crosshair/examples/PEP316/bugs_detected/shopping_cart.py +24 -0
  34. crosshair/examples/PEP316/bugs_detected/showcase.py +39 -0
  35. crosshair/examples/PEP316/correct_code/__init__.py +0 -0
  36. crosshair/examples/PEP316/correct_code/arith.py +60 -0
  37. crosshair/examples/PEP316/correct_code/chess.py +77 -0
  38. crosshair/examples/PEP316/correct_code/nesting_inference.py +17 -0
  39. crosshair/examples/PEP316/correct_code/numpy_examples.py +132 -0
  40. crosshair/examples/PEP316/correct_code/rolling_average.py +35 -0
  41. crosshair/examples/PEP316/correct_code/showcase.py +104 -0
  42. crosshair/examples/__init__.py +0 -0
  43. crosshair/examples/check_examples_test.py +146 -0
  44. crosshair/examples/deal/__init__.py +1 -0
  45. crosshair/examples/icontract/__init__.py +1 -0
  46. crosshair/examples/icontract/bugs_detected/__init__.py +0 -0
  47. crosshair/examples/icontract/bugs_detected/showcase.py +41 -0
  48. crosshair/examples/icontract/bugs_detected/wrong_sign.py +8 -0
  49. crosshair/examples/icontract/correct_code/__init__.py +0 -0
  50. crosshair/examples/icontract/correct_code/arith.py +51 -0
  51. crosshair/examples/icontract/correct_code/showcase.py +94 -0
  52. crosshair/fnutil.py +391 -0
  53. crosshair/fnutil_test.py +75 -0
  54. crosshair/fuzz_core_test.py +516 -0
  55. crosshair/libimpl/__init__.py +0 -0
  56. crosshair/libimpl/arraylib.py +161 -0
  57. crosshair/libimpl/binascii_ch_test.py +30 -0
  58. crosshair/libimpl/binascii_test.py +67 -0
  59. crosshair/libimpl/binasciilib.py +150 -0
  60. crosshair/libimpl/bisectlib_test.py +23 -0
  61. crosshair/libimpl/builtinslib.py +5228 -0
  62. crosshair/libimpl/builtinslib_ch_test.py +1191 -0
  63. crosshair/libimpl/builtinslib_test.py +3735 -0
  64. crosshair/libimpl/codecslib.py +86 -0
  65. crosshair/libimpl/codecslib_test.py +86 -0
  66. crosshair/libimpl/collectionslib.py +264 -0
  67. crosshair/libimpl/collectionslib_ch_test.py +252 -0
  68. crosshair/libimpl/collectionslib_test.py +332 -0
  69. crosshair/libimpl/copylib.py +23 -0
  70. crosshair/libimpl/copylib_test.py +18 -0
  71. crosshair/libimpl/datetimelib.py +2559 -0
  72. crosshair/libimpl/datetimelib_ch_test.py +354 -0
  73. crosshair/libimpl/datetimelib_test.py +112 -0
  74. crosshair/libimpl/decimallib.py +5257 -0
  75. crosshair/libimpl/decimallib_ch_test.py +78 -0
  76. crosshair/libimpl/decimallib_test.py +76 -0
  77. crosshair/libimpl/encodings/__init__.py +23 -0
  78. crosshair/libimpl/encodings/_encutil.py +187 -0
  79. crosshair/libimpl/encodings/ascii.py +44 -0
  80. crosshair/libimpl/encodings/latin_1.py +40 -0
  81. crosshair/libimpl/encodings/utf_8.py +93 -0
  82. crosshair/libimpl/encodings_ch_test.py +83 -0
  83. crosshair/libimpl/fractionlib.py +16 -0
  84. crosshair/libimpl/fractionlib_test.py +80 -0
  85. crosshair/libimpl/functoolslib.py +34 -0
  86. crosshair/libimpl/functoolslib_test.py +56 -0
  87. crosshair/libimpl/hashliblib.py +30 -0
  88. crosshair/libimpl/hashliblib_test.py +18 -0
  89. crosshair/libimpl/heapqlib.py +47 -0
  90. crosshair/libimpl/heapqlib_test.py +21 -0
  91. crosshair/libimpl/importliblib.py +18 -0
  92. crosshair/libimpl/importliblib_test.py +38 -0
  93. crosshair/libimpl/iolib.py +216 -0
  94. crosshair/libimpl/iolib_ch_test.py +128 -0
  95. crosshair/libimpl/iolib_test.py +19 -0
  96. crosshair/libimpl/ipaddresslib.py +8 -0
  97. crosshair/libimpl/itertoolslib.py +44 -0
  98. crosshair/libimpl/itertoolslib_test.py +44 -0
  99. crosshair/libimpl/jsonlib.py +984 -0
  100. crosshair/libimpl/jsonlib_ch_test.py +42 -0
  101. crosshair/libimpl/jsonlib_test.py +51 -0
  102. crosshair/libimpl/mathlib.py +179 -0
  103. crosshair/libimpl/mathlib_ch_test.py +44 -0
  104. crosshair/libimpl/mathlib_test.py +67 -0
  105. crosshair/libimpl/oslib.py +7 -0
  106. crosshair/libimpl/pathliblib_test.py +10 -0
  107. crosshair/libimpl/randomlib.py +178 -0
  108. crosshair/libimpl/randomlib_test.py +120 -0
  109. crosshair/libimpl/relib.py +846 -0
  110. crosshair/libimpl/relib_ch_test.py +169 -0
  111. crosshair/libimpl/relib_test.py +493 -0
  112. crosshair/libimpl/timelib.py +72 -0
  113. crosshair/libimpl/timelib_test.py +82 -0
  114. crosshair/libimpl/typeslib.py +15 -0
  115. crosshair/libimpl/typeslib_test.py +36 -0
  116. crosshair/libimpl/unicodedatalib.py +75 -0
  117. crosshair/libimpl/unicodedatalib_test.py +42 -0
  118. crosshair/libimpl/urlliblib.py +23 -0
  119. crosshair/libimpl/urlliblib_test.py +19 -0
  120. crosshair/libimpl/weakreflib.py +13 -0
  121. crosshair/libimpl/weakreflib_test.py +69 -0
  122. crosshair/libimpl/zliblib.py +15 -0
  123. crosshair/libimpl/zliblib_test.py +13 -0
  124. crosshair/lsp_server.py +261 -0
  125. crosshair/lsp_server_test.py +30 -0
  126. crosshair/main.py +973 -0
  127. crosshair/main_test.py +543 -0
  128. crosshair/objectproxy.py +376 -0
  129. crosshair/objectproxy_test.py +41 -0
  130. crosshair/opcode_intercept.py +601 -0
  131. crosshair/opcode_intercept_test.py +304 -0
  132. crosshair/options.py +218 -0
  133. crosshair/options_test.py +10 -0
  134. crosshair/patch_equivalence_test.py +75 -0
  135. crosshair/path_cover.py +209 -0
  136. crosshair/path_cover_test.py +138 -0
  137. crosshair/path_search.py +161 -0
  138. crosshair/path_search_test.py +52 -0
  139. crosshair/pathing_oracle.py +271 -0
  140. crosshair/pathing_oracle_test.py +21 -0
  141. crosshair/pure_importer.py +27 -0
  142. crosshair/pure_importer_test.py +16 -0
  143. crosshair/py.typed +0 -0
  144. crosshair/register_contract.py +273 -0
  145. crosshair/register_contract_test.py +190 -0
  146. crosshair/simplestructs.py +1165 -0
  147. crosshair/simplestructs_test.py +283 -0
  148. crosshair/smtlib.py +24 -0
  149. crosshair/smtlib_test.py +14 -0
  150. crosshair/statespace.py +1199 -0
  151. crosshair/statespace_test.py +108 -0
  152. crosshair/stubs_parser.py +352 -0
  153. crosshair/stubs_parser_test.py +43 -0
  154. crosshair/test_util.py +329 -0
  155. crosshair/test_util_test.py +26 -0
  156. crosshair/tools/__init__.py +0 -0
  157. crosshair/tools/check_help_in_doc.py +264 -0
  158. crosshair/tools/check_init_and_setup_coincide.py +119 -0
  159. crosshair/tools/generate_demo_table.py +127 -0
  160. crosshair/tracers.py +544 -0
  161. crosshair/tracers_test.py +154 -0
  162. crosshair/type_repo.py +151 -0
  163. crosshair/unicode_categories.py +589 -0
  164. crosshair/unicode_categories_test.py +27 -0
  165. crosshair/util.py +741 -0
  166. crosshair/util_test.py +173 -0
  167. crosshair/watcher.py +307 -0
  168. crosshair/watcher_test.py +107 -0
  169. crosshair/z3util.py +76 -0
  170. crosshair/z3util_test.py +11 -0
  171. crosshair_tool-0.0.99.dist-info/METADATA +144 -0
  172. crosshair_tool-0.0.99.dist-info/RECORD +176 -0
  173. crosshair_tool-0.0.99.dist-info/WHEEL +6 -0
  174. crosshair_tool-0.0.99.dist-info/entry_points.txt +3 -0
  175. crosshair_tool-0.0.99.dist-info/licenses/LICENSE +93 -0
  176. 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)