Skip to content

Commit

Permalink
Merge pull request #3854 from tybug/more-test-changes
Browse files Browse the repository at this point in the history
More small IR-related improvements
  • Loading branch information
Zac-HD committed Jan 23, 2024
2 parents 1119e7d + 16c0de8 commit 38eafc7
Show file tree
Hide file tree
Showing 10 changed files with 84 additions and 64 deletions.
3 changes: 3 additions & 0 deletions hypothesis-python/RELEASE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
RELEASE_TYPE: patch

This patch slightly refactors some internals. There is no user-visible change.
26 changes: 8 additions & 18 deletions hypothesis-python/src/hypothesis/internal/conjecture/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -1093,12 +1093,12 @@ def draw_float(
if clamped != result and not (math.isnan(result) and allow_nan):
self._cd.stop_example(discard=True)
self._cd.start_example(DRAW_FLOAT_LABEL)
self._write_float(clamped)
self._draw_float(forced=clamped)
result = clamped
else:
result = nasty_floats[i - 1]

self._write_float(result)
self._draw_float(forced=result)

self._cd.stop_example() # (DRAW_FLOAT_LABEL)
self._cd.stop_example() # (FLOAT_STRATEGY_DO_DRAW_LABEL)
Expand Down Expand Up @@ -1170,23 +1170,13 @@ def _draw_float(
# sign_aware_lte(forced, -0.0) does not correctly handle the
# math.nan case here.
forced_sign_bit = math.copysign(1, forced) == -1

self._cd.start_example(DRAW_FLOAT_LABEL)
try:
is_negative = self._cd.draw_bits(1, forced=forced_sign_bit)
f = lex_to_float(
self._cd.draw_bits(
64, forced=None if forced is None else float_to_lex(abs(forced))
)
is_negative = self._cd.draw_bits(1, forced=forced_sign_bit)
f = lex_to_float(
self._cd.draw_bits(
64, forced=None if forced is None else float_to_lex(abs(forced))
)
return -f if is_negative else f
finally:
self._cd.stop_example()

def _write_float(self, f: float) -> None:
sign = float_to_int(f) >> 63
self._cd.draw_bits(1, forced=sign)
self._cd.draw_bits(64, forced=float_to_lex(abs(f)))
)
return -f if is_negative else f

def _draw_unbounded_integer(self, *, forced: Optional[int] = None) -> int:
forced_i = None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def exponent_key(e: int) -> float:


def decode_exponent(e: int) -> int:
"""Take draw_bits(11) and turn it into a suitable floating point exponent
"""Take an integer and turn it into a suitable floating point exponent
such that lexicographically simpler leads to simpler floats."""
assert 0 <= e <= MAX_EXPONENT
return ENCODING_TABLE[e]
Expand Down
3 changes: 3 additions & 0 deletions hypothesis-python/src/hypothesis/internal/intervalsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ def __sub__(self, other):
def __and__(self, other):
return self.intersection(other)

def __eq__(self, other):
return isinstance(other, IntervalSet) and (other.intervals == self.intervals)

def union(self, other):
"""Merge two sequences of intervals into a single tuple of intervals.
Expand Down
4 changes: 2 additions & 2 deletions hypothesis-python/tests/conjecture/test_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,8 +442,8 @@ def test_can_shrink_variable_draws(n_large):

@run_to_data
def data(data):
n = data.draw_bits(4)
b = [data.draw_bits(8) for _ in range(n)]
n = data.draw_integer(0, 15)
b = [data.draw_integer(0, 255) for _ in range(n)]
if sum(b) >= target:
data.mark_interesting()

Expand Down
20 changes: 11 additions & 9 deletions hypothesis-python/tests/conjecture/test_float_encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
import pytest

from hypothesis import HealthCheck, assume, example, given, settings, strategies as st
from hypothesis.internal.compat import ceil, floor, int_from_bytes, int_to_bytes
from hypothesis.internal.compat import ceil, floor, int_to_bytes
from hypothesis.internal.conjecture import floats as flt
from hypothesis.internal.conjecture.data import ConjectureData, PrimitiveProvider
from hypothesis.internal.conjecture.data import ConjectureData
from hypothesis.internal.conjecture.engine import ConjectureRunner
from hypothesis.internal.floats import float_to_int

from tests.conjecture.common import run_to_buffer

EXPONENTS = list(range(flt.MAX_EXPONENT + 1))
assert len(EXPONENTS) == 2**11

Expand Down Expand Up @@ -130,17 +132,18 @@ def test_reverse_bits_table_has_right_elements():


def float_runner(start, condition):
def parse_buf(b):
return flt.lex_to_float(int_from_bytes(b))
@run_to_buffer
def buf(data):
data.draw_float(forced=start)
data.mark_interesting()

def test_function(data):
pp = PrimitiveProvider(data)
f = pp._draw_float()
f = data.draw_float()
if condition(f):
data.mark_interesting()

runner = ConjectureRunner(test_function)
runner.cached_test_function(bytes(1) + int_to_bytes(flt.float_to_lex(start), 8))
runner.cached_test_function(buf)
assert runner.interesting_examples
return runner

Expand All @@ -150,8 +153,7 @@ def minimal_from(start, condition):
runner.shrink_interesting_examples()
(v,) = runner.interesting_examples.values()
data = ConjectureData.for_buffer(v.buffer)
pp = PrimitiveProvider(data)
result = pp._draw_float()
result = data.draw_float()
assert condition(result)
return result

Expand Down
15 changes: 15 additions & 0 deletions hypothesis-python/tests/cover/test_intervalset.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,18 @@ def test_char_in_shrink_order():
rewritten = [ord(xs.char_in_shrink_order(i)) for i in range(256)]
assert rewritten != list(range(256))
assert sorted(rewritten) == sorted(range(256))


def test_index_from_char_in_shrink_order():
xs = IntervalSet([(0, 256)])
for i in xs:
assert xs.index_from_char_in_shrink_order(xs.char_in_shrink_order(i)) == i


def test_intervalset_equal():
xs1 = IntervalSet([(0, 256)])
xs2 = IntervalSet([(0, 256)])
assert xs1 == xs2

xs3 = IntervalSet([(0, 255)])
assert xs2 != xs3
9 changes: 7 additions & 2 deletions hypothesis-python/tests/nocover/test_conjecture_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,20 @@ def test_regression_1():
# specific exception inside one of the shrink passes. It's unclear how
# useful this regression test really is, but nothing else caught the
# problem.
#
# update 2024-01-15: we've since changed generation and are about to
# change shrinking, so it's unclear if the failure case this test was aimed
# at (1) is still being covered or (2) even exists anymore.
# we can probably safely remove this once the shrinker is rebuilt.
@run_to_buffer
def x(data):
data.draw_bytes(2, forced=b"\x01\x02")
data.draw_bytes(2, forced=b"\x01\x00")
v = data.draw_bits(41)
v = data.draw_integer(0, 2**41 - 1)
if v >= 512 or v == 254:
data.mark_interesting()

assert list(x)[:-2] == [1, 2, 1, 0, 0, 0, 0, 0]
assert list(x)[:-2] == [1, 2, 1, 0, 0, 0, 0, 0, 0]

assert int_from_bytes(x[-2:]) in (254, 512)

Expand Down
6 changes: 3 additions & 3 deletions hypothesis-python/tests/quality/test_poisoned_trees.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ def do_draw(self, data):
# single block. If it did, the heuristics that allow us to move
# blocks around would fire and it would move right, which would
# then allow us to shrink it more easily.
n = (data.draw_integer(0, 2**16 - 1) << 16) | data.draw_integer(
0, 2**16 - 1
)
n1 = data.draw_integer(0, 2**16 - 1) << 16
n2 = data.draw_integer(0, 2**16 - 1)
n = n1 | n2
if n == MAX_INT:
return (POISON,)
else:
Expand Down
60 changes: 31 additions & 29 deletions hypothesis-python/tests/quality/test_zig_zagging.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,20 @@
settings,
strategies as st,
)
from hypothesis.internal.compat import ceil, int_from_bytes
from hypothesis.internal.compat import ceil
from hypothesis.internal.conjecture.data import ConjectureData
from hypothesis.internal.conjecture.engine import ConjectureRunner

from tests.conjecture.common import run_to_buffer


@st.composite
def problem(draw):
b = draw(st.binary(min_size=1, max_size=8))
m = int_from_bytes(b) * 256
def problems(draw):
m = draw(st.integers(256, 2**64 - 1))
assume(m > 0)
marker = draw(st.binary(max_size=8))
bound = draw(st.integers(0, m - 1))
return (b, marker, bound)
return (m, marker, bound)


base_settings = settings(
Expand All @@ -46,17 +47,17 @@ def problem(draw):
)


@example((b"\x10\x00\x00\x00\x00\x00", b"", 2861143707951135))
@example((b"\x05Cn", b"%\x1b\xa0\xfa", 12394667))
@example((b"\x179 f", b"\xf5|", 24300326997))
@example((b"\x05*\xf5\xe5\nh", b"", 1076887621690235))
@example((b"=", b"", 2508))
@example((b"\x01\x00", b"", 20048))
@example((b"\x01", b"", 0))
@example((b"\x02", b"", 258))
@example((b"\x08", b"", 1792))
@example((b"\x0c", b"", 0))
@example((b"\x01", b"", 1))
@example((4503599627370496, b"", 2861143707951135))
@example((88305152, b"%\x1b\xa0\xfa", 12394667))
@example((99742672384, b"\xf5|", 24300326997))
@example((1454610481571840, b"", 1076887621690235))
@example((15616, b"", 2508))
@example((65536, b"", 20048))
@example((256, b"", 0))
@example((512, b"", 258))
@example((2048, b"", 1792))
@example((3072, b"", 0))
@example((256, b"", 1))
@settings(
base_settings,
verbosity=Verbosity.normal,
Expand All @@ -68,17 +69,23 @@ def problem(draw):
),
max_examples=20,
)
@given(problem())
@given(problems())
def test_avoids_zig_zag_trap(p):
b, marker, lower_bound = p
m, marker, lower_bound = p
n_bits = m.bit_length() + 1

n_bits = 8 * (len(b) + 1)
@run_to_buffer
def buf(data):
_m = data.draw_integer(0, 2**n_bits - 1, forced=m)
_n = data.draw_integer(0, 2**n_bits - 1, forced=m + 1)
_marker = data.draw_bytes(len(marker), forced=marker)
data.mark_interesting()

def test_function(data):
m = data.draw_bits(n_bits)
m = data.draw_integer(0, 2**n_bits - 1)
if m < lower_bound:
data.mark_invalid()
n = data.draw_bits(n_bits)
n = data.draw_integer(0, 2**n_bits - 1)
if data.draw_bytes(len(marker)) != marker:
data.mark_invalid()
if abs(m - n) == 1:
Expand All @@ -91,24 +98,19 @@ def test_function(data):
random=Random(0),
)

runner.cached_test_function(b + bytes([0]) + b + bytes([1]) + marker)

runner.cached_test_function(buf)
assert runner.interesting_examples

runner.run()

(v,) = runner.interesting_examples.values()

data = ConjectureData.for_buffer(v.buffer)

m = data.draw_bits(n_bits)
n = data.draw_bits(n_bits)
m = data.draw_integer(0, 2**n_bits - 1)
n = data.draw_integer(0, 2**n_bits - 1)
assert m == lower_bound
if m == 0:
assert n == 1
else:
assert n == m - 1

budget = 2 * n_bits * ceil(log(n_bits, 2)) + 2

assert runner.shrinks <= budget

0 comments on commit 38eafc7

Please sign in to comment.