File: test_health_checks.py

package info (click to toggle)
python-hypothesis 6.130.5-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 14,884 kB
  • sloc: python: 59,532; ruby: 1,107; sh: 251; makefile: 45
file content (125 lines) | stat: -rw-r--r-- 4,298 bytes parent folder | download
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
# 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/.

import time

import pytest
from pytest import raises

from hypothesis import HealthCheck, Phase, given, settings, strategies as st
from hypothesis.errors import FailedHealthCheck
from hypothesis.internal.conjecture.data import ConjectureData
from hypothesis.internal.conjecture.engine import BUFFER_SIZE
from hypothesis.internal.entropy import deterministic_PRNG
from hypothesis.strategies._internal.lazy import LazyStrategy

pytestmark = pytest.mark.skipif(settings._current_profile == "crosshair", reason="slow")

large_strategy = st.binary(min_size=7000, max_size=7000)
too_large_strategy = st.tuples(large_strategy, large_strategy)


def test_large_data_will_fail_a_health_check():
    @given(st.none() | too_large_strategy)
    @settings(database=None)
    def test(x):
        pass

    with raises(FailedHealthCheck) as e:
        test()
    assert "allowable size" in e.value.args[0]


def test_large_base_example_fails_health_check():
    @given(large_strategy)
    def test(b):
        pass

    with pytest.raises(FailedHealthCheck) as exc:
        test()

    assert str(HealthCheck.large_base_example) in str(exc.value)


def test_example_that_shrinks_to_overrun_fails_health_check():
    @given(too_large_strategy | st.none())
    def test(b):
        pass

    with pytest.raises(FailedHealthCheck) as exc:
        test()

    assert str(HealthCheck.large_base_example) in str(exc.value)


slow_down_init = True


def slow_init_integers(*args, **kwargs):
    # This mimics st.characters() or st.text(), which perform some
    # expensive Unicode calculations when the cache is empty.
    global slow_down_init
    if slow_down_init:
        time.sleep(0.5)  # We monkeypatch time, so this is fast
        slow_down_init = False
    return st.integers(*args, **kwargs)


@given(st.data())
def test_lazy_slow_initialization_issue_2108_regression(data):
    # Slow init in strategies wrapped in a LazyStrategy, inside an interactive draw,
    # should be attributed to drawing from the strategy (not the test function).
    # Specifically, this used to fail with a DeadlineExceeded error.
    data.draw(LazyStrategy(slow_init_integers, (), {}))


def test_does_not_trigger_health_check_on_simple_strategies(monkeypatch):
    existing_draw = ConjectureData.draw_integer

    # We need to make drawing data artificially slow in order to trigger this
    # effect. This isn't actually slow because time is fake in our CI, but
    # we need it to pretend to be.
    def draw_integer(*args, **kwargs):
        time.sleep(0.001)
        return existing_draw(*args, **kwargs)

    monkeypatch.setattr(ConjectureData, "draw_integer", draw_integer)

    with deterministic_PRNG():
        for _ in range(100):
            # Setting max_examples=11 ensures we have enough examples for the
            # health checks to finish running, but cuts the generation short
            # after that point to allow this test to run in reasonable time.
            @settings(database=None, max_examples=11, phases=[Phase.generate])
            @given(st.integers())
            def test(n):
                pass

            test()


def test_does_not_trigger_health_check_when_most_examples_are_small(monkeypatch):
    with deterministic_PRNG():
        for _ in range(100):
            # Setting max_examples=11 ensures we have enough examples for the
            # health checks to finish running, but cuts the generation short
            # after that point to allow this test to run in reasonable time.
            @settings(database=None, max_examples=11, phases=[Phase.generate])
            @given(
                st.integers(0, 100).flatmap(
                    lambda n: st.binary(
                        min_size=min(n * 100, BUFFER_SIZE), max_size=n * 100
                    )
                )
            )
            def test(b):
                pass

            test()