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 137 138 139 140 141 142 143 144 145 146 147 148
|
# 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, strategies as st
from hypothesis.errors import InvalidArgument
from tests.common.debug import assert_no_examples, check_can_generate_examples, minimal
def test_binary_tree():
tree = st.deferred(lambda: st.integers() | st.tuples(tree, tree))
assert minimal(tree) == 0
assert minimal(tree, lambda x: isinstance(x, tuple)) == (0, 0)
def test_mutual_recursion():
t = st.deferred(lambda: a | b)
a = st.deferred(lambda: st.none() | st.tuples(st.just("a"), b))
b = st.deferred(lambda: st.none() | st.tuples(st.just("b"), a))
for c in ("a", "b"):
assert minimal(t, lambda x: x is not None and x[0] == c) == (c, None) # noqa
def test_errors_on_non_function_define():
x = st.deferred(1)
with pytest.raises(InvalidArgument):
check_can_generate_examples(x)
def test_errors_if_define_does_not_return_search_strategy():
x = st.deferred(lambda: 1)
with pytest.raises(InvalidArgument):
check_can_generate_examples(x)
def test_errors_on_definition_as_self():
x = st.deferred(lambda: x)
with pytest.raises(InvalidArgument):
check_can_generate_examples(x)
def test_branches_pass_through_deferred():
x = st.one_of(st.booleans(), st.integers())
y = st.deferred(lambda: x)
assert x.branches == y.branches
def test_can_draw_one_of_self():
x = st.deferred(lambda: st.one_of(st.booleans(), x))
assert minimal(x) is False
assert len(x.branches) == 1
def test_hidden_self_references_just_result_in_no_example():
bad = st.deferred(lambda: st.none().flatmap(lambda _: bad))
assert_no_examples(bad)
def test_self_recursive_flatmap():
bad = st.deferred(lambda: bad.flatmap(lambda x: st.none()))
assert_no_examples(bad)
def test_self_reference_through_one_of_can_detect_emptiness():
bad = st.deferred(lambda: st.one_of(bad, bad))
assert bad.is_empty
def test_self_tuple_draws_nothing():
x = st.deferred(lambda: st.tuples(x))
assert_no_examples(x)
def test_mutually_recursive_tuples_draw_nothing():
x = st.deferred(lambda: st.tuples(y))
y = st.tuples(x)
assert_no_examples(x)
assert_no_examples(y)
def test_literals_strategy_is_valid():
literals = st.deferred(
lambda: st.one_of(
st.booleans(), st.tuples(literals, literals), literals.map(lambda x: [x])
)
)
@given(literals)
def test(e):
pass
test()
assert not literals.has_reusable_values
def test_impossible_self_recursion():
x = st.deferred(lambda: st.tuples(st.none(), x))
assert x.is_empty
assert x.has_reusable_values
def test_very_deep_deferral():
# This test is designed so that the recursive properties take a very long
# time to converge: Although we can rapidly determine them for the original
# value, each round in the fixed point calculation only manages to update
# a single value in the related strategies, so it takes 100 rounds to
# update everything. Most importantly this triggers our infinite loop
# detection heuristic and we start tracking duplicates, but we shouldn't
# see any because this loop isn't infinite, just long.
def strat(i):
if i == 0:
return st.deferred(lambda: st.one_of([*strategies, st.none()]))
else:
return st.deferred(lambda: st.tuples(strategies[(i + 1) % len(strategies)]))
strategies = list(map(strat, range(100)))
assert strategies[0].has_reusable_values
assert not strategies[0].is_empty
def test_recursion_in_middle():
# This test is significant because the integers().map(abs) is not checked
# in the initial pass - when we recurse into x initially we decide that
# x is empty, so the tuple is empty, and don't need to check the third
# argument. Then when we do the more refined test we've discovered that x
# is non-empty, so we need to check the non-emptiness of the last component
# to determine the non-emptiness of the tuples.
x = st.deferred(lambda: st.tuples(st.none(), x, st.integers().map(abs)) | st.none())
assert not x.is_empty
def test_deferred_supports_find():
nested = st.deferred(lambda: st.integers() | st.lists(nested))
assert nested.supports_find
|