def test_keeps_using_solid_passes_while_they_shrink_size():
    good = {
        hbytes([0, 1, 2, 3, 4, 5]),
        hbytes([0, 1, 2, 3, 5]),
        hbytes([0, 1, 3, 5]),
        hbytes([1, 3, 5]),
        hbytes([1, 5]),
    }
    initial = max(good, key=sort_key)

    @shrinking_from(initial)
    def shrinker(data):
        while True:
            data.draw_bits(8)
            if hbytes(data.buffer) in good:
                data.mark_interesting()

    shrinker.clear_passes()

    d1 = shrinker.add_new_pass(block_program("X"))
    d2 = shrinker.add_new_pass(block_program("-"))

    for _ in range(3):
        shrinker.single_greedy_shrink_iteration()
        assert d1.classification == PassClassification.HOPEFUL
        assert d2.classification == PassClassification.CANDIDATE
def test_block_deletion_can_delete_short_ranges(monkeypatch):
    @shrinking_from([v for i in range(5) for _ in range(i + 1) for v in [0, i]])
    def shrinker(data):
        while True:
            n = data.draw_bits(16)
            for _ in range(n):
                if data.draw_bits(16) != n:
                    data.mark_invalid()
            if n == 4:
                data.mark_interesting()

    for i in range(1, 5):
        block_program("X" * i)(shrinker)
    assert list(shrinker.shrink_target.buffer) == [0, 4] * 5
Esempio n. 3
0
def test_block_programs_fail_efficiently(monkeypatch):
    # Create 256 byte-sized blocks. None of the blocks can be deleted, and
    # every deletion attempt produces a different buffer.
    @shrinking_from(bytes(range(256)))
    def shrinker(data):
        values = set()
        for _ in range(256):
            v = data.draw_bits(8)
            values.add(v)
        if len(values) == 256:
            data.mark_interesting()

    monkeypatch.setattr(
        Shrinker, "run_block_program", counts_calls(Shrinker.run_block_program)
    )

    shrinker.max_stall = 500

    shrinker.fixate_shrink_passes([block_program("XX")])

    assert shrinker.shrinks == 0
    assert 250 <= shrinker.calls <= 260

    # The block program should have been run roughly 255 times, with a little
    # bit of wiggle room for implementation details.
    #   - Too many calls mean that failing steps are doing too much work.
    #   - Too few calls mean that this test is probably miscounting and buggy.
    assert 250 <= Shrinker.run_block_program.calls <= 260
def test_block_programs_fail_efficiently(monkeypatch):
    # Create 256 byte-sized blocks. None of the blocks can be deleted, and
    # every deletion attempt produces a different buffer.
    @shrinking_from(hbytes(hrange(256)))
    def shrinker(data):
        values = set()
        for _ in hrange(256):
            v = data.draw_bits(8)
            values.add(v)
        if len(values) == 256:
            data.mark_interesting()

    monkeypatch.setattr(
        Shrinker, "run_block_program", counts_calls(Shrinker.run_block_program)
    )

    shrinker.fixate_shrink_passes([block_program("XX")])

    assert shrinker.shrinks == 0
    assert 250 <= shrinker.calls <= 260

    # The block program should have been run roughly 255 times, with a little
    # bit of wiggle room for implementation details.
    #   - Too many calls mean that failing steps are doing too much work.
    #   - Too few calls mean that this test is probably miscounting and buggy.
    assert 250 <= Shrinker.run_block_program.calls <= 260
Esempio n. 5
0
def test_shrink_pass_method_is_idempotent():
    @shrinking_from([255])
    def shrinker(data):
        data.draw_bits(8)
        data.mark_interesting()

    sp = shrinker.shrink_pass(block_program("X"))
    assert isinstance(sp, ShrinkPass)
    assert shrinker.shrink_pass(sp) is sp
def test_block_programs_are_adaptive():
    @shrinking_from(hbytes(1000) + hbytes([1]))
    def shrinker(data):
        while not data.draw_bits(1):
            pass
        data.mark_interesting()

    p = shrinker.add_new_pass(block_program("X"))
    shrinker.fixate_shrink_passes([p.name])

    assert len(shrinker.shrink_target.buffer) == 1
    assert shrinker.calls <= 60
def test_block_programs_are_adaptive():
    @shrinking_from(hbytes(1000) + hbytes([1]))
    def shrinker(data):
        while not data.draw_bits(1):
            pass
        data.mark_interesting()

    p = shrinker.add_new_pass(block_program("X"))
    shrinker.fixate_shrink_passes([p.name])

    assert len(shrinker.shrink_target.buffer) == 1
    assert shrinker.calls <= 60
def test_passes_can_come_back_to_life():
    initial = hbytes([1, 2, 3, 4, 5, 6])
    buf1 = hbytes([0, 1, 3, 4, 5, 6])
    buf2 = hbytes([0, 1, 3, 4, 4, 6])

    good = {initial, buf1, buf2}

    @shrinking_from(initial)
    def shrinker(data):
        string = hbytes([data.draw_bits(8) for _ in range(6)])
        if string in good:
            data.mark_interesting()

    shrinker.clear_passes()
    shrinker.add_new_pass(block_program("--"))
    shrinker.add_new_pass(block_program("-"))

    shrinker.single_greedy_shrink_iteration()
    assert shrinker.shrink_target.buffer == buf1

    shrinker.single_greedy_shrink_iteration()
    assert shrinker.shrink_target.buffer == buf2
def test_pandas_hack():
    @shrinking_from([2, 1, 1, 7])
    def shrinker(data):
        n = data.draw_bits(8)
        m = data.draw_bits(8)
        if n == 1:
            if m == 7:
                data.mark_interesting()
        data.draw_bits(8)
        if data.draw_bits(8) == 7:
            data.mark_interesting()

    shrinker.run_shrink_pass(block_program("-XX"))
    assert list(shrinker.shrink_target.buffer) == [1, 7]
def test_pandas_hack():
    @shrinking_from([2, 1, 1, 7])
    def shrinker(data):
        n = data.draw_bits(8)
        m = data.draw_bits(8)
        if n == 1:
            if m == 7:
                data.mark_interesting()
        data.draw_bits(8)
        if data.draw_bits(8) == 7:
            data.mark_interesting()

    shrinker.run_shrink_pass(block_program("-XX"))
    assert list(shrinker.shrink_target.buffer) == [1, 7]
def test_block_deletion_can_delete_short_ranges(monkeypatch):
    @shrinking_from([v for i in range(5) for _ in range(i + 1) for v in [0, i]])
    def shrinker(data):
        while True:
            n = data.draw_bits(16)
            for _ in range(n):
                if data.draw_bits(16) != n:
                    data.mark_invalid()
            if n == 4:
                data.mark_interesting()

    for i in range(1, 5):
        shrinker.run_shrink_pass(block_program("X" * i))
    assert list(shrinker.shrink_target.buffer) == [0, 4] * 5
def test_will_enable_previously_bad_passes_when_failing_to_shrink():
    # We lead the shrinker down the garden path a bit where it keeps making
    # progress but only lexically. When it finally gets down to the minimum
    good = {
        hbytes([1, 2, 3, 4, 5, 6]),
        hbytes([1, 2, 3, 4, 5, 5]),
        hbytes([1, 2, 2, 4, 5, 5]),
        hbytes([1, 2, 2, 4, 4, 5]),
        hbytes([0, 2, 2, 4, 4, 5]),
        hbytes([0, 1, 2, 4, 4, 5]),
    }

    initial = max(good)
    final = min(good)

    @shrinking_from(initial + hbytes([0, 7]))
    def shrinker(data):
        string = hbytes([data.draw_bits(8) for _ in range(6)])
        if string in good:
            n = 0
            while data.draw_bits(8) != 7:
                n += 1
            if not (string == final or n > 0):
                data.mark_invalid()
            data.mark_interesting()

    # In order to get to the minimized result we want to run both of these,
    # but the second pass starts out as disabled (and anyway won't work until
    # the first has hit fixity).
    shrinker.clear_passes()
    shrinker.add_new_pass(block_program("-"))
    shrinker.add_new_pass(block_program("X"))

    shrinker.shrink()

    assert shrinker.shrink_target.buffer == final + hbytes([7])
Esempio n. 13
0
def test_will_let_fixate_shrink_passes_do_a_full_run_through():
    @shrinking_from(range(50))
    def shrinker(data):
        for i in range(50):
            if data.draw_bits(8) != i:
                data.mark_invalid()
        data.mark_interesting()

    shrinker.max_stall = 5

    passes = [block_program("X" * i) for i in range(1, 11)]

    with pytest.raises(StopShrinking):
        shrinker.fixate_shrink_passes(passes)

    assert shrinker.shrink_pass(passes[-1]).calls > 0