File: test_searchstrategy.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 (180 lines) | stat: -rw-r--r-- 4,810 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
# 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 dataclasses
import functools
import random
import sys
from collections import defaultdict, namedtuple

import attr
import pytest

from hypothesis import given
from hypothesis.errors import InvalidArgument, Unsatisfiable
from hypothesis.internal.conjecture.data import ConjectureData
from hypothesis.internal.reflection import get_pretty_function_description
from hypothesis.strategies import booleans, data, integers, just, lists, none, tuples
from hypothesis.strategies._internal.utils import to_jsonable

from tests.common.debug import assert_simple_property, check_can_generate_examples
from tests.common.utils import checks_deprecated_behaviour


def test_or_errors_when_given_non_strategy():
    bools = tuples(booleans())
    with pytest.raises(ValueError):
        bools | "foo"


SomeNamedTuple = namedtuple("SomeNamedTuple", ("a", "b"))


def last(xs):
    t = None
    for x in xs:
        t = x
    return t


def test_just_strategy_uses_repr():
    class WeirdRepr:
        def __repr__(self):
            return "ABCDEFG"

    assert repr(just(WeirdRepr())) == f"just({WeirdRepr()!r})"


def test_just_strategy_does_not_draw():
    data = ConjectureData.for_choices([])
    s = just("hello")
    assert s.do_draw(data) == "hello"


def test_none_strategy_does_not_draw():
    data = ConjectureData.for_choices([])
    s = none()
    assert s.do_draw(data) is None


def test_can_map():
    s = integers().map(pack=lambda t: "foo")
    assert_simple_property(s, lambda v: v == "foo")


def test_example_raises_unsatisfiable_when_too_filtered():
    with pytest.raises(Unsatisfiable):
        check_can_generate_examples(integers().filter(lambda x: False))


def nameless_const(x):
    def f(u, v):
        return u

    return functools.partial(f, x)


def test_can_map_nameless():
    f = nameless_const(2)
    assert get_pretty_function_description(f) in repr(integers().map(f))


def test_can_flatmap_nameless():
    f = nameless_const(just(3))
    assert get_pretty_function_description(f) in repr(integers().flatmap(f))


def test_flatmap_with_invalid_expand():
    with pytest.raises(InvalidArgument):
        check_can_generate_examples(just(100).flatmap(lambda n: "a"))


_bad_random_strategy = lists(integers(), min_size=1).map(random.choice)


@checks_deprecated_behaviour
def test_use_of_global_random_is_deprecated_in_given():
    check_can_generate_examples(_bad_random_strategy)


@checks_deprecated_behaviour
def test_use_of_global_random_is_deprecated_in_interactive_draws():
    @given(data())
    def inner(d):
        d.draw(_bad_random_strategy)

    inner()


def test_jsonable():
    assert to_jsonable(object(), avoid_realization=True) == "<symbolic>"
    assert isinstance(to_jsonable(object(), avoid_realization=False), str)


@dataclasses.dataclass()
class HasDefaultDict:
    x: defaultdict


@attr.s
class AttrsClass:
    n = attr.ib()


def test_jsonable_defaultdict():
    obj = HasDefaultDict(defaultdict(list))
    obj.x["a"] = [42]
    assert to_jsonable(obj, avoid_realization=False) == {"x": {"a": [42]}}


def test_jsonable_attrs():
    obj = AttrsClass(n=10)
    assert to_jsonable(obj, avoid_realization=False) == {"n": 10}


def test_jsonable_namedtuple():
    Obj = namedtuple("Obj", ("x"))
    obj = Obj(10)
    assert to_jsonable(obj, avoid_realization=False) == {"x": 10}


def test_jsonable_small_ints_are_ints():
    n = 2**62
    for avoid in (True, False):
        assert isinstance(to_jsonable(n, avoid_realization=avoid), int)
        assert to_jsonable(n, avoid_realization=avoid) == n


def test_jsonable_large_ints_are_floats():
    n = 2**63
    assert isinstance(to_jsonable(n, avoid_realization=False), float)
    assert to_jsonable(n, avoid_realization=False) == float(n)
    assert to_jsonable(n, avoid_realization=True) == "<symbolic>"


def test_jsonable_very_large_ints():
    # previously caused OverflowError when casting to float.
    n = 2**1024
    assert to_jsonable(n, avoid_realization=False) == sys.float_info.max
    assert to_jsonable(n, avoid_realization=True) == "<symbolic>"


@dataclasses.dataclass()
class HasCustomJsonFormat:
    x: str

    def to_json(self):
        return "surprise!"


def test_jsonable_override():
    obj = HasCustomJsonFormat("expected")
    assert to_jsonable(obj, avoid_realization=False) == "surprise!"
    assert to_jsonable(obj, avoid_realization=True) == "<symbolic>"