1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
# This file is part of Hypothesis, which may be found at
# https://github.com/HypothesisWorks/hypothesis/
#
# Copyright the Hypothesis Authors.
# Individual contributors are listed in AUTHORS.rst and the git log.
#
# This Source Code Form is subject to the terms of the Mozilla Public License,
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at https://mozilla.org/MPL/2.0/.
from random import Random
from hypothesis import (
HealthCheck,
Phase,
Verbosity,
assume,
example,
given,
reject,
settings,
strategies as st,
)
from hypothesis.internal.conjecture.data import ConjectureData, Status, StopTest
from hypothesis.internal.conjecture.engine import ConjectureRunner
from hypothesis.internal.conjecture.utils import INT_SIZES
@st.composite
def problems(draw):
while True:
buf = bytearray(draw(st.binary(min_size=16, max_size=16)))
while buf and not buf[-1]:
buf.pop()
try:
d = ConjectureData.for_buffer(buf)
k = d.draw(st.integers())
stop = d.draw_bits(8)
except (StopTest, IndexError):
pass
else:
if stop > 0 and k > 0:
return (draw(st.integers(0, k - 1)), bytes(d.buffer))
@example((2, b"\x00\x00\n\x01"))
@example((1, b"\x00\x00\x06\x01"))
@example(problem=(32768, b"\x03\x01\x00\x00\x00\x00\x00\x01\x00\x02\x01"))
@settings(
suppress_health_check=HealthCheck.all(),
deadline=None,
max_examples=10,
verbosity=Verbosity.normal,
)
@given(problems())
def test_always_reduces_integers_to_smallest_suitable_sizes(problem):
n, blob = problem
try:
d = ConjectureData.for_buffer(blob)
k = d.draw(st.integers())
stop = blob[len(d.buffer)]
except (StopTest, IndexError):
reject()
assume(k > n)
assume(stop > 0)
def f(data):
k = data.draw(st.integers())
data.output = repr(k)
if data.draw_bits(8) == stop and k >= n:
data.mark_interesting()
runner = ConjectureRunner(
f,
random=Random(0),
settings=settings(
suppress_health_check=HealthCheck.all(),
phases=(Phase.shrink,),
database=None,
verbosity=Verbosity.debug,
),
database_key=None,
)
runner.cached_test_function(blob)
assert runner.interesting_examples
(v,) = runner.interesting_examples.values()
shrinker = runner.new_shrinker(v, lambda x: x.status == Status.INTERESTING)
shrinker.fixate_shrink_passes(["minimize_individual_blocks"])
v = shrinker.shrink_target
m = ConjectureData.for_buffer(v.buffer).draw(st.integers())
assert m == n
# Upper bound on the length needed is calculated as follows:
# * We have an initial byte at the beginning to decide the length of the
# integer.
# * We have a terminal byte as the stop value.
# * The rest is the integer payload. This should be n. Including the sign
# bit, n needs (1 + n.bit_length()) / 8 bytes (rounded up). But we only
# have power of two sizes, so it may be up to a factor of two more than
# that.
bits_needed = 1 + n.bit_length()
actual_bits_needed = min(s for s in INT_SIZES if s >= bits_needed)
bytes_needed = actual_bits_needed // 8
# 3 extra bytes: two for the sampler, one for the capping value.
assert len(v.buffer) == 3 + bytes_needed
def test_generates_boundary_values_even_when_unlikely():
r = Random()
trillion = 10**12
strat = st.integers(-trillion, trillion)
boundary_vals = {-trillion, -trillion + 1, trillion - 1, trillion}
for _ in range(10_000):
buffer = bytes(r.randrange(0, 255) for _ in range(1000))
val = ConjectureData.for_buffer(buffer).draw(strat)
boundary_vals.discard(val)
if not boundary_vals:
break
else:
raise AssertionError(
f"Expected to see all boundary vals, but still have {boundary_vals}"
)
|