crosshair-tool 0.0.97__cp314-cp314-macosx_11_0_arm64.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.

Potentially problematic release.


This version of crosshair-tool might be problematic. Click here for more details.

Files changed (176) hide show
  1. _crosshair_tracers.cpython-314-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 +145 -0
  18. crosshair/copyext_test.py +74 -0
  19. crosshair/core.py +1759 -0
  20. crosshair/core_and_libs.py +149 -0
  21. crosshair/core_regestered_types_test.py +82 -0
  22. crosshair/core_test.py +1313 -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 +5133 -0
  62. crosshair/libimpl/builtinslib_ch_test.py +1191 -0
  63. crosshair/libimpl/builtinslib_test.py +3705 -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 +2546 -0
  72. crosshair/libimpl/datetimelib_ch_test.py +349 -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 +177 -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 +250 -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 +1161 -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 +1196 -0
  151. crosshair/statespace_test.py +99 -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 +525 -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 +736 -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.97.dist-info/METADATA +145 -0
  172. crosshair_tool-0.0.97.dist-info/RECORD +176 -0
  173. crosshair_tool-0.0.97.dist-info/WHEEL +6 -0
  174. crosshair_tool-0.0.97.dist-info/entry_points.txt +3 -0
  175. crosshair_tool-0.0.97.dist-info/licenses/LICENSE +93 -0
  176. crosshair_tool-0.0.97.dist-info/top_level.txt +2 -0
@@ -0,0 +1,3705 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import collections.abc
4
+ import copy
5
+ import dataclasses
6
+ import enum
7
+ import math
8
+ import operator
9
+ import re
10
+ import sys
11
+ from abc import ABC, abstractmethod
12
+ from array import array
13
+ from numbers import Integral
14
+ from typing import (
15
+ Callable,
16
+ Dict,
17
+ FrozenSet,
18
+ Hashable,
19
+ Iterable,
20
+ List,
21
+ Mapping,
22
+ MutableMapping,
23
+ Optional,
24
+ Sequence,
25
+ Set,
26
+ SupportsAbs,
27
+ SupportsBytes,
28
+ SupportsFloat,
29
+ SupportsInt,
30
+ SupportsRound,
31
+ Tuple,
32
+ Type,
33
+ TypeVar,
34
+ Union,
35
+ get_type_hints,
36
+ )
37
+
38
+ import pytest
39
+ import z3 # type: ignore
40
+
41
+ from crosshair import type_repo
42
+ from crosshair.core import (
43
+ analyze_function,
44
+ deep_realize,
45
+ proxy_for_type,
46
+ realize,
47
+ standalone_statespace,
48
+ )
49
+ from crosshair.core_and_libs import run_checkables
50
+ from crosshair.dynamic_typing import origin_of
51
+ from crosshair.libimpl.builtinslib import (
52
+ LazyIntSymbolicStr,
53
+ ModelingDirector,
54
+ PreciseIeeeSymbolicFloat,
55
+ RealBasedSymbolicFloat,
56
+ SymbolicArrayBasedUniformTuple,
57
+ SymbolicBool,
58
+ SymbolicByteArray,
59
+ SymbolicBytes,
60
+ SymbolicInt,
61
+ SymbolicList,
62
+ SymbolicObject,
63
+ SymbolicRange,
64
+ SymbolicType,
65
+ crosshair_types_for_python_type,
66
+ )
67
+ from crosshair.options import AnalysisOptionSet
68
+ from crosshair.statespace import (
69
+ CANNOT_CONFIRM,
70
+ CONFIRMED,
71
+ EXEC_ERR,
72
+ POST_FAIL,
73
+ MessageType,
74
+ StateSpace,
75
+ )
76
+ from crosshair.test_util import (
77
+ check_exec_err,
78
+ check_messages,
79
+ check_states,
80
+ summarize_execution,
81
+ )
82
+ from crosshair.tracers import NoTracing, ResumedTracing
83
+ from crosshair.util import (
84
+ CrossHairInternal,
85
+ CrossHairValue,
86
+ IgnoreAttempt,
87
+ UnknownSatisfiability,
88
+ )
89
+
90
+
91
+ class Cat:
92
+ def size(self) -> int:
93
+ return 1
94
+
95
+
96
+ class BiggerCat(Cat):
97
+ def size(self) -> int:
98
+ return 2
99
+
100
+
101
+ class AbstractBase(ABC):
102
+ @abstractmethod
103
+ def do(self):
104
+ pass
105
+
106
+
107
+ class ConcreteSubclass(AbstractBase):
108
+ def do(self):
109
+ pass
110
+
111
+
112
+ # Type repo doesn't load crosshair classes by default; load manually:
113
+ type_repo._add_class(AbstractBase)
114
+ type_repo._add_class(ConcreteSubclass)
115
+
116
+
117
+ class Color(enum.Enum):
118
+ RED = 0
119
+ BLUE = 1
120
+ GREEN = 2
121
+
122
+
123
+ @dataclasses.dataclass
124
+ class SmokeDetector:
125
+ """inv: not (self._is_plugged_in and self._in_original_packaging)"""
126
+
127
+ _in_original_packaging: bool
128
+ _is_plugged_in: bool
129
+
130
+ def signaling_alarm(self, air_samples: List[str]) -> bool:
131
+ """
132
+ pre: self._is_plugged_in
133
+ post: implies('smoke' in air_samples, _ == True)
134
+ """
135
+ return "smoke" in air_samples
136
+
137
+
138
+ if sys.version_info >= (3, 9):
139
+ from typing import TypedDict
140
+
141
+ class Movie(TypedDict):
142
+ name: str
143
+ year: int
144
+
145
+
146
+ INF = float("inf")
147
+ NAN = float("nan")
148
+
149
+
150
+ def test_crosshair_types_for_python_type() -> None:
151
+ assert crosshair_types_for_python_type(int) == ((SymbolicInt, 1.0),)
152
+ assert crosshair_types_for_python_type(SmokeDetector) == ()
153
+
154
+
155
+ def test_isinstance():
156
+ with standalone_statespace:
157
+ with NoTracing():
158
+ f = RealBasedSymbolicFloat("f")
159
+ assert isinstance(f, float)
160
+ assert not isinstance(f, int)
161
+
162
+
163
+ def test_smtfloat_like_a_float():
164
+ with standalone_statespace:
165
+ with NoTracing():
166
+ f1 = RealBasedSymbolicFloat("f")
167
+ f2 = type(f1)(12)
168
+ with NoTracing():
169
+ assert isinstance(f2, float)
170
+ assert f2 == 12.0
171
+
172
+
173
+ def test_bool_simple_conditional_fail() -> None:
174
+ def f(a: bool, b: bool) -> bool:
175
+ """post: _ == a"""
176
+ return True if a else b
177
+
178
+ check_states(f, POST_FAIL)
179
+
180
+
181
+ def test_bool_simple_conditional_ok() -> None:
182
+ def f(a: bool, b: bool) -> bool:
183
+ """post: _ == a or b"""
184
+ return True if a else b
185
+
186
+ check_states(f, CONFIRMED)
187
+
188
+
189
+ def test_bool_ors_fail() -> None:
190
+ def f(a: bool, b: bool, c: bool, d: bool) -> bool:
191
+ """post: _ == (a ^ b) or (c ^ d)"""
192
+ return a or b or c or d
193
+
194
+ check_states(f, POST_FAIL)
195
+
196
+
197
+ def test_bool_ors() -> None:
198
+ def f(a: bool, b: bool, c: bool, d: bool) -> bool:
199
+ """
200
+ pre: (not a) and (not d)
201
+ post: _ == (a ^ b) or (c ^ d)
202
+ """
203
+ return a or b or c or d
204
+
205
+ check_states(f, CONFIRMED)
206
+
207
+
208
+ def test_bool_as_numbers() -> None:
209
+ def f(a: bool, b: bool) -> int:
210
+ """post: _ in (1, 2)"""
211
+ return (a * b) + True
212
+
213
+ check_states(f, CONFIRMED)
214
+
215
+
216
+ def test_int___floordiv___ok() -> None:
217
+ def f(n: int, d: int) -> Tuple[int, int]:
218
+ """
219
+ pre: n in (5, -5)
220
+ pre: d in (5, 3, -3, -5)
221
+ post: _[0] == _[1]
222
+ """
223
+ return ((n // d), (int(n) // int(d)))
224
+
225
+ check_states(f, CONFIRMED)
226
+
227
+
228
+ def test_number_simple_compare_ok() -> None:
229
+ def f(i: List[int]) -> bool:
230
+ """
231
+ pre: 10 < len(i)
232
+ post: _
233
+ """
234
+ return 9 < len(i[1:])
235
+
236
+ check_states(f, CONFIRMED)
237
+
238
+
239
+ def test_number_promotion_compare_ok() -> None:
240
+ def f(i: int, f: float) -> bool:
241
+ """
242
+ pre: i == 7
243
+ pre: f == 7.0
244
+ post: _
245
+ """
246
+ return i == f and f >= i and i >= f
247
+
248
+ check_states(f, CONFIRMED)
249
+
250
+
251
+ def test_numeric_promotions() -> None:
252
+ def f(b: bool, i: int) -> Tuple[int, float, float]:
253
+ """
254
+ post: _ != (101, 4.14, 13.14)
255
+ """
256
+ return ((b + 100), (b + 3.14), (i + 3.14))
257
+
258
+ check_states(f, POST_FAIL)
259
+
260
+
261
+ def test_float_as_bool() -> None:
262
+ def f(x: float, y: float):
263
+ """
264
+ pre: math.isfinite(x) and math.isfinite(y)
265
+ post: _ == x or _ == y
266
+ """
267
+ return x or y
268
+
269
+ check_states(f, CONFIRMED)
270
+
271
+
272
+ def test_int_reverse_operators() -> None:
273
+ def f(i: int) -> float:
274
+ """
275
+ pre: i != 0
276
+ post: _ != 1
277
+ """
278
+ return (1 + i) + (1 - i) + (1 / i)
279
+
280
+ check_states(f, POST_FAIL)
281
+
282
+
283
+ @pytest.mark.demo
284
+ def test_int___add___method():
285
+ def f(a: int, b: int) -> int:
286
+ """
287
+ Can the sum of two consecutive integers be 37?
288
+
289
+ pre: a + 1 == b
290
+ post: _ != 37
291
+ """
292
+ return a + b
293
+
294
+ check_states(f, POST_FAIL)
295
+
296
+
297
+ @pytest.mark.demo
298
+ def test_int___mod___method():
299
+ def f(a: int) -> int:
300
+ """
301
+ Can the last digit of a given large number be 3?
302
+
303
+ pre: a > 1234
304
+ post: _ != 3
305
+ """
306
+ return a % 10
307
+
308
+ check_states(f, POST_FAIL)
309
+
310
+
311
+ @pytest.mark.demo
312
+ def test_int___mul___method():
313
+ def f(a: int, b: int) -> int:
314
+ """
315
+ Can we multiply two integers and return 42?
316
+
317
+ NOTE: Although this example works, nonlinear integer arithmetic can not
318
+ always be effectively reasoned about.
319
+
320
+ pre: a > b > 1
321
+ post: _ != 42
322
+ """
323
+ return a * b
324
+
325
+ check_states(f, POST_FAIL)
326
+
327
+
328
+ @pytest.mark.demo("yellow")
329
+ def test_int___pow___method():
330
+ def f(a: int) -> int:
331
+ """
332
+ Can the given integer, cubed, equal 343?
333
+
334
+ NOTE: Although this example works, nonlinear integer arithmetic can not
335
+ always be effectively reasoned about. This is particularly true when
336
+ the exponent is symbolic.
337
+
338
+
339
+ post: _ != 343
340
+ """
341
+ return a**3
342
+
343
+ check_states(f, POST_FAIL)
344
+
345
+
346
+ def test_int___pow___to_ieee_float():
347
+ with standalone_statespace as space:
348
+ with NoTracing():
349
+ space.extra(ModelingDirector).global_representations[
350
+ float
351
+ ] = PreciseIeeeSymbolicFloat
352
+ a = SymbolicInt("a")
353
+ with pytest.raises(UnknownSatisfiability):
354
+ sqrt_a = a**0.5
355
+
356
+
357
+ def test_int___pow___to_real_based_float():
358
+ with standalone_statespace as space:
359
+ with NoTracing():
360
+ space.extra(ModelingDirector).global_representations[
361
+ float
362
+ ] = RealBasedSymbolicFloat
363
+ a = SymbolicInt("a")
364
+ sqrt_a = a**0.5
365
+ with pytest.raises(UnknownSatisfiability):
366
+ realize(sqrt_a == 3)
367
+
368
+
369
+ @pytest.mark.demo
370
+ def test_int___sub___method():
371
+ def f(a: int) -> int:
372
+ """
373
+ Can we subtract from 42 and get something larger?
374
+
375
+ post: _ <= 42
376
+ """
377
+ return 42 - a
378
+
379
+ check_states(f, POST_FAIL)
380
+
381
+
382
+ def test_int___rsub__() -> None:
383
+ def f(i: int) -> float:
384
+ """
385
+ post: _ != 42
386
+ """
387
+ return 1 - i
388
+
389
+ check_states(f, POST_FAIL)
390
+
391
+
392
+ @pytest.mark.demo
393
+ def test_int___floordiv___method() -> None:
394
+ def f(a: int, b: int) -> int:
395
+ """
396
+ Can the average of two integers equal either one?
397
+
398
+ pre: a < b
399
+ post: a < _ < b
400
+ """
401
+ return (a + b) // 2
402
+
403
+ check_states(f, POST_FAIL)
404
+
405
+
406
+ def test_int___floordiv___bounds() -> None:
407
+ def f(a: int, b: int) -> int:
408
+ """
409
+ pre: a < b
410
+ post: a <= _ < b
411
+ """
412
+ return (a + b) // 2
413
+
414
+ check_states(f, CONFIRMED)
415
+
416
+
417
+ def test_int_bitwise_fail() -> None:
418
+ def f(a: int, b: int) -> int:
419
+ """
420
+ pre: 0 <= a <= 3
421
+ pre: 0 <= b <= 3
422
+ post: _ < 7
423
+ """
424
+ return (a << 1) ^ b
425
+
426
+ check_states(f, POST_FAIL)
427
+
428
+
429
+ def test_int_bitwise_ok() -> None:
430
+ def f(a: int, b: int) -> int:
431
+ """
432
+ pre: 0 <= a <= 3
433
+ pre: 0 <= b <= 3
434
+ post: _ <= 7
435
+ """
436
+ return (a << 1) ^ b
437
+
438
+ check_states(f, CONFIRMED)
439
+
440
+
441
+ @pytest.mark.demo
442
+ def test_int___truediv___method() -> None:
443
+ def f(a: int, b: int) -> float:
444
+ """
445
+ Can we find an integer that is half as large as another?
446
+
447
+ pre: b != 0
448
+ post: _ != 0.5
449
+ """
450
+ return a / b
451
+
452
+ check_states(f, POST_FAIL)
453
+
454
+
455
+ def test_trunc_fail() -> None:
456
+ def f(n: float) -> int:
457
+ """
458
+ pre: math.isfinite(n)
459
+ pre: n > 100
460
+ post: _ < n
461
+ """
462
+ return math.trunc(n)
463
+
464
+ check_states(f, POST_FAIL)
465
+
466
+
467
+ @pytest.mark.demo
468
+ def test_range() -> None:
469
+ def f(n: int) -> Sequence[int]:
470
+ """
471
+ Can the length of range() be different than the integer we pass to it?
472
+
473
+ post: len(_) == n
474
+ """
475
+ return range(n)
476
+
477
+ check_states(f, POST_FAIL)
478
+
479
+
480
+ def test_round_fail() -> None:
481
+ def f(n1: int, n2: int) -> Tuple[int, int]:
482
+ """
483
+ pre: n1 < n2
484
+ post: _[0] < _[1] # because we round towards even
485
+ """
486
+ return (round(n1 + 0.5), round(n2 + 0.5))
487
+
488
+ check_states(f, POST_FAIL)
489
+
490
+
491
+ def test_round_unknown() -> None:
492
+ def f(num: float, ndigits: Optional[int]) -> float:
493
+ """
494
+ pre: math.isfinite(num)
495
+ post: isinstance(_, int) == (ndigits is None)
496
+ """
497
+ return round(num, ndigits)
498
+
499
+ check_states(f, CANNOT_CONFIRM)
500
+
501
+
502
+ def test_float_isinstance() -> None:
503
+ def f(x: float) -> float:
504
+ """post: isinstance(_, float)"""
505
+ return x
506
+
507
+ check_states(f, CONFIRMED)
508
+
509
+
510
+ def test_mismatched_types() -> None:
511
+ def f(x: float, y: list) -> float:
512
+ """
513
+ pre: x == 1.0 and y == []
514
+ post: _ == 1
515
+ """
516
+ return x + y # type: ignore
517
+
518
+ (actual, expected) = check_exec_err(f, "TypeError: unsupported operand type")
519
+ assert actual == expected
520
+
521
+
522
+ def test_bool_bitwise_negation() -> None:
523
+ def f(x: bool) -> float:
524
+ """
525
+ pre: x == True
526
+ post: _ == -2
527
+ """
528
+ return ~x
529
+
530
+ check_states(f, CONFIRMED)
531
+
532
+
533
+ def test_float_from_hex() -> None:
534
+ def f(s: str) -> float:
535
+ """
536
+ pre: s == '0x3.a7p10'
537
+ post: _ == 3740.0
538
+ """
539
+ return float.fromhex(s)
540
+
541
+ check_states(f, CONFIRMED)
542
+
543
+
544
+ def test_int_from_byte_iterator(space) -> None:
545
+ byts = proxy_for_type(bytes, "byts")
546
+ with ResumedTracing():
547
+ space.add(len(byts) == 2)
548
+ number = int.from_bytes(iter(byts), byteorder="little")
549
+ assert space.is_possible(number == 5)
550
+
551
+
552
+ def test_int_from_bytes(space) -> None:
553
+ byts = proxy_for_type(bytes, "byts")
554
+ with ResumedTracing():
555
+ space.add(len(byts) == 2)
556
+ number = int.from_bytes(byts, byteorder="little")
557
+ assert space.is_possible(number == 5)
558
+
559
+
560
+ def test_int_nonlinear() -> None:
561
+ def make_bigger(x: int, e: int) -> float:
562
+ """
563
+ pre: e > 1
564
+ post: __return__ != 592704
565
+ """
566
+ # Expenentation is not SMT-solvable. (z3 gives unsat for this)
567
+ # But CrossHair gracefully falls back to realized values, yielding
568
+ # the counterexample of: 84 ** 3
569
+ return x**e
570
+
571
+ check_states(make_bigger, POST_FAIL)
572
+
573
+
574
+ @pytest.mark.demo
575
+ def test_int___str___method() -> None:
576
+ def f(x: int) -> str:
577
+ """
578
+ Can any input make this function return the string "321"?
579
+
580
+ post: _ != "321"
581
+ """
582
+ return str(x)
583
+
584
+ check_states(f, POST_FAIL)
585
+
586
+
587
+ @pytest.mark.demo
588
+ def test_int___repr___method() -> None:
589
+ def f(x: int) -> str:
590
+ """
591
+ Can any input make this function return the string "321"?
592
+
593
+ post: _ != '321'
594
+ """
595
+ return repr(x)
596
+
597
+ check_states(f, POST_FAIL)
598
+
599
+
600
+ @pytest.mark.parametrize("b", (False, 1, -2.0, NAN, INF, -INF))
601
+ @pytest.mark.parametrize("op", (operator.lt, operator.eq, operator.add, operator.mul))
602
+ def test_bool_ops(b, op):
603
+ with standalone_statespace as space:
604
+ with NoTracing():
605
+ a = SymbolicBool("a")
606
+ space.add(a)
607
+ symbolic_ret = summarize_execution(lambda: op(a, b))
608
+ concrete_ret = summarize_execution(lambda: op(realize(a), b), detach_path=False)
609
+ assert symbolic_ret == concrete_ret
610
+
611
+
612
+ @pytest.mark.parametrize("b", (False, 1, -2.0, NAN, INF, -INF))
613
+ @pytest.mark.parametrize(
614
+ "op",
615
+ (operator.lt, operator.eq, operator.add, operator.mul, operator.eq, operator.ne),
616
+ )
617
+ def test_float_ops(b, op):
618
+ with standalone_statespace as space:
619
+ with NoTracing():
620
+ a = space.extra(ModelingDirector).choose(float)("a")
621
+ space.add(a < 0)
622
+ symbolic_ret = summarize_execution(lambda: op(a, b))
623
+ concrete_ret = summarize_execution(lambda: op(realize(a), b), detach_path=False)
624
+ assert symbolic_ret == concrete_ret
625
+
626
+
627
+ def test_int_from_str():
628
+ def f(a: str) -> int:
629
+ """
630
+ post: _ != 7
631
+ raises: ValueError
632
+ """
633
+ return int(a)
634
+
635
+ check_states(f, POST_FAIL)
636
+
637
+
638
+ def test_int_from_str_with_bases(space):
639
+ i = proxy_for_type(int, "i")
640
+ s_11 = proxy_for_type(str, "s_11")
641
+ s_a = proxy_for_type(str, "s_a")
642
+ with ResumedTracing():
643
+ space.add(len(s_11) == 2)
644
+ space.add(s_11 == "11")
645
+ space.add(len(s_a) == 1)
646
+ space.add(s_a == "a")
647
+ assert int(s_11, 4) == 5
648
+ assert int(s_11, 16) == 17
649
+ assert int(s_11, 36) == 37
650
+ assert int(s_11, 0) == 11
651
+ assert int(s_a, 16) == 10
652
+ with pytest.raises(TypeError):
653
+ assert int(s_a, base=2.5)
654
+ with pytest.raises(TypeError):
655
+ int(i, base="foo")
656
+
657
+
658
+ def test_easy_float_from_str():
659
+ def f(a: str) -> float:
660
+ """
661
+ post: _ != 0.0
662
+ raises: ValueError
663
+ """
664
+ return float(a)
665
+
666
+ check_states(
667
+ f,
668
+ MessageType.POST_FAIL,
669
+ AnalysisOptionSet(max_iterations=100),
670
+ )
671
+
672
+
673
+ def test_float_from_three_digit_str():
674
+ with standalone_statespace as space:
675
+ with NoTracing():
676
+ codepoints = [
677
+ proxy_for_type(int, "xat0"),
678
+ proxy_for_type(int, "xat1"),
679
+ proxy_for_type(int, "xat2"),
680
+ ]
681
+ x = LazyIntSymbolicStr(codepoints)
682
+ for point in codepoints:
683
+ space.add(point >= ord("0"))
684
+ space.add(point <= ord("9"))
685
+ asfloat = float(x)
686
+ assert space.is_possible(asfloat <= 999)
687
+ assert not space.is_possible(asfloat > 999)
688
+ assert space.is_possible(asfloat == 0) # (because "000" is a valid float)
689
+ assert not space.is_possible(asfloat == 500.5)
690
+
691
+
692
+ @pytest.mark.demo("yellow")
693
+ def test_float___pow___operator():
694
+ def f(a: float) -> float:
695
+ """
696
+ Can the given float, cubed, equal 0.125?
697
+
698
+ NOTE: Although this example works, nonlinear arithmetic is quite difficult
699
+ to reason about in most cases.
700
+
701
+ post: _ != 0.125
702
+ """
703
+ return a**3
704
+
705
+ check_states(f, POST_FAIL)
706
+
707
+
708
+ def test_int_bitwise_find_negative_input():
709
+ def f(x: int) -> int:
710
+ """
711
+ pre: x < 0
712
+ post: _ != 7
713
+ """
714
+ return x & 255
715
+
716
+ check_states(f, POST_FAIL)
717
+
718
+
719
+ @pytest.mark.parametrize("val", [-256, 2**16] + list(range(-4, 9, 2)))
720
+ def test_int_bit_length(val):
721
+ with standalone_statespace as space:
722
+ x = proxy_for_type(int, "x")
723
+ space.add(x == val)
724
+ assert realize(x.bit_length()) == val.bit_length()
725
+
726
+
727
+ @pytest.mark.parametrize(
728
+ "val", [-256, -(2**15), 2**9, 2**15 - 1] + list(range(-4, 9, 3))
729
+ )
730
+ def test_int_to_bytes(val):
731
+ with standalone_statespace as space:
732
+ x = proxy_for_type(int, "x")
733
+ space.add(x == val)
734
+ assert realize(x.to_bytes(2, "big", signed=True)) == val.to_bytes(
735
+ 2, "big", signed=True
736
+ )
737
+
738
+
739
+ def test_int_format():
740
+ with standalone_statespace as space:
741
+ with NoTracing():
742
+ x = SymbolicInt("x")
743
+ space.add(x == 42)
744
+ assert x.__format__("") == "42"
745
+ # TODO this fails:
746
+ # assert x.__format__("f") == "42.000000"
747
+
748
+
749
+ def test_class_format():
750
+ with standalone_statespace as space:
751
+ with NoTracing():
752
+ t = SymbolicType("t", Type[int])
753
+ space.add(t.var == SymbolicType._coerce_to_smt_sort(int))
754
+ assert "a{}b".format(t) == "a<class 'int'>b"
755
+
756
+
757
+ @pytest.mark.demo
758
+ def test_sorted() -> None:
759
+ def f(lst: List[int]) -> List[int]:
760
+ """
761
+ Can sorting shift the number 4002 to the front?
762
+
763
+ pre: len(lst) >= 3
764
+ pre: lst[0] > 4002
765
+ post: _[0] != 4002
766
+ """
767
+ return list(sorted(lst))
768
+
769
+ check_states(f, POST_FAIL)
770
+
771
+
772
+ def test_str___bool__() -> None:
773
+ def f(a: str) -> str:
774
+ """post: a"""
775
+ return a
776
+
777
+ check_states(f, POST_FAIL)
778
+
779
+
780
+ @pytest.mark.demo
781
+ def test_str___mul___method() -> None:
782
+ def f(a: str) -> str:
783
+ """
784
+ Can this string-trippling-function produce a 6-character string?
785
+
786
+ post: len(_) != 6
787
+ """
788
+ return 3 * a
789
+
790
+ check_states(f, POST_FAIL)
791
+
792
+
793
+ def test_str___mul___ok() -> None:
794
+ def f(a: str) -> str:
795
+ """
796
+ pre: len(a) == 2
797
+ post: len(_) == 10
798
+ """
799
+ return a * 3 + 2 * a
800
+
801
+ check_states(f, CONFIRMED)
802
+
803
+
804
+ def test_str___mul___by_symbolic_fail() -> None:
805
+ def f(i: int) -> str:
806
+ """post: len(_) != 6"""
807
+ return "a\x00b" * i
808
+
809
+ check_states(f, POST_FAIL)
810
+
811
+
812
+ def test_str___mul___full_symbolic_multiply_unknown() -> None:
813
+ def f(s: str, i: int) -> str:
814
+ """
815
+ pre: s and i > 0
816
+ post: _[0] == s[0]
817
+ """
818
+ return s * i
819
+
820
+ check_states(f, CANNOT_CONFIRM)
821
+
822
+
823
+ def test_str___add___prefixing_fail() -> None:
824
+ def f(a: str, indent: bool) -> str:
825
+ """post: len(_) == len(a) + indent"""
826
+ return (" " if indent else "") + a
827
+
828
+ check_states(f, POST_FAIL)
829
+
830
+
831
+ def test_str___add___prefixing_ok() -> None:
832
+ def f(a: str, indent: bool) -> str:
833
+ """post: len(_) == len(a) + (2 if indent else 0)"""
834
+ return (" " if indent else "") + a
835
+
836
+ check_states(f, CONFIRMED)
837
+
838
+
839
+ @pytest.mark.demo
840
+ def test_str___contains___method() -> None:
841
+ def f(a: str) -> str:
842
+ """
843
+ What 3 characters can we append to "purple" so that the result contains "please"?
844
+
845
+ pre: len(a) == 3
846
+ post: "please" not in _
847
+ """
848
+ return "purple" + a
849
+
850
+ check_states(f, POST_FAIL)
851
+
852
+
853
+ def test_str_find_does_not_realize_string_length() -> None:
854
+ def f(a: str) -> str:
855
+ """post: len(_) != 100"""
856
+ a.find("abc")
857
+ return a
858
+
859
+ check_states(f, POST_FAIL)
860
+
861
+
862
+ def test_str_find_with_limits_ok() -> None:
863
+ def f(a: str) -> int:
864
+ """post: _ == -1"""
865
+ return a.find("abc", 1, 3)
866
+
867
+ check_states(f, CONFIRMED)
868
+
869
+
870
+ def test_str_find_with_negative_limits_fail() -> None:
871
+ def f(a: str) -> int:
872
+ """post: _ == -1"""
873
+ return a.find("ab", -2, 3)
874
+
875
+ check_states(f, POST_FAIL)
876
+
877
+
878
+ def test_str_ljust_fail() -> None:
879
+ def f(s: str) -> str:
880
+ """post: len(_) == len(s)"""
881
+ return s.ljust(3, " ")
882
+
883
+ check_states(f, POST_FAIL)
884
+
885
+
886
+ def test_str_rfind_with_limits_ok() -> None:
887
+ def f(a: str) -> int:
888
+ """post: _ == -1"""
889
+ return a.rfind("abc", 1, 3)
890
+
891
+ check_states(f, CONFIRMED)
892
+
893
+
894
+ def test_str_rfind_with_negative_limits_fail() -> None:
895
+ def f(a: str) -> int:
896
+ """post: _ == -1"""
897
+ return a.rfind("ab", -2, 3)
898
+
899
+ check_states(f, POST_FAIL)
900
+
901
+
902
+ def test_str_rindex_fail() -> None:
903
+ def f(a: str) -> int:
904
+ """post: _ != 2"""
905
+ try:
906
+ return a.rindex("abc")
907
+ except ValueError:
908
+ return 0
909
+
910
+ check_states(f, POST_FAIL)
911
+
912
+
913
+ def test_str_rindex_err() -> None:
914
+ def f(a: str) -> int:
915
+ """post: True"""
916
+ return a.rindex("abc", 1, 3)
917
+
918
+ check_states(f, EXEC_ERR)
919
+
920
+
921
+ def test_str_rjust_fail() -> None:
922
+ def f(s: str) -> str:
923
+ """post: len(_) == len(s)"""
924
+ return s.rjust(3, "x")
925
+
926
+ check_states(f, POST_FAIL)
927
+
928
+
929
+ @pytest.mark.demo
930
+ def test_str_replace_method() -> None:
931
+ def f(a: str) -> str:
932
+ """
933
+ Can this function return a changed string?
934
+
935
+ post: _ == a
936
+ """
937
+ return a.replace("abc", "x", 1)
938
+
939
+ check_states(f, POST_FAIL)
940
+
941
+
942
+ def test_str_startswith(space) -> None:
943
+ symbolic_char = proxy_for_type(str, "x")
944
+ symbolic_empty = proxy_for_type(str, "y")
945
+ with ResumedTracing():
946
+ space.add(len(symbolic_char) == 1)
947
+ space.add(len(symbolic_empty) == 0)
948
+ assert symbolic_char.startswith(symbolic_empty)
949
+ assert symbolic_char.startswith(symbolic_char)
950
+ assert symbolic_char.startswith(("foo", symbolic_empty))
951
+ assert not symbolic_char.startswith(("foo", "bar"))
952
+ assert symbolic_char.startswith(("", "bar"))
953
+ assert symbolic_char.startswith("")
954
+ assert symbolic_char.startswith(symbolic_empty, 1)
955
+ assert symbolic_char.startswith(symbolic_empty, 1, 1)
956
+ assert str.startswith(symbolic_char, symbolic_empty)
957
+ assert "foo".startswith(symbolic_empty)
958
+ assert not "".startswith(symbolic_char)
959
+
960
+ # Yes, the empty string is findable off the left side but not the right
961
+ assert "x".startswith("", -10, -9)
962
+ assert symbolic_char.startswith(symbolic_empty, -10, -9)
963
+ assert not "x".startswith("", 9, 10)
964
+ assert not symbolic_char.startswith(symbolic_empty, 9, 10)
965
+
966
+
967
+ @pytest.mark.demo
968
+ def test_str_index_method() -> None:
969
+ def f(a: str) -> int:
970
+ """
971
+ Can we find "abc" at position 2?
972
+
973
+ raises: ValueError
974
+ post: _ != 2
975
+ """
976
+ return a.rindex("abc")
977
+
978
+ check_states(f, POST_FAIL)
979
+
980
+
981
+ def test_str_index_err() -> None:
982
+ def f(s1: str, s2: str) -> int:
983
+ """
984
+ pre: s1 == 'aba'
985
+ pre: 'ab' in s2
986
+ post: True
987
+ """
988
+ return s1.index(s2)
989
+
990
+ # index() raises ValueError when a match isn't found:
991
+ (actual, expected) = check_exec_err(f, "ValueError")
992
+ assert actual == expected
993
+
994
+
995
+ def test_str_negative_index_slicing() -> None:
996
+ def f(s: str) -> Tuple[str, str]:
997
+ """post: sum(map(len, _)) == len(s) - 1"""
998
+ idx = s.find(":")
999
+ return (s[:idx], s[idx + 1 :])
1000
+
1001
+ check_states(f, POST_FAIL) # (fails when idx == -1)
1002
+
1003
+
1004
+ def test_str_starts_and_ends_ok() -> None:
1005
+ def f(s: str) -> str:
1006
+ """
1007
+ pre: s == 'aba'
1008
+ post: s.startswith('ab')
1009
+ post: s.endswith('ba')
1010
+ """
1011
+ return s
1012
+
1013
+ check_states(f, CONFIRMED)
1014
+
1015
+
1016
+ @pytest.mark.demo
1017
+ def test_str_count_method() -> None:
1018
+ def f(s: str) -> int:
1019
+ """
1020
+ Can this function find two "a" characters?
1021
+
1022
+ post: _ != 2
1023
+ """
1024
+ return s.count("a")
1025
+
1026
+ check_states(f, POST_FAIL)
1027
+
1028
+
1029
+ @pytest.mark.demo
1030
+ def test_str_split_method() -> None:
1031
+ def f(s: str) -> list:
1032
+ """
1033
+ Does any string comma-split into "a" and "b"?
1034
+
1035
+ post: _ != ['a', 'b']
1036
+ """
1037
+ return s.split(",")
1038
+
1039
+ check_states(f, POST_FAIL)
1040
+
1041
+
1042
+ def test_str_rsplit_fail() -> None:
1043
+ def f(s: str) -> list:
1044
+ """post: __return__ != ['a', 'b']"""
1045
+ return s.rsplit(":", 1)
1046
+
1047
+ check_states(f, POST_FAIL)
1048
+
1049
+
1050
+ def test_str_partition_ok() -> None:
1051
+ def f(s: str) -> tuple:
1052
+ """
1053
+ pre: len(s) == 3
1054
+ post: len(_) == 3
1055
+ """
1056
+ return s.partition(":")
1057
+
1058
+ check_states(f, CONFIRMED)
1059
+
1060
+
1061
+ @pytest.mark.smoke
1062
+ @pytest.mark.demo
1063
+ def test_str_partition_method() -> None:
1064
+ def f(s: str) -> tuple:
1065
+ """
1066
+ Does any input to this partitioning yield ("a", "bc", "d")?
1067
+
1068
+ post: _ != ("a", "bc", "d")
1069
+ """
1070
+ return s.partition("bc")
1071
+
1072
+ check_states(f, POST_FAIL)
1073
+
1074
+
1075
+ def test_str_rpartition_ok() -> None:
1076
+ def f(s: str) -> tuple:
1077
+ """
1078
+ pre: len(s) == 2
1079
+ post: len(_) == 3
1080
+ """
1081
+ return s.rpartition(":")
1082
+
1083
+ check_states(f, CONFIRMED)
1084
+
1085
+
1086
+ def test_str_rpartition_fail() -> None:
1087
+ def f(s: str) -> tuple:
1088
+ """
1089
+ pre: len(s) == 4
1090
+ post: _ != ("abb", "b", "")
1091
+ """
1092
+ return s.rpartition("b")
1093
+
1094
+ check_states(f, POST_FAIL)
1095
+
1096
+
1097
+ def test_str___ge___fail() -> None:
1098
+ def f(s1: str, s2: str) -> bool:
1099
+ """post: _"""
1100
+ return s1 >= s2
1101
+
1102
+ check_states(f, POST_FAIL)
1103
+
1104
+
1105
+ @pytest.mark.demo
1106
+ def test_str___le___method() -> None:
1107
+ def f(a: str, b: str) -> bool:
1108
+ """
1109
+ Can a be greater than b, even though its first charater is not?
1110
+
1111
+ pre: a[0] <= b[0]
1112
+ post: _
1113
+ """
1114
+ return a <= b
1115
+
1116
+ check_states(f, POST_FAIL)
1117
+
1118
+
1119
+ def test_str_realized_compare() -> None:
1120
+ def f(a: str, b: str) -> bool:
1121
+ """
1122
+ post: implies(_, a == b)
1123
+ """
1124
+ return realize(a) == b
1125
+
1126
+ check_states(f, CANNOT_CONFIRM)
1127
+
1128
+
1129
+ def test_str_int_comparison_fail() -> None:
1130
+ def f(a: int, b: str) -> Tuple[bool, bool]:
1131
+ """post: (not _[0]) or (not _[1])"""
1132
+ return (a != b, b != a)
1133
+
1134
+ check_states(f, POST_FAIL)
1135
+
1136
+
1137
+ def test_str_int_comparison_ok() -> None:
1138
+ def f(a: int, b: str) -> bool:
1139
+ """post: _ == False"""
1140
+ return a == b or b == a
1141
+
1142
+ check_states(f, CONFIRMED)
1143
+
1144
+
1145
+ def test_str_formatting_wrong_key() -> None:
1146
+ def f(o: object) -> str:
1147
+ """post: True"""
1148
+ return "object of type {typ} with repr {zzzzz}".format( # type: ignore
1149
+ typ=type(o), rep=repr(o)
1150
+ )
1151
+
1152
+ check_states(f, EXEC_ERR)
1153
+
1154
+
1155
+ def test_str_format_symbolic_format() -> None:
1156
+ def f(fmt: str) -> str:
1157
+ """
1158
+ pre: '{}' in fmt
1159
+ post: True
1160
+ """
1161
+ return fmt.format(ver=sys.version, platform=sys.platform)
1162
+
1163
+ check_states(f, EXEC_ERR)
1164
+
1165
+
1166
+ def test_str_format_percent_unknown() -> None:
1167
+ def f(fmt: str) -> str:
1168
+ """
1169
+ pre: '%' not in fmt
1170
+ post: True
1171
+ """
1172
+ return fmt % ()
1173
+
1174
+ check_states(f, CANNOT_CONFIRM)
1175
+
1176
+
1177
+ @pytest.mark.demo
1178
+ def test_str_join_method() -> None:
1179
+ def f(items: List[str]) -> str:
1180
+ """
1181
+ Any inputs that produce a 5-character string?
1182
+
1183
+ pre: len(items) == 2
1184
+ post: len(_) != 5
1185
+ """
1186
+ return "and".join(items)
1187
+
1188
+ check_states(f, POST_FAIL)
1189
+
1190
+
1191
+ def test_str_upper_fail() -> None:
1192
+ def f(s: str) -> str:
1193
+ """
1194
+ Does any character uppercase to "F"?
1195
+
1196
+ pre: len(s) == 1
1197
+ pre: s != "F"
1198
+ post: __return__ != "F"
1199
+ """
1200
+ return s.upper()
1201
+
1202
+ # TODO: make this use case more efficient.
1203
+ options = AnalysisOptionSet(per_path_timeout=20.0)
1204
+ check_states(f, POST_FAIL, options)
1205
+
1206
+
1207
+ def test_csv_example() -> None:
1208
+ def f(lines: List[str]) -> List[str]:
1209
+ """
1210
+ pre: all(',' in line for line in lines)
1211
+ post: __return__ == [line.split(',')[0] for line in lines]
1212
+ """
1213
+ return [line[: line.index(",")] for line in lines]
1214
+
1215
+ check_states(f, CANNOT_CONFIRM)
1216
+
1217
+
1218
+ @pytest.mark.demo
1219
+ def test_str_zfill_method() -> None:
1220
+ def f(s: str) -> str:
1221
+ """
1222
+ Can zero-filling a two-character string produce "0ab"?
1223
+
1224
+ pre: len(s) == 2
1225
+ post: _ != "0ab"
1226
+ """
1227
+ return s.zfill(3)
1228
+
1229
+ check_states(f, POST_FAIL)
1230
+
1231
+
1232
+ @pytest.mark.demo("yellow")
1233
+ def test_str_format_method() -> None:
1234
+ def f(s: str) -> str:
1235
+ """
1236
+ Does any substitution produce the string "abcdef"?
1237
+
1238
+ NOTE: CrossHair will not be effective with a symbolic template string;
1239
+ e.g. trying to solve s.format("cd") is much more difficult.
1240
+
1241
+ post: _ != "abcdef"
1242
+ """
1243
+ return "ab{}ef".format(s)
1244
+
1245
+ check_states(f, POST_FAIL)
1246
+
1247
+
1248
+ def test_str_constructor() -> None:
1249
+ with standalone_statespace as space:
1250
+ with NoTracing():
1251
+ x = LazyIntSymbolicStr("x")
1252
+ assert str(x) is x
1253
+
1254
+
1255
+ def test_str_str() -> None:
1256
+ with standalone_statespace:
1257
+ with NoTracing():
1258
+ x = LazyIntSymbolicStr("x")
1259
+ strx = x.__str__()
1260
+ with NoTracing():
1261
+ assert isinstance(strx, str)
1262
+
1263
+
1264
+ def test_str_center():
1265
+ with standalone_statespace as space:
1266
+ with NoTracing():
1267
+ string = LazyIntSymbolicStr("string")
1268
+ fillch = LazyIntSymbolicStr("fillch")
1269
+ sz = SymbolicInt("sz")
1270
+ sz6 = SymbolicInt("sz6")
1271
+ space.add(string.__len__() == 3)
1272
+ space.add(fillch.__len__() == 1)
1273
+ space.add(sz > 5)
1274
+ space.add(sz6 == 6)
1275
+ assert "boo".center(sz6) == " boo "
1276
+ symbolic_centered = "boo".center(sz, fillch)
1277
+ starts_with_nonfill = ord(symbolic_centered[0]) != ord(fillch)
1278
+ assert not space.is_possible(starts_with_nonfill)
1279
+
1280
+
1281
+ def test_str_map_chars() -> None:
1282
+ with standalone_statespace:
1283
+ with NoTracing():
1284
+ string = LazyIntSymbolicStr(list(map(ord, "ab")))
1285
+ codepoints = list(map(ord, string))
1286
+
1287
+
1288
+ @pytest.mark.demo
1289
+ def test_str___add___method() -> None:
1290
+ def f(s: str) -> str:
1291
+ """
1292
+ Can any input make this function return "Hello World"?
1293
+
1294
+ post: _ != "Hello World"
1295
+ """
1296
+ return s + "World"
1297
+
1298
+ check_states(f, POST_FAIL)
1299
+
1300
+
1301
+ def test_str_bool():
1302
+ with standalone_statespace as space, NoTracing():
1303
+ a = LazyIntSymbolicStr("a")
1304
+ with ResumedTracing():
1305
+ space.add(a.__len__() > 0)
1306
+ assert bool(a)
1307
+ # Can we retain our symbolic state after forcing a positive truthiness?:
1308
+ assert space.is_possible(a == "this")
1309
+ assert space.is_possible(a == "that")
1310
+
1311
+
1312
+ def test_str_eq():
1313
+ with standalone_statespace, NoTracing():
1314
+ assert LazyIntSymbolicStr([]) == ""
1315
+
1316
+
1317
+ def test_str_getitem():
1318
+ with standalone_statespace, NoTracing():
1319
+ assert LazyIntSymbolicStr(list(map(ord, "abc")))[0] == "a"
1320
+ assert LazyIntSymbolicStr(list(map(ord, "abc")))[-1] == "c"
1321
+ assert LazyIntSymbolicStr(list(map(ord, "abc")))[-5:2] == "ab"
1322
+
1323
+
1324
+ def test_str_filter():
1325
+ with standalone_statespace, NoTracing():
1326
+ string = LazyIntSymbolicStr(list(map(ord, " ")))
1327
+ with ResumedTracing():
1328
+ ret = list(filter(str.isspace, [string]))
1329
+ assert ret == [string]
1330
+
1331
+
1332
+ def test_str_filter_with_none():
1333
+ with standalone_statespace as space, NoTracing():
1334
+ string = LazyIntSymbolicStr([ord("a")])
1335
+ truthyint = proxy_for_type(int, "truthyint")
1336
+ falseyint = proxy_for_type(int, "falseyint")
1337
+ with ResumedTracing():
1338
+ space.add(truthyint == 10)
1339
+ space.add(falseyint == 0)
1340
+ ret = deep_realize(list(filter(None, [falseyint, 42, 0, truthyint])))
1341
+ assert ret == [42, 10]
1342
+
1343
+
1344
+ def test_str_find() -> None:
1345
+ with standalone_statespace, NoTracing():
1346
+ string = LazyIntSymbolicStr(list(map(ord, "aabc")))
1347
+ assert string.find("ab") == 1
1348
+
1349
+
1350
+ def test_str_find_symbolic() -> None:
1351
+ def f(s: str) -> int:
1352
+ """
1353
+ pre: len(s) == 3
1354
+ post: _ == -1
1355
+ """
1356
+ return "haystack".find(s)
1357
+
1358
+ check_states(f, POST_FAIL)
1359
+
1360
+
1361
+ def test_str_find_notfound() -> None:
1362
+ with standalone_statespace, NoTracing():
1363
+ string = LazyIntSymbolicStr([])
1364
+ assert string.find("abc", 1, 3) == -1
1365
+
1366
+
1367
+ def test_str_format_basic():
1368
+ with standalone_statespace as space:
1369
+ with NoTracing():
1370
+ s = LazyIntSymbolicStr("s")
1371
+ space.add(s.__len__() == 1)
1372
+ assert space.is_possible(s == "z")
1373
+ assert space.is_possible(ord("a{0}c".format(s)[1]) == ord("b"))
1374
+
1375
+
1376
+ def test_str_format_map():
1377
+ with standalone_statespace as space:
1378
+ with NoTracing():
1379
+ s = LazyIntSymbolicStr("s")
1380
+ space.add(s.__len__() == 1)
1381
+ assert space.is_possible(s == "z")
1382
+ assert space.is_possible(ord("a{foo}c".format_map({"foo": s})[1]) == ord("b"))
1383
+
1384
+
1385
+ def test_str_rfind() -> None:
1386
+ with standalone_statespace, NoTracing():
1387
+ string = LazyIntSymbolicStr(list(map(ord, "ababb")))
1388
+ assert string.rfind("ab") == 2
1389
+
1390
+
1391
+ def test_str_rfind_notfound() -> None:
1392
+ with standalone_statespace, NoTracing():
1393
+ string = LazyIntSymbolicStr(list(map(ord, "ababb")))
1394
+ assert string.rfind("ab") == 2
1395
+
1396
+
1397
+ def test_str_split_limits():
1398
+ with standalone_statespace, NoTracing():
1399
+ string = LazyIntSymbolicStr(list(map(ord, "a:b:c")))
1400
+ parts = realize(string.split(":", 1))
1401
+ assert parts == ["a", "b:c"]
1402
+ parts = realize(string.split(":"))
1403
+ assert parts == ["a", "b", "c"]
1404
+
1405
+
1406
+ def test_str_rsplit():
1407
+ with standalone_statespace, NoTracing():
1408
+ string = LazyIntSymbolicStr(list(map(ord, "a:b:c")))
1409
+ parts = realize(string.rsplit(":", 1))
1410
+ assert parts == ["a:b", "c"]
1411
+
1412
+
1413
+ def test_str_contains():
1414
+ with standalone_statespace:
1415
+ with NoTracing():
1416
+ small = LazyIntSymbolicStr([ord("b"), ord("c")])
1417
+ big = LazyIntSymbolicStr([ord("a"), ord("b"), ord("c"), ord("d")])
1418
+ assert small in big
1419
+ assert big not in small
1420
+ assert small in "bc"
1421
+ assert small not in "b"
1422
+ assert "c" in small
1423
+ assert "cd" not in small
1424
+
1425
+
1426
+ def test_str_deep_realize():
1427
+ with standalone_statespace, NoTracing():
1428
+ a = LazyIntSymbolicStr("a")
1429
+ tupl = (a, (a,))
1430
+ realized = deep_realize(tupl)
1431
+ assert list(map(type, realized)) == [str, tuple]
1432
+ assert list(map(type, realized[1])) == [str]
1433
+ assert realized[0] is realized[1][0]
1434
+
1435
+
1436
+ def test_str_strip():
1437
+ with standalone_statespace:
1438
+ with NoTracing():
1439
+ x = LazyIntSymbolicStr(list(map(ord, " A b\n")))
1440
+ assert x.strip() == "A b"
1441
+
1442
+
1443
+ def test_str_lower():
1444
+ chr_Idot = "\u0130" # Capital I with dot above
1445
+ # (it's the only unicde char that lower()s to 2 characters)
1446
+ with standalone_statespace:
1447
+ with NoTracing():
1448
+ x = LazyIntSymbolicStr(list(map(ord, "Ab" + chr_Idot)))
1449
+ assert x.lower() == "abi\u0307"
1450
+
1451
+
1452
+ def test_str_title():
1453
+ chr_lj = "\u01c9" # "lj"
1454
+ chr_Lj = "\u01c8" # "Lj" (different from "LJ", "\u01c7")
1455
+ with standalone_statespace:
1456
+ with NoTracing():
1457
+ lj = LazyIntSymbolicStr(list(map(ord, chr_lj)))
1458
+ lja_b = LazyIntSymbolicStr(list(map(ord, chr_lj + "a_b")))
1459
+ assert lja_b.title() == chr_Lj + "a_B"
1460
+
1461
+
1462
+ def test_object_deep_realize():
1463
+ @dataclasses.dataclass
1464
+ class Container:
1465
+ contents: int
1466
+
1467
+ with standalone_statespace as space, NoTracing():
1468
+ a = SymbolicObject("a", Container)
1469
+ shallow = realize(a)
1470
+ assert type(shallow) is Container
1471
+ assert type(shallow.contents) is not int
1472
+ deep = deep_realize(a)
1473
+ assert type(deep) is Container
1474
+ assert type(deep.contents) is int
1475
+
1476
+
1477
+ def test_seq_string_deep_realize():
1478
+ with standalone_statespace as space, NoTracing():
1479
+ tupl = SymbolicArrayBasedUniformTuple("s", List[str])
1480
+ space.add(tupl._len() == 2)
1481
+ realized = deep_realize(tupl)
1482
+ assert list(map(type, realized)) == [str, str]
1483
+
1484
+
1485
+ @pytest.mark.demo
1486
+ def test_tuple___add___method():
1487
+ def f(a: Tuple[int, ...]):
1488
+ """
1489
+ Can we get this function to return (1, 2, 3, 4)?
1490
+
1491
+ post: _ != (1, 2, 3, 4)
1492
+ """
1493
+ return (1,) + a + (4,)
1494
+
1495
+ check_states(f, POST_FAIL)
1496
+
1497
+
1498
+ @pytest.mark.demo
1499
+ def test_tuple___getitem___method() -> None:
1500
+ def f(t: Tuple[int, ...], idx: int) -> int:
1501
+ """
1502
+ Can we find 42 in the given tuple at the given index?
1503
+
1504
+ pre: idx >= 0 and idx < len(t)
1505
+ post: _ != 42
1506
+ """
1507
+ return t[idx]
1508
+
1509
+ check_states(f, POST_FAIL)
1510
+
1511
+
1512
+ @pytest.mark.demo
1513
+ def test_tuple___len___method():
1514
+ def f(a: Tuple[int, ...]):
1515
+ """
1516
+ Can we find a tuple of length 8?
1517
+
1518
+ post: _ != 8
1519
+ """
1520
+ return len(a)
1521
+
1522
+ check_states(f, POST_FAIL)
1523
+
1524
+
1525
+ def test_tuple___repr__symbolic_in_concrete(space) -> None:
1526
+ x = proxy_for_type(int, "x")
1527
+ with ResumedTracing():
1528
+ space.add(x == 4) # type: ignore
1529
+ container = (x, x)
1530
+ assert repr(container) == "(4, 4)"
1531
+
1532
+
1533
+ def test_tuple___repr__symbolic_in_concrete_namedtuple(space) -> None:
1534
+ NamedTupleClass = collections.namedtuple("NamedTupleClass", ["target"])
1535
+ x = proxy_for_type(int, "x")
1536
+ with ResumedTracing():
1537
+ space.add(x == 4) # type: ignore
1538
+ container = NamedTupleClass(target=x)
1539
+ assert repr(container) == "NamedTupleClass(target=4)"
1540
+
1541
+
1542
+ def test_tuple_range_intersection_fail() -> None:
1543
+ def f(a: Tuple[int, int], b: Tuple[int, int]) -> Optional[Tuple[int, int]]:
1544
+ """
1545
+ pre: a[0] < a[1] and b[0] < b[1]
1546
+ post: _[0] <= _[1]
1547
+ """
1548
+ return (max(a[0], b[0]), min(a[1], b[1]))
1549
+
1550
+ check_states(f, POST_FAIL)
1551
+
1552
+
1553
+ def test_tuple_range_intersection_ok() -> None:
1554
+ def f(a: Tuple[int, int], b: Tuple[int, int]) -> Optional[Tuple[int, int]]:
1555
+ """
1556
+ pre: a[0] < a[1] and b[0] < b[1]
1557
+ post: _ is None or _[0] <= _[1]
1558
+ """
1559
+ if a[1] > b[0] and a[0] < b[1]: # (if the ranges overlap)
1560
+ return (max(a[0], b[0]), min(a[1], b[1]))
1561
+ else:
1562
+ return None
1563
+
1564
+ check_states(f, CONFIRMED)
1565
+
1566
+
1567
+ def test_tuple_with_uniform_values_fail() -> None:
1568
+ def f(a: Tuple[int, ...]) -> float:
1569
+ """
1570
+ post: True
1571
+ """
1572
+ return sum(a) / len(a)
1573
+
1574
+ check_states(f, EXEC_ERR)
1575
+
1576
+
1577
+ def test_tuple_with_uniform_values_ok() -> None:
1578
+ def f(a: Tuple[int, ...]) -> Tuple[int, ...]:
1579
+ """
1580
+ pre: len(a) < 4
1581
+ post: 0 not in _
1582
+ """
1583
+ return tuple(x for x in a if x)
1584
+
1585
+ check_states(f, CONFIRMED)
1586
+
1587
+
1588
+ def test_tuple_runtime_type() -> None:
1589
+ def f(t: Tuple) -> Tuple:
1590
+ """post: t != (1, 2)"""
1591
+ return t
1592
+
1593
+ check_states(f, POST_FAIL)
1594
+
1595
+
1596
+ def test_empty_tuple(space) -> None:
1597
+ t = proxy_for_type(Tuple[()], "t")
1598
+ with ResumedTracing():
1599
+ assert type(t) is tuple
1600
+ assert t == ()
1601
+
1602
+
1603
+ def test_tuple_isinstance_check() -> None:
1604
+ def f(uniform_tuple: Tuple[List, ...], basic_tuple: tuple) -> Tuple[bool, bool]:
1605
+ """post: _ == (True, True)"""
1606
+ return (isinstance(uniform_tuple, tuple), isinstance(basic_tuple, tuple))
1607
+
1608
+ check_states(f, CONFIRMED)
1609
+
1610
+
1611
+ def test_range___len___method() -> None:
1612
+ def f(a: int) -> Iterable[int]:
1613
+ """
1614
+ post: len(_) == a or a < 0
1615
+ """
1616
+ return range(a)
1617
+
1618
+ check_states(f, CONFIRMED)
1619
+
1620
+
1621
+ @pytest.mark.demo
1622
+ def test_range___reversed___method() -> None:
1623
+ def f(start: int, stop: int, step: int) -> List[int]:
1624
+ """
1625
+ Does some reversed range equal [12, 8]?
1626
+
1627
+ pre: step != 0
1628
+ post: _ != [12, 8]
1629
+ """
1630
+ return list(reversed(range(start, stop, step)))
1631
+
1632
+ check_states(f, POST_FAIL)
1633
+
1634
+
1635
+ def test_range_slicing(space) -> None:
1636
+ assert list(range(3, 40, 2)[5::-1]) == [13, 11, 9, 7, 5, 3]
1637
+ # Repeat this with a symbolic range:
1638
+ rng = proxy_for_type(range, "rng")
1639
+ newstart = proxy_for_type(int, "newstart")
1640
+ with ResumedTracing():
1641
+ space.add(rng.start == 3) # type: ignore
1642
+ space.add(rng.stop == 40) # type: ignore
1643
+ space.add(rng.step == 2) # type: ignore
1644
+ space.add(newstart == 5) # type: ignore
1645
+ assert list(rng[newstart::-1]) == [13, 11, 9, 7, 5, 3]
1646
+
1647
+
1648
+ def test_range_realization(space) -> None:
1649
+ rng = proxy_for_type(range, "rng")
1650
+ assert isinstance(rng, SymbolicRange)
1651
+ with ResumedTracing():
1652
+ assert isinstance(rng, range)
1653
+ realized_range = realize(rng)
1654
+ assert isinstance(realized_range, range)
1655
+ with ResumedTracing():
1656
+ assert realized_range == rng
1657
+ assert hash(realized_range) == hash(rng)
1658
+
1659
+
1660
+ @pytest.mark.demo
1661
+ def test_list___contains___method() -> None:
1662
+ def f(a: int, b: List[int]) -> bool:
1663
+ """
1664
+ Is full containment checking equivalent to checking the first 3 elements?
1665
+
1666
+ post: _ == (a in b[:3])
1667
+ """
1668
+ return a in b
1669
+
1670
+ check_states(f, POST_FAIL)
1671
+
1672
+
1673
+ def test_list___contains___ok() -> None:
1674
+ def f(a: int, b: List[int]) -> bool:
1675
+ """
1676
+ pre: 1 == len(b)
1677
+ post: _ == (a == b[0])
1678
+ """
1679
+ return a in b
1680
+
1681
+ check_states(f, CONFIRMED)
1682
+
1683
+
1684
+ @pytest.mark.demo
1685
+ def test_list___add___method() -> None:
1686
+ def f(a: List[int]) -> List[int]:
1687
+ """
1688
+ Does doubling the list always make it longer?
1689
+
1690
+ post: len(_) > len(a)
1691
+ """
1692
+ return a + a
1693
+
1694
+ check_states(f, POST_FAIL)
1695
+
1696
+
1697
+ def test_list___repr___symbolic_in_concrete(space) -> None:
1698
+ x = proxy_for_type(int, "x")
1699
+ with ResumedTracing():
1700
+ space.add(x == 4) # type: ignore
1701
+ continer = [x]
1702
+ assert f"{continer=}" == "continer=[4]"
1703
+
1704
+
1705
+ def test_list_doubling_ok() -> None:
1706
+ def f(a: List[int]) -> List[int]:
1707
+ """
1708
+ post: len(_) > len(a) or not a
1709
+ """
1710
+ return a + a
1711
+
1712
+ check_states(f, CONFIRMED)
1713
+
1714
+
1715
+ def test_list_multiply_ok() -> None:
1716
+ def f(a: List[int]) -> List[int]:
1717
+ """post: len(_) == len(a) * 5"""
1718
+ return a * 3 + 2 * a
1719
+
1720
+ check_states(f, CONFIRMED)
1721
+
1722
+
1723
+ def test_list_average() -> None:
1724
+ def average(numbers: List[float]) -> float:
1725
+ """
1726
+ pre: len(numbers) > 0
1727
+ post: min(numbers) <= _ <= max(numbers)
1728
+ """
1729
+ return sum(numbers) / len(numbers)
1730
+
1731
+ check_states(average, CANNOT_CONFIRM)
1732
+
1733
+
1734
+ def test_list_mixed_symbolic_and_literal_concat_ok() -> None:
1735
+ def f(ls: List[int], i: int) -> List[int]:
1736
+ """
1737
+ pre: i >= 0
1738
+ post: len(_) == len(ls) + 1
1739
+ """
1740
+ return (
1741
+ ls[:i]
1742
+ + [
1743
+ 42,
1744
+ ]
1745
+ + ls[i:]
1746
+ )
1747
+
1748
+ check_states(f, CONFIRMED)
1749
+
1750
+
1751
+ def test_list_range_fail() -> None:
1752
+ def f(ls: List[int]) -> List[int]:
1753
+ """
1754
+ pre: len(ls) == 3
1755
+ post: len(_) > len(ls)
1756
+ """
1757
+ n: List[int] = []
1758
+ for i in range(len(ls)):
1759
+ n.append(ls[i] + 1)
1760
+ return n
1761
+
1762
+ check_states(f, POST_FAIL)
1763
+
1764
+
1765
+ def test_list_range_ok() -> None:
1766
+ def f(ls: List[int]) -> List[int]:
1767
+ """
1768
+ pre: ls and len(ls) < 10 # (max is to cap runtime)
1769
+ post: _[0] == ls[0] + 1
1770
+ """
1771
+ n: List[int] = []
1772
+ for i in range(len(ls)):
1773
+ n.append(ls[i] + 1)
1774
+ return n
1775
+
1776
+ check_states(f, CONFIRMED)
1777
+
1778
+
1779
+ def test_list_equality() -> None:
1780
+ def f(ls: List[int]) -> List[int]:
1781
+ """
1782
+ pre: len(ls) > 0
1783
+ post: _ != ls
1784
+ """
1785
+ # extra check for positive equality:
1786
+ assert ls == [x for x in ls], "list does not equal itself"
1787
+ nl = ls[:]
1788
+ nl[0] = 42
1789
+ return nl
1790
+
1791
+ check_states(f, POST_FAIL)
1792
+
1793
+
1794
+ def test_list_extend_literal_unknown() -> None:
1795
+ def f(ls: List[int]) -> List[int]:
1796
+ """
1797
+ post: _[:2] == [1, 2]
1798
+ """
1799
+ r = [1, 2, 3]
1800
+ r.extend(ls)
1801
+ return r
1802
+
1803
+ check_states(f, CANNOT_CONFIRM)
1804
+
1805
+
1806
+ @pytest.mark.demo
1807
+ def test_list___getitem___method() -> None:
1808
+ def f(ls: List[int], idx: int) -> int:
1809
+ """
1810
+ Can we find 42 in the given list at the given index?
1811
+
1812
+ pre: idx >= 0 and idx < len(ls)
1813
+ post: _ != 42
1814
+ """
1815
+ return ls[idx]
1816
+
1817
+ check_states(f, POST_FAIL)
1818
+
1819
+
1820
+ def test_list____getitem___error() -> None:
1821
+ def f(ls: List[int], idx: int) -> int:
1822
+ """
1823
+ pre: idx >= 0 and len(ls) > 2
1824
+ post: True
1825
+ """
1826
+ return ls[idx]
1827
+
1828
+ (actual, expected) = check_exec_err(f, "IndexError")
1829
+ assert actual == expected
1830
+
1831
+
1832
+ def test_list____getitem___type_error() -> None:
1833
+ def f(ls: List[int]) -> int:
1834
+ """post: True"""
1835
+ return ls[0.0:] # type: ignore
1836
+
1837
+ (actual, expected) = check_exec_err(f, "TypeError")
1838
+ assert actual == expected
1839
+
1840
+
1841
+ def test_list____getitem___ok() -> None:
1842
+ def f(ls: List[int]) -> bool:
1843
+ """
1844
+ pre: len(ls) <= 3
1845
+ post: _ == (7 in ls)
1846
+ """
1847
+ try:
1848
+ return ls[ls.index(7)] == 7
1849
+ return True
1850
+ except ValueError:
1851
+ return False
1852
+
1853
+ check_states(f, CONFIRMED)
1854
+
1855
+
1856
+ def test_list_nested_lists_fail() -> None:
1857
+ def f(ls: List[List[int]]) -> int:
1858
+ """
1859
+ post: _ > 0
1860
+ """
1861
+ total = 0
1862
+ for i in ls:
1863
+ total += len(i)
1864
+ return total
1865
+
1866
+ check_states(f, POST_FAIL)
1867
+
1868
+
1869
+ def test_list_nested_lists_ok() -> None:
1870
+ def f(ls: List[List[int]]) -> int:
1871
+ """
1872
+ pre: len(ls) < 4
1873
+ post: _ >= 0
1874
+ """
1875
+ total = 0
1876
+ for i in ls:
1877
+ total += len(i)
1878
+ return total
1879
+
1880
+ check_states(f, CONFIRMED)
1881
+
1882
+
1883
+ def test_list_iterable() -> None:
1884
+ def f(a: Iterable[int]) -> int:
1885
+ """
1886
+ pre: a
1887
+ post: _ in a
1888
+ """
1889
+ return next(iter(a))
1890
+
1891
+ check_states(f, CONFIRMED)
1892
+
1893
+
1894
+ def test_list_isinstance_check() -> None:
1895
+ def f(ls: List) -> bool:
1896
+ """post: _"""
1897
+ return isinstance(ls, list)
1898
+
1899
+ check_states(f, CONFIRMED)
1900
+
1901
+
1902
+ def test_list_slice_outside_range_ok() -> None:
1903
+ def f(ls: List[int], i: int) -> List[int]:
1904
+ """
1905
+ pre: i >= len(ls)
1906
+ post: _ == ls
1907
+ """
1908
+ return ls[:i]
1909
+
1910
+ check_states(f, CONFIRMED)
1911
+
1912
+
1913
+ def test_list_slice_amount() -> None:
1914
+ def f(ls: List[int]) -> List[int]:
1915
+ """
1916
+ pre: len(ls) >= 3
1917
+ post: len(_) == 1
1918
+ """
1919
+ return ls[2:3]
1920
+
1921
+ check_states(f, CONFIRMED)
1922
+
1923
+
1924
+ def test_list____setitem___ok() -> None:
1925
+ def f(ls: List[int]) -> None:
1926
+ """
1927
+ pre: len(ls) >= 2
1928
+ post[ls]:
1929
+ ls[1] == 42
1930
+ ls[2] == 43
1931
+ len(ls) == 4
1932
+ """
1933
+ ls[1:-1] = [42, 43]
1934
+
1935
+ check_states(f, CONFIRMED)
1936
+
1937
+
1938
+ def test_list___setitem___out_of_bounds() -> None:
1939
+ def f(ls: List[int], i: int) -> None:
1940
+ """
1941
+ pre: i != -1
1942
+ post: ls == __old__.ls[:i] + __old__.ls[i+1:]
1943
+ """
1944
+ ls[i : i + 1] = []
1945
+
1946
+ check_states(f, CANNOT_CONFIRM)
1947
+
1948
+
1949
+ def test_list_insert_ok() -> None:
1950
+ def f(ls: List[int]) -> None:
1951
+ """
1952
+ pre: len(ls) == 4
1953
+ post[ls]:
1954
+ len(ls) == 5
1955
+ ls[2] == 42
1956
+ """
1957
+ ls.insert(-2, 42)
1958
+
1959
+ check_states(f, CONFIRMED)
1960
+
1961
+
1962
+ def test_list_insert_with_conversions() -> None:
1963
+ def f(ls: List[Set[int]], a: bool, b: int) -> None:
1964
+ """
1965
+ # self.insert(a,b) with {'a': True, 'b': 10, 'self': [{0}]}
1966
+ post: True
1967
+ """
1968
+ ls.insert(a, b) # type: ignore
1969
+
1970
+ check_states(f, CONFIRMED)
1971
+
1972
+
1973
+ def test_list_pop_ok() -> None:
1974
+ def f(ls: List[int]) -> None:
1975
+ """
1976
+ pre: ls == [4, 5]
1977
+ post: ls == [4]
1978
+ """
1979
+ ls.pop()
1980
+
1981
+ check_states(f, CONFIRMED)
1982
+
1983
+
1984
+ def test_list_count_ok() -> None:
1985
+ def f(ls: List[Dict[int, Dict[int, int]]]) -> int:
1986
+ """
1987
+ pre: ls == [{1: {2: 3}}]
1988
+ post: _ == 1
1989
+ """
1990
+ return ls.count({1: {2: 3}})
1991
+
1992
+ check_states(f, CONFIRMED)
1993
+
1994
+
1995
+ @pytest.mark.smoke
1996
+ def test_list___setitem___ok() -> None:
1997
+ def f(ls: List[int]) -> None:
1998
+ """
1999
+ pre: len(ls) >= 4
2000
+ post[ls]: ls[3] == 42
2001
+ """
2002
+ ls[3] = 42
2003
+
2004
+ check_states(f, CONFIRMED)
2005
+
2006
+
2007
+ @pytest.mark.demo
2008
+ def test_list___delitem___method() -> None:
2009
+ def f(ls: List[int]) -> None:
2010
+ """
2011
+ Can we trim the tail two elements and have three left over?
2012
+
2013
+ post[ls]: len(ls) != 3
2014
+ """
2015
+ del ls[-2:]
2016
+
2017
+ check_states(f, POST_FAIL)
2018
+
2019
+
2020
+ def test_list___delitem___ok() -> None:
2021
+ def f(ls: List[int]) -> None:
2022
+ """
2023
+ pre: len(ls) == 5
2024
+ post[ls]: len(ls) == 4
2025
+ """
2026
+ del ls[2]
2027
+
2028
+ check_states(f, CONFIRMED)
2029
+
2030
+
2031
+ def test_list___delitem___type_error() -> None:
2032
+ def f(ls: List[float]) -> None:
2033
+ """
2034
+ pre: len(ls) == 0
2035
+ post: True
2036
+ """
2037
+ del ls[1.0] # type: ignore
2038
+
2039
+ (actual, expected) = check_exec_err(f, "TypeError")
2040
+ assert actual == expected
2041
+
2042
+
2043
+ def test_list___delitem___out_of_bounds() -> None:
2044
+ def f(ls: List[float]) -> None:
2045
+ """post: True"""
2046
+ del ls[1]
2047
+
2048
+ (actual, expected) = check_exec_err(f, "IndexError")
2049
+ assert actual == expected
2050
+
2051
+
2052
+ def test_list_sort_ok() -> None:
2053
+ def f(ls: List[int]) -> None:
2054
+ """
2055
+ pre: len(ls) == 3
2056
+ post[ls]: ls[0] == min(ls)
2057
+ """
2058
+ ls.sort()
2059
+
2060
+ check_states(f, CONFIRMED)
2061
+
2062
+
2063
+ def test_list_reverse_ok() -> None:
2064
+ def f(ls: List[int]) -> None:
2065
+ """
2066
+ pre: len(ls) == 2
2067
+ post[ls]: ls[0] == 42
2068
+ """
2069
+ ls.append(42)
2070
+ ls.reverse()
2071
+
2072
+ check_states(f, CONFIRMED)
2073
+
2074
+
2075
+ def test_list_comparison_type_error() -> None:
2076
+ def f(a: List[Set], b: str):
2077
+ """post: True"""
2078
+ return a <= b # type: ignore
2079
+
2080
+ (actual, expected) = check_exec_err(f, "TypeError")
2081
+ assert actual == expected
2082
+
2083
+
2084
+ def test_list_shallow_realization():
2085
+ with standalone_statespace as space:
2086
+ nums = proxy_for_type(List[int], "nums")
2087
+ numslen = len(nums)
2088
+ space.add(numslen == 1)
2089
+ with NoTracing():
2090
+ realized = realize(nums)
2091
+ assert type(realized) is list
2092
+ assert len(realized) == 1
2093
+ assert type(realized[0]) is SymbolicInt
2094
+
2095
+
2096
+ def test_list_concrete_with_symbolic_slice(space):
2097
+ idx = proxy_for_type(int, "i")
2098
+ with ResumedTracing():
2099
+ space.add(1 <= idx)
2100
+ space.add(idx <= 3)
2101
+ prefix = [0, 1, 2, 3][:idx]
2102
+ prefixlen = len(prefix)
2103
+ assert isinstance(prefix, CrossHairValue)
2104
+ assert isinstance(prefixlen, CrossHairValue)
2105
+ with ResumedTracing():
2106
+ assert space.is_possible(prefixlen == 1)
2107
+ assert space.is_possible(prefixlen == 3)
2108
+
2109
+
2110
+ def test_list_copy(space):
2111
+ lst = proxy_for_type(List[int], "lst")
2112
+ with ResumedTracing():
2113
+ # Mostly just ensure the various ways of copying don't explode
2114
+ assert lst[:] is not lst
2115
+ assert lst.copy() is not lst
2116
+ assert copy.deepcopy(lst) is not lst
2117
+ assert copy.copy(lst) is not lst
2118
+
2119
+
2120
+ def test_list_copy_compare_without_forking(space):
2121
+ lst = proxy_for_type(List[int], "lst")
2122
+ with ResumedTracing():
2123
+ lst2 = copy.deepcopy(lst)
2124
+ assert lst.inner is not lst2.inner
2125
+ assert type(lst2) is SymbolicList
2126
+ assert lst.inner.var is lst2.inner.var
2127
+ with ResumedTracing():
2128
+ are_same = lst == lst2
2129
+ assert type(are_same) is SymbolicBool
2130
+ assert not space.is_possible(z3.Not(are_same.var))
2131
+
2132
+
2133
+ def test_dict___bool___ok() -> None:
2134
+ def f(a: Dict[int, str]) -> bool:
2135
+ """
2136
+ post[a]: _ == True
2137
+ """
2138
+ a[0] = "zero"
2139
+ return bool(a)
2140
+
2141
+ check_states(f, CONFIRMED)
2142
+
2143
+
2144
+ def test_dict___iter___fail() -> None:
2145
+ def f(a: Dict[int, str]) -> List[int]:
2146
+ """
2147
+ post[a]: 5 in _
2148
+ """
2149
+ a[10] = "ten"
2150
+ return list(a.__iter__())
2151
+
2152
+ check_states(f, POST_FAIL)
2153
+
2154
+
2155
+ def test_dict___iter___ok() -> None:
2156
+ def f(a: Dict[int, str]) -> List[int]:
2157
+ """
2158
+ pre: len(a) < 3
2159
+ post[a]: 10 in _
2160
+ """
2161
+ a[10] = "ten"
2162
+ return list(a.__iter__())
2163
+
2164
+ check_states(f, CONFIRMED)
2165
+
2166
+
2167
+ def test_dict___or___method():
2168
+ with standalone_statespace as space:
2169
+ d = proxy_for_type(Dict[int, int], "d")
2170
+ space.add(len(d) == 0)
2171
+ with pytest.raises(TypeError):
2172
+ d | set()
2173
+ if sys.version_info >= (3, 9):
2174
+ assert d | {1: 2} == {1: 2}
2175
+ else:
2176
+ with pytest.raises(TypeError):
2177
+ d | {1: 2}
2178
+
2179
+
2180
+ @pytest.mark.demo("yellow")
2181
+ def test_dict___delitem___method() -> None:
2182
+ def f(a: Dict[str, int]) -> None:
2183
+ """
2184
+ Can deleting the key "foo" leave an empty dictionary?
2185
+
2186
+ NOTE: Deleting a symbolic key from a concrete dictionary is not effectively
2187
+ reasoned about at present:
2188
+
2189
+ dictionary | key | effective?
2190
+ -----------+----------+-----------
2191
+ symbolic | * | yes
2192
+ * | concrete | yes
2193
+ concrete | symbolic | no
2194
+
2195
+
2196
+ raises: KeyError
2197
+ post[a]: len(a) != 0
2198
+ """
2199
+ del a["foo"]
2200
+
2201
+ check_states(f, POST_FAIL)
2202
+
2203
+
2204
+ @pytest.mark.demo
2205
+ def test_dict___eq___method() -> None:
2206
+ def f(t: dict) -> dict:
2207
+ """
2208
+ Can we find a dictionary that maps 50 to 100?
2209
+
2210
+ post: t != {50: 100}
2211
+ """
2212
+ return t
2213
+
2214
+ check_states(f, POST_FAIL)
2215
+
2216
+
2217
+ def test_dict___eq___deep() -> None:
2218
+ def f(a: Dict[bool, set], b: List[Set[float]]) -> object:
2219
+ """
2220
+ pre: a == {True: set()}
2221
+ pre: b == [set(), {1.0}]
2222
+ post: _
2223
+ """
2224
+ if a == {True: set()}:
2225
+ if b == [set(), {1.0}]:
2226
+ return False
2227
+ return True
2228
+
2229
+ check_states(f, POST_FAIL)
2230
+
2231
+
2232
+ def test_dict___eq___ok() -> None:
2233
+ def f(d: Dict[int, int]) -> Dict[int, int]:
2234
+ """post: _ == {**_}"""
2235
+ return d
2236
+
2237
+ check_states(f, CANNOT_CONFIRM)
2238
+
2239
+
2240
+ @pytest.mark.demo
2241
+ def test_dict___getitem___method() -> None:
2242
+ def f(m: Dict[int, int]):
2243
+ """
2244
+ Can we make a path from 0 to 2, by indexing into the dictionary twice?
2245
+
2246
+ pre: len(m) == 2
2247
+ raises: KeyError
2248
+ post: _ != 2
2249
+ """
2250
+ return m[m[0]]
2251
+
2252
+ check_states(f, POST_FAIL)
2253
+
2254
+
2255
+ def test_dict___getitem___implicit_conversion_for_keys_fail() -> None:
2256
+ def f(m: Dict[complex, float], b: bool, i: int):
2257
+ """
2258
+ pre: not m
2259
+ post: len(m) != 1
2260
+ """
2261
+ m[b] = 2.0
2262
+ m[i] = 3.0
2263
+
2264
+ check_states(f, POST_FAIL)
2265
+
2266
+
2267
+ def test_dict__items__works_with_symbolic_self(space) -> None:
2268
+ x = proxy_for_type(Dict[int, int], "x")
2269
+ with ResumedTracing():
2270
+ x[42] = 42
2271
+ assert (42, 42) in list(dict.items(x))
2272
+
2273
+
2274
+ def test_dict___repr___symbolic_in_concrete(space) -> None:
2275
+ x = proxy_for_type(int, "x")
2276
+ with ResumedTracing():
2277
+ space.add(x == 4) # type: ignore
2278
+ container = {x: x}
2279
+ assert repr(container) == "{4: 4}"
2280
+
2281
+
2282
+ @pytest.mark.demo("yellow")
2283
+ def test_dict___setitem___method() -> None:
2284
+ def f(a: Dict[int, int], k: int, v: int) -> None:
2285
+ """
2286
+ Can we make a dictionary assignment, and be left with {4: 5, 10: 20}?
2287
+
2288
+ NOTE: CrossHair cannot effectively handle the assignment of a symbolic key on a
2289
+ concrete dictionary, e.g. `d={4:5}; d[k] = 20`
2290
+
2291
+ dictionary | key | value | effective?
2292
+ -----------+----------+-------+-----------
2293
+ symbolic | * | * | yes
2294
+ * | concrete | * | yes
2295
+ concrete | symbolic | * | no
2296
+
2297
+
2298
+ post[a]: a != {4: 5, 10: 20}
2299
+ """
2300
+ a[k] = v
2301
+
2302
+ check_states(f, POST_FAIL)
2303
+
2304
+
2305
+ def test_dict___setitem___ok() -> None:
2306
+ def f(a: Dict[int, int], k: int, v: int) -> None:
2307
+ """
2308
+ post[a]: a[k] == v
2309
+ """
2310
+ a[k] = v
2311
+
2312
+ check_states(f, CONFIRMED)
2313
+
2314
+
2315
+ def test_dict___setitem___on_copy() -> None:
2316
+ def f(d: Dict[int, int]) -> Dict[int, int]:
2317
+ """post: _ != d"""
2318
+ d = d.copy()
2319
+ d[42] = 100
2320
+ return d
2321
+
2322
+ check_states(f, POST_FAIL)
2323
+
2324
+
2325
+ def TODO_test_dict___setitem___on_concrete() -> None:
2326
+ # NOTE: This is very challenging to implement: opcode interception could upgrade
2327
+ # the concrete dictionary to a symbolic, but the original dictionary may be aliased.
2328
+ # One investigation: start everything out as symbolic by intercepting BUILD_MAP and
2329
+ # BUILD_SET. This potentially also lets us detect writes to persistent state
2330
+ # (because all pre-existing dicts/sets will be concrete).
2331
+ def f(k: int, v: int) -> Dict[int, int]:
2332
+ """post: _[100] == 200"""
2333
+ d = {100: 200}
2334
+ d[k] = v
2335
+ return d
2336
+
2337
+ check_states(f, POST_FAIL)
2338
+
2339
+
2340
+ def test_dict___str__() -> None:
2341
+ def f(a: Dict[int, str]) -> str:
2342
+ """
2343
+ pre: len(a) == 0
2344
+ post: _ == '{}'
2345
+ """
2346
+ return str(a)
2347
+
2348
+ check_states(f, CONFIRMED)
2349
+
2350
+
2351
+ @pytest.mark.demo
2352
+ def test_dict_get_method():
2353
+ def f(x: int) -> int:
2354
+ """
2355
+ Can we find the key that is mapped to 5?
2356
+
2357
+ post: _ != 5
2358
+ """
2359
+ a = {2: 3, 4: 5, 6: 7}
2360
+ return a.get(x, 9)
2361
+
2362
+ check_states(f, POST_FAIL)
2363
+
2364
+
2365
+ def test_dict_get_with_defaults_ok() -> None:
2366
+ def f(a: Dict[int, int]) -> int:
2367
+ """post: (_ == 2) or (_ == a[4])"""
2368
+ return a.get(4, 2)
2369
+
2370
+ check_states(f, CONFIRMED)
2371
+
2372
+
2373
+ def test_dict_items_ok() -> None:
2374
+ def f(a: Dict[int, str]) -> Iterable[Tuple[int, str]]:
2375
+ """
2376
+ pre: len(a) < 5
2377
+ post[a]: (10,'ten') in _
2378
+ """
2379
+ a[10] = "ten"
2380
+ return a.items()
2381
+
2382
+ check_states(f, CONFIRMED)
2383
+
2384
+
2385
+ def test_dict_setdefault_float_int_comparison() -> None:
2386
+ def f(a: Dict[int, int]):
2387
+ """
2388
+ pre: a == {2: 0}
2389
+ post: _ == 0
2390
+ """
2391
+ return a.setdefault(2.0, {True: "0"}) # type: ignore
2392
+
2393
+ check_states(f, CONFIRMED)
2394
+
2395
+
2396
+ def test_dict_construction_from_generator(space):
2397
+ with ResumedTracing():
2398
+ d = dict((k, v) for k, v in [(1, 2), (3, 4)])
2399
+ assert d == {1: 2, 3: 4}
2400
+
2401
+
2402
+ def test_dict_construction_copies_dict(space):
2403
+ with ResumedTracing():
2404
+ source = {1: 2, 3: 4}
2405
+ copy = dict(source)
2406
+ source[5] = 6
2407
+ assert copy == {1: 2, 3: 4}
2408
+
2409
+
2410
+ def test_dict_construction_with_duplicate_keys(space):
2411
+ with ResumedTracing():
2412
+ d = dict([(1, 2), (3, 4), (1, 10), (5, 6), (3, 10)])
2413
+ assert d == {1: 10, 3: 10, 5: 6}
2414
+
2415
+
2416
+ def test_dict_over_objects() -> None:
2417
+ def f(a: Dict[object, object]) -> int:
2418
+ """
2419
+ post: _ >= 0
2420
+ """
2421
+ return len(a)
2422
+
2423
+ check_states(f, CONFIRMED)
2424
+
2425
+
2426
+ def test_dict_over_heap_objects() -> None:
2427
+ def f(a: Dict[Tuple[int], int]) -> Optional[int]:
2428
+ """
2429
+ post: _ != 10
2430
+ """
2431
+ return a.get((5,))
2432
+
2433
+ check_states(f, POST_FAIL)
2434
+
2435
+
2436
+ def test_dict_complex_contents() -> None:
2437
+ def f(d: Dict[Tuple[int, bool], Tuple[float, int]]) -> int:
2438
+ """
2439
+ post: _ > 0
2440
+ """
2441
+ if (42, True) in d:
2442
+ return d[(42, True)][1]
2443
+ else:
2444
+ return 42
2445
+
2446
+ check_states(f, MessageType.POST_FAIL)
2447
+
2448
+
2449
+ def test_dict_isinstance_check() -> None:
2450
+ def f(smtdict: Dict[int, int], heapdict: Dict) -> Tuple[bool, bool]:
2451
+ """post: _ == (True, True)"""
2452
+ return (isinstance(smtdict, dict), isinstance(heapdict, dict))
2453
+
2454
+ check_states(f, CONFIRMED)
2455
+
2456
+
2457
+ def test_dict_subtype_lookup() -> None:
2458
+ def f(d: Dict[Tuple[int, str], int]) -> None:
2459
+ """
2460
+ pre: not d
2461
+ post[d]: [(42, 'fourty-two')] == list(d.keys())
2462
+ """
2463
+ d[(42, "fourty-two")] = 1
2464
+
2465
+ check_states(f, CONFIRMED)
2466
+
2467
+
2468
+ def test_dict_complex_keys() -> None:
2469
+ def f(dx: Dict[Tuple[int, str], int]) -> None:
2470
+ """
2471
+ pre: not dx
2472
+ post[dx]:
2473
+ len(dx) == 1
2474
+ dx[(42, 'fourty-two')] == 1
2475
+ """
2476
+ dx[(42, "fourty-two")] = 1
2477
+
2478
+ check_states(f, CONFIRMED)
2479
+
2480
+
2481
+ def test_dict_has_unique_keys() -> None:
2482
+ def f(d: Dict[Tuple[int, str], int]) -> None:
2483
+ """
2484
+ pre: len(d) == 2 and (1, 'one') in d
2485
+ post[d]: (1, 'one') not in d
2486
+ """
2487
+ del d[(1, "one")]
2488
+
2489
+ check_states(f, CONFIRMED)
2490
+
2491
+
2492
+ def test_dict_wrong_key_type() -> None:
2493
+ def f(d: Dict[int, int], s: str, i: int) -> bool:
2494
+ """
2495
+ post: _
2496
+ raises: KeyError
2497
+ """
2498
+ if i == 0:
2499
+ del d[s] # type: ignore
2500
+ elif i < 0:
2501
+ d[s] = 7 # type: ignore
2502
+ else:
2503
+ _val = d[s] # type: ignore
2504
+ return True
2505
+
2506
+ check_states(f, CANNOT_CONFIRM)
2507
+
2508
+
2509
+ def test_dict_key_type_union() -> None:
2510
+ def f(d: Dict[Union[int, str], int]) -> Dict:
2511
+ """
2512
+ pre: len(d) == 2
2513
+ post: not (42 in d and '42' in d)
2514
+ """
2515
+ return d
2516
+
2517
+ check_states(f, POST_FAIL)
2518
+
2519
+
2520
+ if sys.version_info >= (3, 10):
2521
+
2522
+ def test_dict_type_union_operator() -> None:
2523
+ def f(a: int | str, b: int | str) -> Tuple[int | str, int | str]:
2524
+ """post: _ != (42, "hi")"""
2525
+ return (a, b)
2526
+
2527
+ check_states(f, POST_FAIL)
2528
+
2529
+
2530
+ @pytest.mark.smoke
2531
+ def test_dict_nonuniform_dict_key_types() -> None:
2532
+ def f(a: Dict[Hashable, int]) -> Dict[Hashable, int]:
2533
+ """
2534
+ pre: len(a) == 1
2535
+ post: _[0] == 100
2536
+ """
2537
+ b: Dict[Hashable, int] = {0: 100}
2538
+ b.update(a)
2539
+ return b
2540
+
2541
+ check_states(f, POST_FAIL)
2542
+
2543
+
2544
+ def test_dict_inside_lists() -> None:
2545
+ def f(dicts: List[Dict[int, int]]) -> Dict[int, int]:
2546
+ """
2547
+ pre: len(dicts) <= 1 # to narrow search space (would love to make this larger)
2548
+ post: len(_) <= len(dicts)
2549
+ """
2550
+ ret = {}
2551
+ for d in dicts:
2552
+ ret.update(d)
2553
+ return ret
2554
+
2555
+ check_states(f, POST_FAIL)
2556
+
2557
+
2558
+ @pytest.mark.skip(
2559
+ reason="flakey; seems to get stuck sometimes despite timeout extensions"
2560
+ )
2561
+ def test_dict_inside_lists_with_identity() -> None:
2562
+ def f(dicts: List[Dict[int, int]]):
2563
+ """
2564
+ Removes duplicate keys.
2565
+ pre: len(dicts) == 2
2566
+ pre: len(dicts[0]) == 1
2567
+ post: len(dicts[0]) == 1
2568
+ """
2569
+ # crosshair: max_uninteresting_iterations=50
2570
+ seen: Set[int] = set()
2571
+ for d in dicts:
2572
+ for k in d.keys():
2573
+ if k in seen:
2574
+ del d[k]
2575
+ else:
2576
+ seen.add(k)
2577
+
2578
+ check_states(f, POST_FAIL)
2579
+
2580
+
2581
+ def test_dict_consistent_ordering() -> None:
2582
+ def f(symbolic: Dict[int, int]) -> Tuple[List[int], List[int]]:
2583
+ """post: _[0] == _[1]"""
2584
+ return (list(symbolic.keys()), list(symbolic.keys()))
2585
+
2586
+ check_states(f, CANNOT_CONFIRM)
2587
+
2588
+
2589
+ def test_dict_ordering_after_mutations() -> None:
2590
+ def f(d: Dict[int, int]) -> Tuple[Tuple[int, int], Tuple[int, int]]:
2591
+ """
2592
+ pre: len(d) == 3
2593
+ post[d]: _[0] == _[1]
2594
+ """
2595
+ o1, middle, o2 = d.keys()
2596
+ d[o1] = 42
2597
+ d[o2] = 42
2598
+ del d[middle]
2599
+ n1, n2 = d.keys()
2600
+ return ((o1, o2), (n1, n2))
2601
+
2602
+ check_states(f, CONFIRMED)
2603
+
2604
+
2605
+ def test_dict_alternate_mapping_types() -> None:
2606
+ def f(m1: Mapping[int, int], m2: MutableMapping[int, int]) -> int:
2607
+ """
2608
+ pre: 1 in m1 and 2 in m2
2609
+ post: _ != 10
2610
+ """
2611
+ return m1[1] + m2[2]
2612
+
2613
+ check_states(f, POST_FAIL)
2614
+
2615
+
2616
+ def test_dict_untyped_access():
2617
+ def f(d: dict, k: int) -> dict:
2618
+ """
2619
+ pre: len(d) == 2 # (just to bound the search space a little)
2620
+ pre: 42 in d
2621
+ post: 42 in __return__
2622
+ raises: KeyError
2623
+ """
2624
+ del d[k]
2625
+ return d
2626
+
2627
+ check_states(f, MessageType.POST_FAIL)
2628
+
2629
+
2630
+ # NOTE: TypedDict appeared earlier than 3.9, but was not runtime-detectable until then
2631
+ if sys.version_info >= (3, 9):
2632
+
2633
+ def test_TypedDict_fail() -> None:
2634
+ def f(td: Movie):
2635
+ '''post: _['year'] != 2020 or _['name'] != "hi"'''
2636
+ return td
2637
+
2638
+ check_states(f, POST_FAIL)
2639
+
2640
+ def test_TypedDict_in_container_fail() -> None:
2641
+ def f(tdlist: List[Movie]):
2642
+ """post: _[1]['year'] != 2020"""
2643
+ return tdlist
2644
+
2645
+ check_states(f, POST_FAIL)
2646
+
2647
+
2648
+ @pytest.mark.smoke
2649
+ def test_set_basic_fail() -> None:
2650
+ def f(a: Set[int], k: int) -> None:
2651
+ """
2652
+ pre: len(a) <= 2
2653
+ post[a]: k+1 in a
2654
+ """
2655
+ a.add(k)
2656
+
2657
+ check_states(f, POST_FAIL)
2658
+
2659
+
2660
+ def test_set_basic_ok() -> None:
2661
+ def f(a: Set[int], k: int) -> None:
2662
+ """
2663
+ post[a]: k in a
2664
+ """
2665
+ a.add(k)
2666
+
2667
+ check_states(f, CONFIRMED)
2668
+
2669
+
2670
+ def test_set_union_fail() -> None:
2671
+ def f(a: Set[str], b: Set[str]) -> Set[str]:
2672
+ """
2673
+ pre: len(a) == len(b) == 1 # (just for test performance)
2674
+ post: all(((i in a) and (i in b)) for i in _)
2675
+ """
2676
+ return a | b
2677
+
2678
+ check_states(f, POST_FAIL)
2679
+
2680
+
2681
+ def test_set_union_ok() -> None:
2682
+ def f(a: Set[str], b: Set[str]) -> Set[str]:
2683
+ """
2684
+ post: all(((i in a) or (i in b)) for i in _)
2685
+ """
2686
+ return a | b
2687
+
2688
+ check_states(f, CANNOT_CONFIRM)
2689
+
2690
+
2691
+ def test_set_contains_different_but_equivalent() -> None:
2692
+ def f(s: Set[Union[int, str]]) -> str:
2693
+ """
2694
+ pre: "foobar" in s
2695
+ post: (_ + "bar") in s
2696
+ """
2697
+ return "foo"
2698
+
2699
+ check_states(f, CANNOT_CONFIRM)
2700
+
2701
+
2702
+ # The heaprefs + deferred set assumptions make this too expensive.
2703
+ # TODO: Optimize & re-enable
2704
+ def TODO_set_test_subtype_union() -> None:
2705
+ def f(s: Set[Union[int, str]]) -> Set[Union[int, str]]:
2706
+ """post: not ((42 in s) and ('42' in s))"""
2707
+ return s
2708
+
2709
+ check_states(f, MessageType.POST_FAIL)
2710
+
2711
+
2712
+ def test_set_subset_compare_ok() -> None:
2713
+ # a >= b with {'a': {0.0, 1.0}, 'b': {2.0}}
2714
+ def f(s1: Set[int], s2: Set[int]) -> bool:
2715
+ """
2716
+ pre: s1 == {0, 1}
2717
+ pre: s2 == {2}
2718
+ post: not _
2719
+ """
2720
+ return s1 >= s2
2721
+
2722
+ check_states(f, CONFIRMED)
2723
+
2724
+
2725
+ def test_set_numeric_promotion() -> None:
2726
+ def f(b: bool, s: Set[int]) -> bool:
2727
+ """
2728
+ pre: b == True
2729
+ pre: s == {1}
2730
+ post: _
2731
+ """
2732
+ return b in s
2733
+
2734
+ check_states(f, CONFIRMED)
2735
+
2736
+
2737
+ def test_set_runtime_type_ok() -> None:
2738
+ def f(s: set) -> bool:
2739
+ """post: _"""
2740
+ return True
2741
+
2742
+ check_states(f, CONFIRMED)
2743
+
2744
+
2745
+ def test_set_isinstance_check() -> None:
2746
+ def f(s: Set[object]) -> bool:
2747
+ """post: _"""
2748
+ return isinstance(s, set)
2749
+
2750
+ check_states(f, CONFIRMED)
2751
+
2752
+
2753
+ def test_frozenset___eq__(space):
2754
+ fs = proxy_for_type(Set[FrozenSet[int]], "fs")
2755
+ with ResumedTracing():
2756
+ space.add(len(fs) == 1)
2757
+ space.add(len(next(iter(fs))) == 0)
2758
+ linearset = set([frozenset()])
2759
+ iseq = realize(fs == linearset)
2760
+ assert iseq is True
2761
+
2762
+
2763
+ def test_set___eq__() -> None:
2764
+ def f(a: Set[FrozenSet[int]]) -> object:
2765
+ """
2766
+ pre: a == {frozenset({7}), frozenset({42})}
2767
+ post: _ in ('{frozenset({7}), frozenset({42})}', '{frozenset({42}), frozenset({7})}')
2768
+ """
2769
+ return repr(a)
2770
+
2771
+ check_states(
2772
+ f,
2773
+ MessageType.CONFIRMED,
2774
+ AnalysisOptionSet(per_path_timeout=10, per_condition_timeout=10),
2775
+ )
2776
+
2777
+
2778
+ def test_frozenset___repr__symbolic_in_concrete(space) -> None:
2779
+ x = proxy_for_type(int, "x")
2780
+ with ResumedTracing():
2781
+ space.add(x == 4) # type: ignore
2782
+ container = frozenset([x])
2783
+ assert repr(container) == "frozenset({4})"
2784
+
2785
+
2786
+ def test_set___repr__symbolic_in_concrete(space) -> None:
2787
+ x = proxy_for_type(int, "x")
2788
+ with ResumedTracing():
2789
+ space.add(x == 4) # type: ignore
2790
+ container = {x}
2791
+ assert repr(container) == "{4}"
2792
+
2793
+
2794
+ def test_set_copy(space):
2795
+ x = proxy_for_type(Set[int], "x")
2796
+ with ResumedTracing():
2797
+ space.add(len(x) == 1)
2798
+ (y, z) = copy.deepcopy((x, x))
2799
+ assert not space.is_possible(len(y) != 1)
2800
+ assert not space.is_possible(list(x)[0] != list(y)[0])
2801
+
2802
+
2803
+ def test_set_no_duplicates() -> None:
2804
+ def f(s: Set[int]) -> int:
2805
+ """
2806
+ pre: len(s) == 2
2807
+ post: _
2808
+ """
2809
+ i = iter(s)
2810
+ x = next(i)
2811
+ y = next(i)
2812
+ return x != y
2813
+
2814
+ check_states(f, CONFIRMED)
2815
+
2816
+
2817
+ def test_set_additions_to_concrete() -> None:
2818
+ class F:
2819
+ set_type = set
2820
+
2821
+ def f(self: F, x: int) -> Set[int]:
2822
+ """
2823
+ post: _ != set([1234])
2824
+ """
2825
+ return self.set_type([x, x])
2826
+
2827
+ check_states(f, POST_FAIL)
2828
+
2829
+
2830
+ def test_frozenset_realize():
2831
+ with standalone_statespace as space:
2832
+ with NoTracing():
2833
+ x = proxy_for_type(FrozenSet[int], "x")
2834
+ y = realize(x)
2835
+ assert type(y) is frozenset
2836
+ assert type(x) is frozenset
2837
+
2838
+
2839
+ def test_frozenset_covariance():
2840
+ with standalone_statespace as space:
2841
+ frozen_set = proxy_for_type(FrozenSet[AbstractBase], "x")
2842
+ space.add(frozen_set.__len__() == 1)
2843
+ with NoTracing():
2844
+ assert isinstance(next(iter(frozen_set)), ConcreteSubclass)
2845
+
2846
+
2847
+ def test_set_invariance():
2848
+ # `set` is invariant, but that doesn't mean it cannot contain subclasses -
2849
+ # it just means that something *typed* as a subclass container cannot be
2850
+ # assigned to a superclass container.
2851
+ # Therefore, CrossHair should happily create set contents using subclasses:
2852
+ with standalone_statespace as space:
2853
+ mutable_set = proxy_for_type(Set[AbstractBase], "x")
2854
+ space.add(mutable_set.__len__() == 1)
2855
+ with NoTracing():
2856
+ assert isinstance(next(iter(mutable_set)), ConcreteSubclass)
2857
+
2858
+
2859
+ def test_set_realize():
2860
+ with standalone_statespace as space:
2861
+ with NoTracing():
2862
+ x = proxy_for_type(Set[str], "x")
2863
+ assert type(x) is not set
2864
+ y = realize(x)
2865
+ assert type(y) is set
2866
+ assert type(x) is set
2867
+
2868
+
2869
+ def test_set_iter_partial():
2870
+ with standalone_statespace as space:
2871
+ with NoTracing():
2872
+ x = proxy_for_type(Set[int], "x")
2873
+ space.add(x.__len__() == 2)
2874
+ itr = iter(x)
2875
+ first = next(itr)
2876
+ # leave the iterator incomplete; looking for generator + context mgr problems
2877
+
2878
+
2879
+ def test_set_containment_check_without_iteration():
2880
+ with standalone_statespace as space:
2881
+ x = proxy_for_type(FrozenSet[int], "x")
2882
+ with ResumedTracing():
2883
+ space.add(len(x) == 1)
2884
+ assert space.is_possible(x._is_consistent())
2885
+ space.add(x.__contains__(42))
2886
+ assert space.is_possible(x._is_consistent())
2887
+ space.add(x.__contains__(10))
2888
+ assert not space.is_possible(x._is_consistent())
2889
+
2890
+
2891
+ def test_set_independence(space):
2892
+ with ResumedTracing():
2893
+ s = set()
2894
+ copy = set(s)
2895
+ s |= s
2896
+ s != copy
2897
+
2898
+
2899
+ def test_frozenset___or__(space):
2900
+ x = proxy_for_type(int, "x")
2901
+ y = proxy_for_type(int, "y")
2902
+ with ResumedTracing():
2903
+ space.add(x != y)
2904
+ s1 = frozenset([x])
2905
+ s2 = frozenset([y])
2906
+ assert len(s1 | s2) == 2
2907
+
2908
+
2909
+ class TestProtocols:
2910
+ # TODO: move most of this into a collectionslib_test.py file
2911
+ def test_hashable_values_fail(self) -> None:
2912
+ def f(b: bool, i: int, t: Tuple[str, ...]) -> int:
2913
+ """post: _ % 5 != 0"""
2914
+ return hash((b, i, t))
2915
+
2916
+ check_states(f, POST_FAIL)
2917
+
2918
+ def test_hashable_values_ok(self) -> None:
2919
+ def f(a: Tuple[str, int, float, bool], b: Tuple[str, int, float, bool]) -> int:
2920
+ """post: _ or not (a == b)"""
2921
+ return hash(a) == hash(b)
2922
+
2923
+ check_states(f, CANNOT_CONFIRM)
2924
+
2925
+ def test_symbolic_hashable(self) -> None:
2926
+ def f(a: Hashable) -> int:
2927
+ """post[]: 0 <= _ <= 1"""
2928
+ return hash(a) % 2
2929
+
2930
+ check_states(f, CONFIRMED)
2931
+
2932
+ def test_symbolic_supports(self) -> None:
2933
+ def f(
2934
+ a: SupportsAbs,
2935
+ f: SupportsFloat,
2936
+ i: SupportsInt,
2937
+ r: SupportsRound,
2938
+ # c: SupportsComplex, # TODO: symbolic complex not yet really working
2939
+ b: SupportsBytes,
2940
+ ) -> float:
2941
+ """
2942
+ pre: math.isfinite(f) and math.isfinite(r)
2943
+ post: _.real <= 0
2944
+ """
2945
+ return abs(a) + float(f) + int(i) + round(r) + len(bytes(b))
2946
+ # + complex(c)
2947
+
2948
+ check_states(f, POST_FAIL)
2949
+
2950
+ def test_iterable(self) -> None:
2951
+ T = TypeVar("T")
2952
+
2953
+ def f(a: Iterable[T]) -> T:
2954
+ """
2955
+ pre: a
2956
+ post: _ in a
2957
+ """
2958
+ return next(iter(a))
2959
+
2960
+ check_states(f, CANNOT_CONFIRM)
2961
+
2962
+ def test_bare_type(self) -> None:
2963
+ def f(a: List) -> bool:
2964
+ """
2965
+ pre: a
2966
+ post: _
2967
+ """
2968
+ return bool(a)
2969
+
2970
+ check_states(f, CONFIRMED)
2971
+
2972
+
2973
+ def test_enum_identity_matches_equality() -> None:
2974
+ def f(color1: Color, color2: Color) -> bool:
2975
+ """post: _ == (color1 is color2)"""
2976
+ return color1 == color2
2977
+
2978
+ check_states(f, CONFIRMED)
2979
+
2980
+
2981
+ def test_enum_in_container() -> None:
2982
+ def f(colors: List[Color]) -> bool:
2983
+ """post: not _"""
2984
+ return Color.RED in colors and Color.BLUE in colors
2985
+
2986
+ check_states(f, POST_FAIL)
2987
+
2988
+
2989
+ def test_type_issubclass_ok() -> None:
2990
+ def f(typ: Type[SmokeDetector]):
2991
+ """post: _"""
2992
+ return issubclass(typ, SmokeDetector)
2993
+
2994
+ check_states(f, CONFIRMED)
2995
+
2996
+
2997
+ def test_type_can_be_a_subclass() -> None:
2998
+ def f(typ: Type[Cat]):
2999
+ """post: _ == "<class '__main__.Cat'>" """
3000
+ return str(typ)
3001
+
3002
+ # False when the type is instantiated as "BiggerCat":
3003
+ check_states(f, POST_FAIL)
3004
+
3005
+
3006
+ def test_type_issubclass_fail() -> None:
3007
+ def f(typ: Type):
3008
+ """post: _"""
3009
+ return issubclass(typ, str)
3010
+
3011
+ check_states(f, POST_FAIL)
3012
+
3013
+
3014
+ def test_type_symbolics_without_literal_types() -> None:
3015
+ def f(typ1: Type, typ2: Type[bool], typ3: Type):
3016
+ """post: implies(_, issubclass(typ1, typ3))"""
3017
+ # The counterexample we expect: typ1==str typ2==bool typ3==int
3018
+ return issubclass(typ2, typ3) and typ2 != typ3
3019
+
3020
+ check_states(
3021
+ f,
3022
+ POST_FAIL,
3023
+ )
3024
+
3025
+
3026
+ def test_type_instance_creation() -> None:
3027
+ def f(t: Type[Cat]):
3028
+ """post: _.size() > 0"""
3029
+ return t()
3030
+
3031
+ check_states(f, CONFIRMED)
3032
+
3033
+
3034
+ def test_type_comparison() -> None:
3035
+ def f(t: Type) -> bool:
3036
+ """post: _"""
3037
+ return t == int
3038
+
3039
+ check_states(f, POST_FAIL)
3040
+
3041
+
3042
+ def test_type_as_bool() -> None:
3043
+ def f(t: Type) -> bool:
3044
+ """post: _"""
3045
+ return bool(t)
3046
+
3047
+ check_states(f, CONFIRMED)
3048
+
3049
+
3050
+ def test_type_generic_object_and_type() -> None:
3051
+ def f(thing: object, detector_kind: Type[SmokeDetector]):
3052
+ """post: True"""
3053
+ if isinstance(thing, detector_kind):
3054
+ return thing._is_plugged_in
3055
+ return False
3056
+
3057
+ check_states(f, CANNOT_CONFIRM)
3058
+
3059
+
3060
+ def test_object___eq__() -> None:
3061
+ def f(thing: object, i: int):
3062
+ """post: not _"""
3063
+ return thing == i
3064
+
3065
+ check_states(f, POST_FAIL)
3066
+
3067
+
3068
+ def test_object_get_type_hints(space: StateSpace) -> None:
3069
+ typ = proxy_for_type(type, "typ")
3070
+ with ResumedTracing():
3071
+ get_type_hints(typ)
3072
+
3073
+
3074
+ def test_issubclass_abc():
3075
+ with standalone_statespace as space:
3076
+ with NoTracing():
3077
+ dict_subtype = SymbolicType("dict_subtype", Type[dict])
3078
+ issub = issubclass(dict_subtype, collections.abc.Mapping)
3079
+ with NoTracing():
3080
+ # `issub` is lazily determined:
3081
+ assert type(issub) is SymbolicBool
3082
+ assert space.is_possible(issub.var)
3083
+ assert space.is_possible(z3.Not(issub.var))
3084
+ # We can artificially assert that this dict type is somehow not a Mapping:
3085
+ space.add(z3.Not(issub.var))
3086
+ # And CrossHair will give up when it comes time to find some such a type:
3087
+ with pytest.raises(IgnoreAttempt):
3088
+ realize(dict_subtype)
3089
+
3090
+
3091
+ def test_object_with_comparison():
3092
+ def f(obj):
3093
+ """post: _"""
3094
+ return obj != b"abc"
3095
+
3096
+ check_states(f, POST_FAIL)
3097
+
3098
+
3099
+ def test_object_addition():
3100
+ def f(a, b):
3101
+ """post: True"""
3102
+ return a + b
3103
+
3104
+ actual, expected = check_messages(
3105
+ analyze_function(f),
3106
+ state=MessageType.EXEC_ERR,
3107
+ # We check the message here, because we used to produce an
3108
+ # (incorrect) counterexample of f('', '')
3109
+ # See https://github.com/pschanely/CrossHair/issues/235
3110
+ message="TypeError: when calling f('', 0)",
3111
+ )
3112
+ assert actual == expected
3113
+
3114
+
3115
+ def test_invoke_integer():
3116
+ # https://github.com/pschanely/CrossHair/issues/236
3117
+ def f(a: int):
3118
+ """post: True"""
3119
+ return a(1) # type: ignore
3120
+
3121
+ check_states(f, EXEC_ERR)
3122
+
3123
+
3124
+ def test_callable_zero_args() -> None:
3125
+ def f(size: int, initializer: Callable[[], int]) -> Tuple[int, ...]:
3126
+ """
3127
+ pre: size >= 1
3128
+ post: _[0] != 707
3129
+ """
3130
+ return tuple(initializer() for _ in range(size))
3131
+
3132
+ check_states(f, POST_FAIL)
3133
+
3134
+
3135
+ @pytest.mark.smoke
3136
+ def test_callable_one_arg() -> None:
3137
+ def f(size: int, mapfn: Callable[[int], int]) -> Tuple[int, ...]:
3138
+ """
3139
+ pre: size >= 1
3140
+ post: _[0] != 707
3141
+ """
3142
+ return tuple(mapfn(i) for i in range(size))
3143
+
3144
+ check_states(f, POST_FAIL)
3145
+
3146
+
3147
+ def test_callable_two_args() -> None:
3148
+ def f(i: int, c: Callable[[int, int], int]) -> int:
3149
+ """post: _ != i"""
3150
+ return c(i, i)
3151
+
3152
+ check_states(f, POST_FAIL)
3153
+
3154
+
3155
+ def test_callable_as_bool() -> None:
3156
+ def f(fn: Callable[[int], int]) -> bool:
3157
+ """post: _"""
3158
+ return bool(fn)
3159
+
3160
+ check_states(f, CONFIRMED)
3161
+
3162
+
3163
+ def test_callable_can_return_different_values(space) -> None:
3164
+ fn = proxy_for_type(Callable[[], int], "fn")
3165
+ with ResumedTracing():
3166
+ first_return = fn()
3167
+ second_return = fn()
3168
+ returns_are_equal = first_return == second_return
3169
+ returns_are_not_equal = first_return != second_return
3170
+ assert space.is_possible(returns_are_equal)
3171
+ assert space.is_possible(returns_are_not_equal)
3172
+
3173
+
3174
+ @pytest.mark.smoke
3175
+ def test_callable_repr() -> None:
3176
+ def f(f1: Callable[[int], int]) -> int:
3177
+ """post: _ != 1234"""
3178
+ return f1(4)
3179
+
3180
+ messages = run_checkables(analyze_function(f))
3181
+ assert len(messages) == 1
3182
+ assert re.compile(
3183
+ r"false when calling f\(.*lambda.*\(which returns 1234\)"
3184
+ ).fullmatch(messages[0].message)
3185
+
3186
+
3187
+ def test_callable_with_typevar_in_args() -> None:
3188
+ T = TypeVar("T")
3189
+
3190
+ def f(a: Callable[[T], int], x: T) -> int:
3191
+ """post: _ != 42"""
3192
+ return a(x)
3193
+
3194
+ check_states(f, POST_FAIL)
3195
+
3196
+
3197
+ def test_callable_with_typevar_in_return() -> None:
3198
+ T = TypeVar("T")
3199
+
3200
+ def f(a: Callable[[int], T], x: int) -> T:
3201
+ """post: _"""
3202
+ return a(x)
3203
+
3204
+ check_states(f, POST_FAIL)
3205
+
3206
+
3207
+ def TODO_test_callable_with_typevars() -> None:
3208
+ # Right now, this incorrectly reports a counterexample like:
3209
+ # a=`lambda x : 42` and k=''
3210
+ # (the type vars preclude such a counterexample)
3211
+ # Note also a related issue: https://github.com/pschanely/CrossHair/issues/85
3212
+ T = TypeVar("T")
3213
+
3214
+ def f(a: Callable[[T], T], k: T) -> T:
3215
+ """post: _ != 42"""
3216
+ if isinstance(k, int):
3217
+ return 0 # type: ignore
3218
+ return a(k)
3219
+
3220
+ check_states(f, CANNOT_CONFIRM) # or maybe CONFIRMED?
3221
+
3222
+
3223
+ def test_all():
3224
+ class ExplodingBool(BaseException):
3225
+ def __bool__(self):
3226
+ raise self
3227
+
3228
+ with standalone_statespace as space:
3229
+ true_bool = proxy_for_type(bool, "true_bool")
3230
+ space.add(true_bool)
3231
+ nonempty_list = proxy_for_type(List[object], "nonempty_list")
3232
+ space.add(len(nonempty_list) == 1)
3233
+ arbitrary_bool = proxy_for_type(bool, "arbitrary_bool")
3234
+ boom = ExplodingBool()
3235
+
3236
+ assert all([true_bool, True, nonempty_list, 42]) is True
3237
+
3238
+ sym_false = all([True, true_bool, nonempty_list, arbitrary_bool])
3239
+ with NoTracing():
3240
+ assert isinstance(sym_false, SymbolicBool)
3241
+ assert space.is_possible(z3.Not(sym_false.var))
3242
+ assert space.is_possible(sym_false)
3243
+
3244
+ with pytest.raises(ExplodingBool):
3245
+ all([true_bool, True, nonempty_list, boom])
3246
+
3247
+ assert all([true_bool, nonempty_list, False, boom]) is False
3248
+
3249
+
3250
+ def test_any():
3251
+ class ExplodingBool(BaseException):
3252
+ def __bool__(self):
3253
+ raise self
3254
+
3255
+ with standalone_statespace as space:
3256
+ false_bool = proxy_for_type(bool, "false_bool")
3257
+ space.add(z3.Not(false_bool.var))
3258
+ empty_list = proxy_for_type(List[object], "empty_list")
3259
+ space.add(len(empty_list) == 0)
3260
+ arbitrary_bool = proxy_for_type(bool, "arbitrary_bool")
3261
+ # arbitrary_list = proxy_for_type(List[object], "arbitrary_list")
3262
+ # TODO: in theory, we should be able to keep `bool(arbitrary_list)`
3263
+ # symbolic. However, not enough of the system is resilient to symbolic
3264
+ # booleans. (at the very least, the UNARY_NOT opcode)
3265
+ boom = ExplodingBool()
3266
+
3267
+ assert any([false_bool, False, empty_list, 0]) is False
3268
+
3269
+ sym_false = any([False, false_bool, empty_list, arbitrary_bool])
3270
+ with NoTracing():
3271
+ assert isinstance(sym_false, SymbolicBool)
3272
+ assert space.is_possible(z3.Not(sym_false.var))
3273
+ assert space.is_possible(sym_false)
3274
+
3275
+ with pytest.raises(ExplodingBool):
3276
+ any([false_bool, False, empty_list, boom])
3277
+
3278
+ assert any([false_bool, empty_list, True, boom]) is True
3279
+
3280
+
3281
+ def test_hash() -> None:
3282
+ def f(s: int) -> int:
3283
+ """post: True"""
3284
+ return hash(s)
3285
+
3286
+ check_states(f, CONFIRMED)
3287
+
3288
+
3289
+ @pytest.mark.demo
3290
+ def test_getattr() -> None:
3291
+ def f(s: str) -> int:
3292
+ """
3293
+ Can this function return 42?
3294
+
3295
+ post: _ != 42
3296
+ """
3297
+
3298
+ class Otter:
3299
+ def do_things(self) -> int:
3300
+ return 42
3301
+
3302
+ try:
3303
+ return getattr(Otter(), s)()
3304
+ except Exception:
3305
+ return 0
3306
+
3307
+ check_states(f, POST_FAIL)
3308
+
3309
+
3310
+ def TODO_test_print_ok() -> None:
3311
+ def f(x: int) -> bool:
3312
+ """
3313
+ post: _ == True
3314
+ """
3315
+ print(x)
3316
+ return True
3317
+
3318
+ check_states(f, CONFIRMED)
3319
+
3320
+
3321
+ def test_repr_ok():
3322
+ def f(x: int) -> str:
3323
+ """post: len(_) == 0 or len(_) > 0"""
3324
+ return repr(x)
3325
+
3326
+ check_states(f, CONFIRMED)
3327
+
3328
+
3329
+ @pytest.mark.demo
3330
+ def test_map() -> None:
3331
+ def f(ls: List[int]) -> List[int]:
3332
+ """
3333
+ Can an incremented list equal [4, 9, 0]?
3334
+
3335
+ post: _ != [4, 9, 0]
3336
+ """
3337
+ return list(map(lambda x: x + 1, ls))
3338
+
3339
+ check_states(f, POST_FAIL)
3340
+
3341
+
3342
+ def test_max_fail() -> None:
3343
+ def f(ls: List[int]) -> int:
3344
+ """
3345
+ post: _ in ls
3346
+ """
3347
+ return max(ls)
3348
+
3349
+ check_states(f, EXEC_ERR)
3350
+
3351
+
3352
+ def test_max_ok() -> None:
3353
+ def f(ls: List[int]) -> int:
3354
+ """
3355
+ pre: bool(ls)
3356
+ post[]: _ in ls
3357
+ """
3358
+ return max(ls)
3359
+
3360
+ check_states(f, CANNOT_CONFIRM)
3361
+
3362
+
3363
+ def test_min_ok() -> None:
3364
+ def f(ls: List[float]) -> float:
3365
+ """
3366
+ pre: bool(ls)
3367
+ post[]: _ in ls
3368
+ """
3369
+ return min(ls)
3370
+
3371
+ check_states(f, CANNOT_CONFIRM)
3372
+
3373
+
3374
+ def test_list_index_on_concrete() -> None:
3375
+ def f(i: int) -> int:
3376
+ """post: True"""
3377
+ return [0, 1, 2].index(i)
3378
+
3379
+ (actual, expected) = check_exec_err(f, "ValueError:")
3380
+ assert actual == expected
3381
+
3382
+
3383
+ def test_eval_namespaces() -> None:
3384
+ def f(i: int) -> int:
3385
+ """post: _ == i + 1"""
3386
+ return eval("i + Color.BLUE.value")
3387
+
3388
+ check_states(f, CONFIRMED)
3389
+
3390
+
3391
+ def test_bytes_specific_length() -> None:
3392
+ def f(b: bytes) -> int:
3393
+ """post: _ != 5"""
3394
+ return len(b)
3395
+
3396
+ check_states(f, POST_FAIL)
3397
+
3398
+
3399
+ def test_bytes_out_of_range_byte() -> None:
3400
+ def f(b: bytes) -> bytes:
3401
+ """
3402
+ pre: len(b) == 1
3403
+ post: _[0] != 256
3404
+ """
3405
+ return b
3406
+
3407
+ check_states(f, CONFIRMED)
3408
+
3409
+
3410
+ def test_bytes_roundtrip_array_as_symbolic():
3411
+ with standalone_statespace as space:
3412
+ orig_bytes = proxy_for_type(bytes, "origbytes")
3413
+ as_array = bytearray(orig_bytes)
3414
+ new_bytes = bytes(as_array)
3415
+ with NoTracing():
3416
+ assert type(as_array) is SymbolicByteArray
3417
+ assert type(new_bytes) is SymbolicBytes
3418
+ assert new_bytes.inner is orig_bytes.inner
3419
+
3420
+
3421
+ @pytest.mark.skipif(
3422
+ sys.version_info >= (3, 13),
3423
+ reason="Need to intercept UnicodeDecodeError.str in 3.13+",
3424
+ )
3425
+ @pytest.mark.demo
3426
+ def test_bytes_decode_method():
3427
+ def f(b: bytes) -> str:
3428
+ """
3429
+ Does any 2-byte sequence represent the character "ε" in UTF-8?
3430
+
3431
+ NOTE: The process of decoding involves a lot of branching;
3432
+ most problems will require minutes of processing or more.
3433
+
3434
+ pre: len(b) == 2
3435
+ post: _ != "ε"
3436
+ raises: UnicodeDecodeError
3437
+ """
3438
+ return b.decode("utf8")
3439
+
3440
+ check_states(f, POST_FAIL)
3441
+
3442
+
3443
+ @pytest.mark.demo("red")
3444
+ def test_bytes___str___method():
3445
+ def f(b: bytes):
3446
+ """
3447
+ Is the string form of any byte array equal to b''?
3448
+
3449
+ NOTE: This conversion does not have symbolic support (yet). We are able to find
3450
+ the enpty string, but nearly any other bytes string cannot be found.
3451
+
3452
+ post: _ != "b''"
3453
+ """
3454
+ return str(b)
3455
+
3456
+ check_states(f, POST_FAIL)
3457
+
3458
+
3459
+ @pytest.mark.demo
3460
+ def test_bytearray___add___method():
3461
+ def f(a: bytes, count: int) -> bytearray:
3462
+ """
3463
+ Can some repetitions of a 3-character byte string produce "abcabc"?
3464
+ pre: len(a) == 3
3465
+ post: _ != b"abcabc"
3466
+ """
3467
+ ba = bytearray()
3468
+ for _ in range(count):
3469
+ ba += a
3470
+ return ba
3471
+
3472
+ check_states(f, POST_FAIL)
3473
+
3474
+
3475
+ def test_extend_concrete_bytearray():
3476
+ with standalone_statespace as space:
3477
+ b = bytearray(b"abc")
3478
+ xyz = proxy_for_type(bytearray, "xyz")
3479
+ b.extend(xyz)
3480
+ assert not space.is_possible(b[0] != ord("a"))
3481
+ assert space.is_possible(len(b) > 3)
3482
+
3483
+
3484
+ def test_bytearray_slice():
3485
+ with standalone_statespace as space:
3486
+ xyz = proxy_for_type(bytearray, "xyz")
3487
+ space.add(xyz.__len__() == 3)
3488
+ assert type(xyz[1:]) is bytearray
3489
+
3490
+
3491
+ def test_memoryview_compare():
3492
+ with standalone_statespace as space:
3493
+ mv1 = proxy_for_type(memoryview, "mv1")
3494
+ mv2 = proxy_for_type(memoryview, "mv2")
3495
+ len1, len2 = len(mv1), len(mv2)
3496
+ space.add(len1 == 0)
3497
+ space.add(len2 == 0)
3498
+ views_equal = mv1 == mv2
3499
+ with NoTracing():
3500
+ assert views_equal is True
3501
+
3502
+
3503
+ def test_memoryview_cast():
3504
+ """post: _"""
3505
+ with standalone_statespace as space:
3506
+ val = proxy_for_type(int, "val")
3507
+ space.add(val == 254)
3508
+ mv = memoryview(bytearray([val]))
3509
+ assert mv.cast("b")[0] == -2
3510
+
3511
+
3512
+ def test_memoryview_toreadonly():
3513
+ """post: _"""
3514
+ with standalone_statespace as space:
3515
+ mv = proxy_for_type(memoryview, "mv")
3516
+ space.add(mv.__len__() == 1)
3517
+ mv2 = mv.toreadonly()
3518
+ mv[0] = 12
3519
+ assert mv2[0] == 12
3520
+ with pytest.raises(TypeError):
3521
+ mv2[0] = 24
3522
+
3523
+
3524
+ def test_memoryview_properties():
3525
+ """post: _"""
3526
+ with standalone_statespace as space:
3527
+ symbolic_mv = proxy_for_type(memoryview, "symbolic_mv")
3528
+ space.add(symbolic_mv.__len__() == 1)
3529
+ concrete_mv = memoryview(bytearray(b"a"))
3530
+ assert symbolic_mv.contiguous == concrete_mv.contiguous
3531
+ assert symbolic_mv.c_contiguous == concrete_mv.c_contiguous
3532
+ assert symbolic_mv.f_contiguous == concrete_mv.f_contiguous
3533
+ assert symbolic_mv.readonly == concrete_mv.readonly
3534
+ assert symbolic_mv.format == concrete_mv.format
3535
+ assert symbolic_mv.itemsize == concrete_mv.itemsize
3536
+ assert symbolic_mv.nbytes == concrete_mv.nbytes
3537
+ assert symbolic_mv.ndim == concrete_mv.ndim
3538
+ assert symbolic_mv.shape == concrete_mv.shape
3539
+ assert symbolic_mv.strides == concrete_mv.strides
3540
+ assert symbolic_mv.suboffsets == concrete_mv.suboffsets
3541
+
3542
+
3543
+ def test_chr(space):
3544
+ i = proxy_for_type(int, "i")
3545
+ with ResumedTracing():
3546
+ space.add(10 <= i)
3547
+ space.add(i < 256)
3548
+ c = chr(i)
3549
+ assert space.is_possible(c._codepoints[0] == ord("a"))
3550
+ assert not space.is_possible(c._codepoints[0] == 0)
3551
+
3552
+
3553
+ def test_ord(space):
3554
+ s = proxy_for_type(str, "s")
3555
+ with ResumedTracing():
3556
+ space.add(len(s) == 1)
3557
+ i = ord(s)
3558
+ assert space.is_possible(i == 42)
3559
+ assert not space.is_possible(i > sys.maxunicode)
3560
+
3561
+
3562
+ def test_unicode_support(space):
3563
+ s = proxy_for_type(str, "s")
3564
+ with ResumedTracing():
3565
+ space.add(len(s) == 1)
3566
+ assert space.is_possible(s == "a")
3567
+ assert space.is_possible(s == "\u1234")
3568
+
3569
+
3570
+ @pytest.mark.parametrize("concrete_x", (25, 15, 6, -4, -15, -25))
3571
+ def test_int_round(concrete_x, space):
3572
+ concrete_ret = round(concrete_x, -1)
3573
+ x = proxy_for_type(int, "x")
3574
+ d = proxy_for_type(int, "d")
3575
+ with ResumedTracing():
3576
+ space.add(x == concrete_x)
3577
+ space.add(d == -1)
3578
+ assert not space.is_possible((round(x, d) != concrete_ret))
3579
+
3580
+
3581
+ class ExplodingValue:
3582
+ def __getattribute__(self, name):
3583
+ raise CrossHairInternal
3584
+
3585
+
3586
+ @dataclasses.dataclass
3587
+ class ClassWithSpecialMemberNames:
3588
+ typ: str
3589
+ var: int
3590
+
3591
+
3592
+ def test_class_with_special_member_names():
3593
+ exploding_value = ExplodingValue()
3594
+
3595
+ def f(obj1: ClassWithSpecialMemberNames):
3596
+ """post: True"""
3597
+ assert isinstance(obj1.typ, str)
3598
+ assert isinstance(obj1.var, int)
3599
+ # Ensure run-time creation doesn't explode either:
3600
+ ClassWithSpecialMemberNames(typ=exploding_value, var=exploding_value) # type: ignore
3601
+
3602
+ check_states(f, CONFIRMED)
3603
+
3604
+
3605
+ @pytest.mark.parametrize("type2", (list, set, frozenset, tuple))
3606
+ @pytest.mark.parametrize(
3607
+ "type1",
3608
+ (
3609
+ list,
3610
+ set,
3611
+ frozenset,
3612
+ tuple,
3613
+ array,
3614
+ ),
3615
+ )
3616
+ def test_container_crosstype_equality(space, type1, type2):
3617
+ sym_obj1 = proxy_for_type(type1, "obj1")
3618
+ obj2 = type2()
3619
+ with ResumedTracing():
3620
+ space.add(len(sym_obj1) == 0)
3621
+ obj1 = deep_realize(sym_obj1)
3622
+ sym_eq_on_left = realize(sym_obj1 == obj2)
3623
+ sym_eq_on_right = realize(obj2 == sym_obj1)
3624
+ actually_equal = obj1 == obj2
3625
+ assert actually_equal == sym_eq_on_left
3626
+ assert actually_equal == sym_eq_on_right
3627
+
3628
+
3629
+ @pytest.mark.parametrize("type2", (str, bytes, tuple))
3630
+ @pytest.mark.parametrize("type1", (str, bytes, tuple, memoryview))
3631
+ def test_stringlike_crosstype_equality(space, type1, type2):
3632
+ sym_obj1 = proxy_for_type(type1, "obj1")
3633
+ obj2 = type2()
3634
+ with ResumedTracing():
3635
+ space.add(len(sym_obj1) == 0)
3636
+ obj1 = deep_realize(sym_obj1)
3637
+ sym_eq_on_left = realize(sym_obj1 == obj2)
3638
+ sym_eq_on_right = realize(obj2 == sym_obj1)
3639
+ actually_equal = obj1 == obj2
3640
+ assert actually_equal == sym_eq_on_left
3641
+ assert actually_equal == sym_eq_on_right
3642
+
3643
+
3644
+ @pytest.mark.parametrize("typ", (List[int],))
3645
+ def test_deep_realization(space, typ):
3646
+ symbolic = proxy_for_type(typ, "symbolic")
3647
+ with ResumedTracing():
3648
+ space.add(len(symbolic) == 3)
3649
+ origin = origin_of(typ)
3650
+ assert type(symbolic) != origin
3651
+ concrete = deep_realize(symbolic)
3652
+ assert type(concrete) == origin
3653
+ with ResumedTracing():
3654
+ assert concrete == symbolic
3655
+
3656
+
3657
+ def test_float_round_to_zero(space):
3658
+ space.extra(ModelingDirector).global_representations[
3659
+ float
3660
+ ] = PreciseIeeeSymbolicFloat
3661
+ n = proxy_for_type(float, "n")
3662
+ d = proxy_for_type(float, "d")
3663
+ with ResumedTracing():
3664
+ space.add(d != 0.0)
3665
+ # This is possible for floats, but not reals:
3666
+ assert space.is_possible(n / d != 0.0)
3667
+ assert space.is_possible(n / d == 0.0)
3668
+
3669
+
3670
+ def test_float_neg_zero_is_falsey(space):
3671
+ space.extra(ModelingDirector).global_representations[
3672
+ float
3673
+ ] = PreciseIeeeSymbolicFloat
3674
+ x = proxy_for_type(float, "x")
3675
+ with ResumedTracing():
3676
+ space.add(x == -10.0)
3677
+ negzero = x / math.inf
3678
+ assert not space.is_possible(negzero != 0.0)
3679
+ assert bool(negzero) is False
3680
+
3681
+
3682
+ def TODO_test_int_mod_float():
3683
+ # (errors at the Z3 level presently)
3684
+ with standalone_statespace as space:
3685
+ x = proxy_for_type(int, "x")
3686
+ y = proxy_for_type(float, "y")
3687
+ modval = x % y
3688
+ with NoTracing():
3689
+ assert type(modval) == RealBasedSymbolicFloat
3690
+ assert space.is_possible(modval == 12.12)
3691
+
3692
+
3693
+ def TODO_test_can_generate_integral():
3694
+ with standalone_statespace as space:
3695
+ proxy_for_type(Integral, "x")
3696
+
3697
+
3698
+ def TODO_test_deepcopy_independence():
3699
+ # (snapshotting should take care of this for us(?), but it doesn't seem to)
3700
+ with standalone_statespace as space:
3701
+ ls = proxy_for_type(List[List[int]], "ls")
3702
+ lscopy = copy.deepcopy(ls)
3703
+ with NoTracing():
3704
+ assert ls[0] is not lscopy[0]
3705
+ # Next try mutation on one and test the other...