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 131 132 133 134 135 136
|
# 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 pytest
from hypothesis import given
from hypothesis.errors import Flaky, FlakyFailure
from hypothesis.strategies import composite, integers, none
from tests.common.utils import Why, skipif_threading, xfail_on_crosshair
@pytest.mark.parametrize(
"e", [KeyboardInterrupt, SystemExit, GeneratorExit, ValueError]
)
def test_exception_propagates_fine(e):
@given(integers())
def test_raise(x):
raise e
with pytest.raises(e):
test_raise()
@pytest.mark.parametrize(
"e", [KeyboardInterrupt, SystemExit, GeneratorExit, ValueError]
)
def test_exception_propagates_fine_from_strategy(e):
@composite
def interrupt_eventually(draw):
raise e
# this line will not be executed, but must be here
# to pass draw function static reference check
return draw(none())
@given(interrupt_eventually())
def test_do_nothing(x):
pass
with pytest.raises(e):
test_do_nothing()
@xfail_on_crosshair(Why.other, strict=False) # extra replay from backend switch
@pytest.mark.parametrize("e", [KeyboardInterrupt, ValueError])
def test_baseexception_no_rerun_no_flaky(e):
runs = 0
interrupt = 3
@given(integers())
def test_raise_baseexception(x):
nonlocal runs
runs += 1
if runs == interrupt:
raise e
if issubclass(e, (KeyboardInterrupt, SystemExit, GeneratorExit)):
# Here SystemExit and GeneratorExit are passed through
with pytest.raises(e):
test_raise_baseexception()
assert runs == interrupt
else:
with pytest.raises(FlakyFailure):
test_raise_baseexception()
@xfail_on_crosshair(Why.symbolic_outside_context, strict=False) # KI and GE only
@pytest.mark.parametrize(
"e", [KeyboardInterrupt, SystemExit, GeneratorExit, ValueError]
)
def test_baseexception_in_strategy_no_rerun_no_flaky(e):
runs = 0
interrupt = 3
@composite
def interrupt_eventually(draw):
nonlocal runs
runs += 1
if runs == interrupt:
raise e
return draw(integers())
@given(interrupt_eventually())
def test_do_nothing(x):
pass
if issubclass(e, KeyboardInterrupt):
with pytest.raises(e):
test_do_nothing()
assert runs == interrupt
else:
# Now SystemExit and GeneratorExit are caught like other exceptions
with pytest.raises(Flaky):
test_do_nothing()
TEMPLATE = """
from hypothesis import given, note, strategies as st
@st.composite
def things(draw):
raise {exception}
# this line will not be executed, but must be here
# to pass draw function static reference check
return draw(st.none())
@given(st.data(), st.integers())
def test(data, x):
if x > 100:
data.draw({strategy})
raise {exception}
"""
@skipif_threading # something in pytest here is not thread safe
@pytest.mark.parametrize("exc_name", ["SystemExit", "GeneratorExit"])
@pytest.mark.parametrize("use_composite", [True, False])
def test_explanations(testdir, exc_name, use_composite):
code = TEMPLATE.format(
exception=exc_name, strategy="things()" if use_composite else "st.none()"
)
test_file = str(testdir.makepyfile(code))
pytest_stdout = str(testdir.runpytest_inprocess(test_file, "--tb=native").stdout)
assert "x=101" in pytest_stdout
assert exc_name in pytest_stdout
|