File: test_forced.py

package info (click to toggle)
python-hypothesis 6.138.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 15,272 kB
  • sloc: python: 62,853; ruby: 1,107; sh: 253; makefile: 41; javascript: 6
file content (185 lines) | stat: -rw-r--r-- 5,566 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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# 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 math

import pytest

import hypothesis.strategies as st
from hypothesis import HealthCheck, example, given, settings
from hypothesis.internal.conjecture import utils as cu
from hypothesis.internal.conjecture.choice import choice_equal
from hypothesis.internal.conjecture.data import ConjectureData
from hypothesis.internal.floats import SIGNALING_NAN, SMALLEST_SUBNORMAL

from tests.conjecture.common import choice_types_constraints, fresh_data


@given(st.data())
@settings(
    database=None,
    suppress_health_check=[HealthCheck.filter_too_much, HealthCheck.too_slow],
)
def test_forced_many(data):
    forced = data.draw(st.integers(0, 100))
    min_size = data.draw(st.integers(0, forced))
    max_size = data.draw(st.integers(forced, 100))
    assert min_size <= forced <= max_size  # by construction

    data = fresh_data()
    many = cu.many(
        data,
        min_size=min_size,
        average_size=(min_size + max_size) / 2,
        max_size=max_size,
        forced=forced,
    )
    for _ in range(forced):
        assert many.more()

    assert not many.more()

    # ensure values written to the buffer do in fact generate the forced value
    data = ConjectureData.for_choices(data.choices)
    many = cu.many(
        data,
        min_size=min_size,
        average_size=(min_size + max_size) / 2,
        max_size=max_size,
    )
    for _ in range(forced):
        assert many.more()

    assert not many.more()


@example(("boolean", {"p": 1e-19, "forced": True}))  # 64 bit p
@example(("boolean", {"p": 3e-19, "forced": True}))  # 62 bit p
@example(
    (
        "integer",
        {
            "min_value": -1,
            "max_value": 1,
            "shrink_towards": 1,
            "weights": {-1: 0.2, 0: 0.2, 1: 0.2},
            "forced": 0,
        },
    )
)
@example(
    (
        "integer",
        {
            "min_value": -1,
            "max_value": 1,
            "shrink_towards": -1,
            "weights": {-1: 0.2, 0: 0.2, 1: 0.2},
            "forced": 0,
        },
    )
)
@example(
    (
        "integer",
        {
            "min_value": 10,
            "max_value": 1_000,
            "shrink_towards": 17,
            "weights": {20: 0.1},
            "forced": 15,
        },
    )
)
@example(
    (
        "integer",
        {
            "min_value": -1_000,
            "max_value": -10,
            "shrink_towards": -17,
            "weights": {-20: 0.1},
            "forced": -15,
        },
    )
)
@example(("float", {"forced": 0.0}))
@example(("float", {"forced": -0.0}))
@example(("float", {"forced": 1.0}))
@example(("float", {"forced": 1.2345}))
@example(("float", {"forced": SMALLEST_SUBNORMAL}))
@example(("float", {"forced": -SMALLEST_SUBNORMAL}))
@example(("float", {"forced": 100 * SMALLEST_SUBNORMAL}))
@example(("float", {"forced": math.nan}))
@example(("float", {"forced": -math.nan}))
@example(("float", {"forced": SIGNALING_NAN}))
@example(("float", {"forced": -SIGNALING_NAN}))
@example(("float", {"forced": 1e999}))
@example(("float", {"forced": -1e999}))
# previously errored on our {pos, neg}_clamper logic not considering nans.
@example(
    (
        "float",
        {"min_value": -1 * math.inf, "max_value": -1 * math.inf, "forced": math.nan},
    )
)
@given(choice_types_constraints(use_forced=True))
def test_forced_values(choice_type_and_constraints):
    (choice_type, constraints) = choice_type_and_constraints
    constraints = constraints.copy()
    forced = constraints["forced"]
    data = fresh_data()
    assert choice_equal(getattr(data, f"draw_{choice_type}")(**constraints), forced)

    # now make sure the written buffer reproduces the forced value, even without
    # specifying forced=.
    del constraints["forced"]
    data = ConjectureData.for_choices(data.choices)
    assert choice_equal(getattr(data, f"draw_{choice_type}")(**constraints), forced)


@pytest.mark.parametrize("sign", [1, -1])
@pytest.mark.parametrize(
    "min_value, max_value",
    [
        (0.0, 0.0),
        (-0.0, -0.0),
        (0.0, 100.0),
        (-100.0, -0.0),
        (5.0, 10.0),
        (-10.0, -5.0),
    ],
)
@given(random=st.randoms())
def test_forced_floats_with_nan(random, sign, min_value, max_value):
    # nans with a sign opposite of both bounds previously gave us trouble
    # trying to use float clampers that didn't exist when drawing.
    data = fresh_data(random=random)
    data.draw_float(min_value=min_value, max_value=max_value, forced=sign * math.nan)


@given(st.data())
def test_forced_with_large_magnitude_integers(data):
    bound_offset = data.draw(st.integers(min_value=0))
    # forced_offset = bound_offset + st.integers(min_value=0) may look cleaner, but
    # has subtly different maximum value semantics as it is twice the range of a
    # single draw
    forced_offset = data.draw(st.integers(min_value=bound_offset))

    half_range = 2**127 + 1
    cd = fresh_data()
    cd.draw_integer(
        min_value=half_range + bound_offset, forced=half_range + forced_offset
    )

    cd = fresh_data()
    cd.draw_integer(
        max_value=-(half_range + bound_offset), forced=-(half_range + forced_offset)
    )