Exemplo n.º 1
0
 def byte_distribution(random, n):
     assert n == nbytes
     v = distribution(random)
     if v >= center:
         probe = v - center
     else:
         probe = upper - v
     return int_to_bytes(probe, n)
def minimal_from(start, condition):
    buf = int_to_bytes(flt.float_to_lex(start), 8)

    def parse_buf(b):
        return flt.lex_to_float(int_from_bytes(b))

    shrunk = minimize(
        buf, lambda b: condition(parse_buf(b)),
        full=True, random=Random(0)
    )
    return parse_buf(shrunk)
Exemplo n.º 3
0
 def distribution(random, n):
     assert n == n_bytes
     for _ in range(100):
         try:
             return int_to_bytes(int(
                 math.log1p(-random.random()) / denom), n)
         # This is basically impossible to hit but is required for
         # correctness
         except OverflowError:  # pragma: no cover
             pass
     # We got a one in a million chance 100 times in a row. Something is up.
     assert False  # pragma: no cover
def test_converts_floats_to_integer_form(f):
    assert flt.is_simple(f)

    buf = int_to_bytes(flt.base_float_to_lex(f), 8)

    def parse_buf(b):
        return flt.lex_to_float(int_from_bytes(b))

    shrunk = Lexical.shrink(
        buf, lambda b: parse_buf(b) == f,
        full=True, random=Random(0)
    )
    assert shrunk < buf
Exemplo n.º 5
0
 def distribution(random, n):
     assert n == size
     if random.randint(0, 2) > 0:
         k = 1
     elif random.randint(0, 2) > 0:
         k = 2
     else:
         k = random.randint(1, size)
     r = random.getrandbits(k * 8)
     if random.randint(0, 1):
         r |= sign_mask
     else:
         r &= ~sign_mask
     return int_to_bytes(r, n)
def test_float_shrink_can_run_when_canonicalisation_does_not_work(monkeypatch):
    # This should be an error when called
    monkeypatch.setattr(Float, "shrink", None)

    base_buf = int_to_bytes(flt.base_float_to_lex(1000.0), 8) + hbytes(1)

    @shrinking_from(base_buf)
    def shrinker(data):
        flt.draw_float(data)
        if hbytes(data.buffer) == base_buf:
            data.mark_interesting()

    shrinker.minimize_floats()

    assert shrinker.shrink_target.buffer == base_buf
Exemplo n.º 7
0
 def distribution(random, n):
     assert n == size
     k = min(
         random.randint(0, n * 8 - 1),
         random.randint(0, n * 8 - 1),
     )
     if k > 0:
         r = random.getrandbits(k)
     else:
         r = 0
     if random.randint(0, 1):
         r |= sign_mask
     else:
         r &= (~sign_mask)
     return int_to_bytes(r, n)
Exemplo n.º 8
0
    def draw_bits(self, n, forced=None):
        """Return an ``n``-bit integer from the underlying source of
        bytes. If ``forced`` is set to an integer will instead
        ignore the underlying source and simulate a draw as if it had
        returned that integer."""
        self.__assert_not_frozen("draw_bits")
        if n == 0:
            return 0
        assert n > 0
        n_bytes = bits_to_bytes(n)
        self.__check_capacity(n_bytes)

        if forced is not None:
            buf = int_to_bytes(forced, n_bytes)
        elif self.__bytes_drawn < len(self.__prefix):
            index = self.__bytes_drawn
            buf = self.__prefix[index:index + n_bytes]
            if len(buf) < n_bytes:
                buf += uniform(self.__random, n_bytes - len(buf))
        else:
            buf = uniform(self.__random, n_bytes)
        buf = bytearray(buf)
        self.__bytes_drawn += n_bytes

        assert len(buf) == n_bytes

        # If we have a number of bits that is not a multiple of 8
        # we have to mask off the high bits.
        buf[0] &= BYTE_MASKS[n % 8]
        buf = bytes(buf)
        result = int_from_bytes(buf)

        self.observer.draw_bits(n, forced is not None, result)
        self.__example_record.draw_bits(n, forced)

        initial = self.index

        self.buffer.extend(buf)
        self.index = len(self.buffer)

        if forced is not None:
            self.forced_indices.update(range(initial, self.index))

        self.blocks.add_endpoint(self.index)

        assert bit_length(result) <= n
        return result
Exemplo n.º 9
0
            def attempt_replace(v):
                """Try replacing the current block in the current best test case
                 with an integer of value i. Note that we use the *current*
                best and not the one we started with. This helps ensure that
                if we luck into a good draw when making random choices we get
                to keep the good bits."""
                if v < 0 or v > max_int_value:
                    return False
                v_as_bytes = int_to_bytes(v, len(existing))

                # We make a couple attempts at replacement. This only matters
                # if we end up growing the buffer - otherwise we exit the loop
                # early - but in the event that there *is* some randomized
                # component we want to give it a couple of tries to succeed.
                for _ in range(3):
                    attempt = self.engine.cached_test_function(
                        prefix + v_as_bytes +
                        self.current_data.buffer[block.end:],
                        extend=BUFFER_SIZE,
                    )

                    if self.consider_new_test_data(attempt):
                        return True

                    if attempt.status < Status.INVALID or len(
                            attempt.buffer) == len(self.current_data.buffer):
                        return False

                    for i, ex in enumerate(self.current_data.examples):
                        if ex.start >= block.end:
                            break
                        if ex.end <= block.start:
                            continue
                        ex_attempt = attempt.examples[i]
                        if ex.length == ex_attempt.length:
                            continue
                        replacement = attempt.buffer[ex_attempt.
                                                     start:ex_attempt.end]
                        if self.consider_new_test_data(
                                self.engine.cached_test_function(
                                    prefix + replacement +
                                    self.current_data.buffer[ex.end:])):
                            return True
                return False
Exemplo n.º 10
0
    def float_hack(self):
        """Our encoding of floating point numbers does the right thing when you
        lexically shrink it, but there are some highly non-obvious lexical
        shrinks corresponding to natural floating point operations.

        We can't actually tell when the floating point encoding is being used
        (that would break the assumptions that Hypothesis doesn't inspect
        the generated values), but we can cheat: We just guess when it might be
        being used and perform shrinks that are valid regardless of our guess
        is correct.

        So that's what this method does. It's a cheat to give us good shrinking
        of floating at low cost in runtime and only moderate cost in elegance.
        """
        # If the block is of the wrong size then we're certainly not using the
        # float encoding.
        if self.size != 8:
            return

        # If the high bit is zero then we're in the integer representation of
        # floats so we don't need these hacks because it will shrink normally.
        if self.current[0] >> 7 == 0:
            return

        i = self.current_int
        f = lex_to_float(i)

        # This floating point number can be represented in our simple format.
        # So we try converting it to that (which will give the same float, but
        # a different encoding of it). If that doesn't work then the float
        # value of this doesn't unambiguously give the desired predicate, so
        # this approach isn't useful. If it *does* work, then we're now in a
        # situation where we don't need it, so either way we return here.
        if is_simple(f):
            self.incorporate_float(f)
            return

        self.delegate(
            Float,
            convert_to=lambda b: lex_to_float(int_from_bytes(b)),
            convert_from=lambda f: int_to_bytes(float_to_lex(f), self.size),
        )
Exemplo n.º 11
0
    def float_hack(self):
        """Our encoding of floating point numbers does the right thing when you
        lexically shrink it, but there are some highly non-obvious lexical
        shrinks corresponding to natural floating point operations.

        We can't actually tell when the floating point encoding is being used
        (that would break the assumptions that Hypothesis doesn't inspect
        the generated values), but we can cheat: We just guess when it might be
        being used and perform shrinks that are valid regardless of our guess
        is correct.

        So that's what this method does. It's a cheat to give us good shrinking
        of floating at low cost in runtime and only moderate cost in elegance.
        """
        # If the block is of the wrong size then we're certainly not using the
        # float encoding.
        if self.size != 8:
            return

        # If the high bit is zero then we're in the integer representation of
        # floats so we don't need these hacks because it will shrink normally.
        if self.current[0] >> 7 == 0:
            return

        i = self.current_int
        f = lex_to_float(i)

        # This floating point number can be represented in our simple format.
        # So we try converting it to that (which will give the same float, but
        # a different encoding of it). If that doesn't work then the float
        # value of this doesn't unambiguously give the desired predicate, so
        # this approach isn't useful. If it *does* work, then we're now in a
        # situation where we don't need it, so either way we return here.
        if is_simple(f):
            self.incorporate_float(f)
            return

        self.delegate(
            Float,
            convert_to=lambda b: lex_to_float(int_from_bytes(b)),
            convert_from=lambda f: int_to_bytes(float_to_lex(f), self.size),
        )
Exemplo n.º 12
0
    def draw_bits(self, n, forced=None):
        """Return an ``n``-bit integer from the underlying source of
        bytes. If ``forced`` is set to an integer will instead
        ignore the underlying source and simulate a draw as if it had
        returned that integer."""
        self.__assert_not_frozen("draw_bits")
        if n == 0:
            return 0
        assert n > 0
        n_bytes = bits_to_bytes(n)
        self.__check_capacity(n_bytes)

        if forced is not None:
            buf = bytearray(int_to_bytes(forced, n_bytes))
        else:
            buf = bytearray(self._draw_bytes(self, n_bytes))
        assert len(buf) == n_bytes

        # If we have a number of bits that is not a multiple of 8
        # we have to mask off the high bits.
        buf[0] &= BYTE_MASKS[n % 8]
        buf = hbytes(buf)
        result = int_from_bytes(buf)

        self.observer.draw_bits(n, forced is not None, result)

        self.start_example(DRAW_BYTES_LABEL)
        initial = self.index

        self.buffer.extend(buf)
        self.index = len(self.buffer)

        if forced is not None:
            self.forced_indices.update(hrange(initial, self.index))

        self.blocks.add_endpoint(self.index)

        self.stop_example()

        assert bit_length(result) <= n
        return result
Exemplo n.º 13
0
 def do_draw(self, data):
     # This strategy is slightly strange in its implementation.
     # We don't want the interpretation of the rule we draw to change based
     # on whether other rules satisfy their preconditions or have data in
     # their bundles. Therefore the index into the rule list needs to stay
     # stable. BUT we don't want to draw invalid rules. So what we do is we
     # draw an index. We *could* just loop until it's valid, but if most
     # rules are invalid then that could result in a very long loop.
     # So what we do is the following:
     #
     #   1. We first draw a rule unconditionally, and check if it's valid.
     #      If it is, great. Nothing more to do, that's our rule.
     #   2. If it is invalid, we now calculate the list of valid rules and
     #      draw from that list (if there are none, that's an error in the
     #      definition of the machine and we complain to the user about it).
     #   3. Once we've drawn a valid rule, we write that back to the byte
     #      stream. As a result, when shrinking runs the shrinker can delete
     #      the initial failed draw + the draw that lead to us finding an
     #      index into valid_rules, leaving just the written value of i.
     #      When this is run, it will look as we got lucky and just happened
     #      to pick a valid rule.
     #
     # Easy, right?
     n = len(self.rules)
     i = cu.integer_range(data, 0, n - 1)
     u, v = data.blocks[-1].bounds
     block_length = v - u
     rule = self.rules[i]
     if not self.is_valid(rule):
         valid_rules = [
             j for j, r in enumerate(self.rules) if self.is_valid(r)
         ]
         if not valid_rules:
             raise InvalidDefinition(
                 u'No progress can be made from state %r' % (self.machine,)
             )
         i = valid_rules[cu.integer_range(data, 0, len(valid_rules) - 1)]
         data.write(int_to_bytes(i, block_length))
         rule = self.rules[i]
     return (rule, data.draw(rule.arguments_strategy))
Exemplo n.º 14
0
 def do_draw(self, data):
     # This strategy is slightly strange in its implementation.
     # We don't want the interpretation of the rule we draw to change based
     # on whether other rules satisfy their preconditions or have data in
     # their bundles. Therefore the index into the rule list needs to stay
     # stable. BUT we don't want to draw invalid rules. So what we do is we
     # draw an index. We *could* just loop until it's valid, but if most
     # rules are invalid then that could result in a very long loop.
     # So what we do is the following:
     #
     #   1. We first draw a rule unconditionally, and check if it's valid.
     #      If it is, great. Nothing more to do, that's our rule.
     #   2. If it is invalid, we now calculate the list of valid rules and
     #      draw from that list (if there are none, that's an error in the
     #      definition of the machine and we complain to the user about it).
     #   3. Once we've drawn a valid rule, we write that back to the byte
     #      stream. As a result, when shrinking runs the shrinker can delete
     #      the initial failed draw + the draw that lead to us finding an
     #      index into valid_rules, leaving just the written value of i.
     #      When this is run, it will look as we got lucky and just happened
     #      to pick a valid rule.
     #
     # Easy, right?
     n = len(self.rules)
     i = cu.integer_range(data, 0, n - 1)
     u, v = data.blocks[-1]
     block_length = v - u
     rule = self.rules[i]
     if not self.is_valid(rule):
         valid_rules = [
             j for j, r in enumerate(self.rules) if self.is_valid(r)
         ]
         if not valid_rules:
             raise InvalidDefinition(
                 u'No progress can be made from state %r' %
                 (self.machine, ))
         i = valid_rules[cu.integer_range(data, 0, len(valid_rules) - 1)]
         data.write(int_to_bytes(i, block_length))
         rule = self.rules[i]
     return (rule, data.draw(rule.arguments_strategy))
Exemplo n.º 15
0
    def draw_bits(self, n, forced=None):
        """Return an ``n``-bit integer from the underlying source of
        bytes. If ``forced`` is set to an integer will instead
        ignore the underlying source and simulate a draw as if it had
        returned that integer."""
        self.__assert_not_frozen("draw_bits")
        if n == 0:
            return 0
        assert n > 0
        n_bytes = bits_to_bytes(n)
        self.__check_capacity(n_bytes)

        if forced is not None:
            buf = bytearray(int_to_bytes(forced, n_bytes))
        else:
            buf = bytearray(self._draw_bytes(self, n_bytes))
        assert len(buf) == n_bytes

        # If we have a number of bits that is not a multiple of 8
        # we have to mask off the high bits.
        buf[0] &= BYTE_MASKS[n % 8]
        buf = hbytes(buf)
        result = int_from_bytes(buf)

        self.observer.draw_bits(n, forced is not None, result)
        self.__example_record.draw_bits(n, forced)

        initial = self.index

        self.buffer.extend(buf)
        self.index = len(self.buffer)

        if forced is not None:
            self.forced_indices.update(hrange(initial, self.index))

        self.blocks.add_endpoint(self.index)

        assert bit_length(result) <= n
        return result
Exemplo n.º 16
0
def test_can_find_endpoints_of_a_range(lower, upper, score_up):
    with deterministic_PRNG():

        def test(data):
            n = data.draw_bits(16)
            if n < lower or n > upper:
                data.mark_invalid()
            if not score_up:
                n = -n
            data.target_observations["n"] = n

        runner = ConjectureRunner(
            test, settings=settings(TEST_SETTINGS, max_examples=1000)
        )
        runner.cached_test_function(int_to_bytes((lower + upper) // 2, 2))

        try:
            runner.optimise_targets()
        except RunIsComplete:
            pass
        if score_up:
            assert runner.best_observed_targets["n"] == upper
        else:
            assert runner.best_observed_targets["n"] == -lower
def test_gives_the_correct_probabilities():
    weights = [Fraction(1), Fraction(9)]
    total = sum(weights)
    probabilities = [w / total for w in weights]

    sampler = cu.Sampler(probabilities)

    assert cu.Sampler(weights).table == sampler.table

    counts = [0] * len(weights)

    i = 0
    while i < 2 ** 16:
        data = ConjectureData.for_buffer(int_to_bytes(i, 2))
        try:
            c = sampler.sample(data)
            counts[c] += 1
            assert probabilities[c] >= Fraction(counts[c], 2 ** 16)
        except StopTest:
            pass
        if 1 in data.forced_indices:
            i += 256
        else:
            i += 1
Exemplo n.º 18
0
def test_gives_the_correct_probabilities():
    weights = [Fraction(1), Fraction(9)]
    total = sum(weights)
    probabilities = [w / total for w in weights]

    sampler = cu.Sampler(probabilities)

    assert cu.Sampler(weights).table == sampler.table

    counts = [0] * len(weights)

    i = 0
    while i < 2**16:
        data = ConjectureData.for_buffer(int_to_bytes(i, 2))
        try:
            c = sampler.sample(data)
            counts[c] += 1
            assert probabilities[c] >= Fraction(counts[c], 2**16)
        except StopTest:
            pass
        if 1 in data.forced_indices:
            i += 256
        else:
            i += 1
Exemplo n.º 19
0
def uniform(random, n):
    return int_to_bytes(random.getrandbits(n * 8), n)
Exemplo n.º 20
0
 def draw_bytes(self, n):
     """Draw n bytes from the underlying source."""
     return int_to_bytes(self.draw_bits(8 * n), n)
 def draw_value(self, random):
     return int_to_bytes(
         random.getrandbits(self.block_size * 8), self.block_size)
Exemplo n.º 22
0
 def append_int(n_bits, value):
     necessary_prefix.extend(int_to_bytes(value, bits_to_bytes(n_bits)))
Exemplo n.º 23
0
 def incorporate_int(self, i):
     return self.incorporate(int_to_bytes(i, self.size))
Exemplo n.º 24
0
def test_to_bytes_in_big_endian_order(x, y):
    x, y = sorted((x, y))
    assert int_to_bytes(x, 8) <= int_to_bytes(y, 8)
Exemplo n.º 25
0
def test_convert_back(bs):
    bs = bytearray(bs)
    assert int_to_bytes(int_from_bytes(bs), len(bs)) == bs
 def draw_value(self, random):
     return int_to_bytes(random.getrandbits(self.block_size * 8),
                         self.block_size)
Exemplo n.º 27
0
 def incorporate_int(self, i):
     return self.incorporate(int_to_bytes(i, self.size))
Exemplo n.º 28
0
 def draw_bytes(self, n):
     """Draw n bytes from the underlying source."""
     return int_to_bytes(self.draw_bits(8 * n), n)
def test_to_bytes_in_big_endian_order(x, y):
    x, y = sorted((x, y))
    assert int_to_bytes(x, 8) <= int_to_bytes(y, 8)
def test_convert_back(bs):
    bs = bytearray(bs)
    assert int_to_bytes(int_from_bytes(bs), len(bs)) == bs
Exemplo n.º 31
0
    def attempt_to_improve(self, example_index, upwards):
        """Part of our hill climbing implementation. Attempts to improve a
        given score by regenerating an example."""

        data = self.current_data
        self.current_score

        ex = data.examples[example_index]
        assert ex.length > 0
        prefix = data.buffer[:ex.start]
        suffix = data.buffer[ex.end:]

        existing = data.buffer[ex.start:ex.end]

        existing_as_int = int_from_bytes(existing)
        max_int_value = (256**len(existing)) - 1

        if existing_as_int == max_int_value and upwards:
            return False

        if existing_as_int == 0 and not upwards:
            return False

        # We make a mix of small and large jumps. Neither are guaranteeed to
        # work, but each will work in circumstances the other might not. Small
        # jumps are especially important for the last steps towards a local
        # maximum - often large jumps will break some important property of the
        # test case while small, more careful, jumps will not. On the flip side
        # we sometimes end up in circumstances where small jumps don't work
        # but a random draw will produce a good result with reasonable
        # probability, and we don't want to be too timid in our optimisation as
        # it will take too long to complete.
        if self.random.randint(0, 1):
            if upwards:
                replacement_as_int = self.random.randint(
                    existing_as_int + 1, max_int_value)
            else:
                replacement_as_int = self.random.randint(
                    0, existing_as_int - 1)
        elif upwards:
            replacement_as_int = existing_as_int + 1
        else:
            replacement_as_int = existing_as_int - 1

        replacement = int_to_bytes(replacement_as_int, len(existing))

        attempt = self.engine.cached_test_function(
            prefix + replacement + suffix,
            extend=BUFFER_SIZE,
        )

        if self.consider_new_test_data(attempt):
            return True

        if attempt.status < Status.VALID:
            return False

        ex_attempt = attempt.examples[example_index]

        replacement = attempt.buffer[ex_attempt.start:ex_attempt.end]

        return self.consider_new_buffer(prefix + replacement + suffix)
Exemplo n.º 32
0
def uniform(random, n):
    """Returns an hbytes of length n, distributed uniformly at random."""
    return int_to_bytes(random.getrandbits(n * 8), n)
Exemplo n.º 33
0
def write_float(data, f):
    data.write(int_to_bytes(float_to_lex(abs(f)), 8))
    sign = float_to_int(f) >> 63
    data.write(hbytes([sign]))
Exemplo n.º 34
0
def uniform(random, n):
    return int_to_bytes(random.getrandbits(n * 8), n)
Exemplo n.º 35
0
 def append_int(n_bits, value):
     novel_prefix.extend(int_to_bytes(value, bits_to_bytes(n_bits)))
Exemplo n.º 36
0
def write_float(data, f):
    data.write(int_to_bytes(float_to_lex(abs(f)), 8))
    sign = float_to_int(f) >> 63
    data.write(hbytes([sign]))
Exemplo n.º 37
0
def uniform(random, n):
    """Returns an hbytes of length n, distributed uniformly at random."""
    return int_to_bytes(random.getrandbits(n * 8), n)