File: test_charmap.py

package info (click to toggle)
python-hypothesis 6.67.1-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 14,220 kB
  • sloc: python: 46,711; ruby: 1,107; sh: 255; xml: 140; makefile: 49; javascript: 12
file content (196 lines) | stat: -rw-r--r-- 5,631 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
186
187
188
189
190
191
192
193
194
195
196
# 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 os
import sys
import tempfile
import time
import unicodedata

from hypothesis import assume, given, strategies as st
from hypothesis.internal import charmap as cm


def test_charmap_contains_all_unicode():
    n = 0
    for vs in cm.charmap().values():
        for u, v in vs:
            n += v - u + 1
    assert n == sys.maxunicode + 1


def test_charmap_has_right_categories():
    for cat, intervals in cm.charmap().items():
        for u, v in intervals:
            for i in range(u, v + 1):
                real = unicodedata.category(chr(i))
                assert real == cat, f"{i} is {real} but reported in {cat}"


def assert_valid_range_list(ls):
    for u, v in ls:
        assert u <= v
    for i in range(len(ls) - 1):
        assert ls[i] <= ls[i + 1]
        assert ls[i][-1] < ls[i + 1][0]


@given(
    st.sets(st.sampled_from(cm.categories())),
    st.sets(st.sampled_from(cm.categories())) | st.none(),
)
def test_query_matches_categories(exclude, include):
    values = cm.query(exclude, include)
    assert_valid_range_list(values)
    for u, v in values:
        for i in (u, v, (u + v) // 2):
            cat = unicodedata.category(chr(i))
            if include is not None:
                assert cat in include
            assert cat not in exclude


@given(
    st.sets(st.sampled_from(cm.categories())),
    st.sets(st.sampled_from(cm.categories())) | st.none(),
    st.integers(0, sys.maxunicode),
    st.integers(0, sys.maxunicode),
)
def test_query_matches_categories_codepoints(exclude, include, m1, m2):
    m1, m2 = sorted((m1, m2))
    values = cm.query(exclude, include, min_codepoint=m1, max_codepoint=m2)
    assert_valid_range_list(values)
    for u, v in values:
        assert m1 <= u
        assert v <= m2


@given(st.sampled_from(cm.categories()), st.integers(0, sys.maxunicode))
def test_exclude_only_excludes_from_that_category(cat, i):
    c = chr(i)
    assume(unicodedata.category(c) != cat)
    intervals = cm.query(exclude_categories=(cat,))
    assert any(a <= i <= b for a, b in intervals)


def test_reload_charmap():
    x = cm.charmap()
    assert x is cm.charmap()
    cm._charmap = None
    y = cm.charmap()
    assert x is not y
    assert x == y


def test_recreate_charmap():
    x = cm.charmap()
    assert x is cm.charmap()
    cm._charmap = None
    os.unlink(cm.charmap_file())
    y = cm.charmap()
    assert x is not y
    assert x == y


def test_uses_cached_charmap():
    cm.charmap()

    # Reset the last-modified time of the cache file to a point in the past.
    mtime = int(time.time() - 1000)
    os.utime(cm.charmap_file(), (mtime, mtime))
    statinfo = os.stat(cm.charmap_file())
    assert statinfo.st_mtime == mtime

    # Force reload of charmap from cache file and check that mtime is unchanged.
    cm._charmap = None
    cm.charmap()
    statinfo = os.stat(cm.charmap_file())
    assert statinfo.st_mtime == mtime


def test_union_empty():
    assert cm._union_intervals([], []) == ()
    assert cm._union_intervals([], [[1, 2]]) == ((1, 2),)
    assert cm._union_intervals([[1, 2]], []) == ((1, 2),)


def test_union_handles_totally_overlapped_gap():
    #   < xx  >  Imagine the intervals x and y as bit strings.
    # | <yy yy>  The bit at position n is set if n falls inside that interval.
    # = <zzzzz>  In this model _union_intervals() performs bit-wise or.
    assert cm._union_intervals([[2, 3]], [[1, 2], [4, 5]]) == ((1, 5),)


def test_union_handles_partially_overlapped_gap():
    #   <  x  >  Imagine the intervals x and y as bit strings.
    # | <yy  y>  The bit at position n is set if n falls inside that interval.
    # = <zzz z>  In this model _union_intervals() performs bit-wise or.
    assert cm._union_intervals([[3, 3]], [[1, 2], [5, 5]]) == ((1, 3), (5, 5))


def test_successive_union():
    x = []
    for v in cm.charmap().values():
        x = cm._union_intervals(x, v)
    assert x == ((0, sys.maxunicode),)


def test_can_handle_race_between_exist_and_create(monkeypatch):
    x = cm.charmap()
    cm._charmap = None
    monkeypatch.setattr(os.path, "exists", lambda p: False)
    y = cm.charmap()
    assert x is not y
    assert x == y


def test_exception_in_write_does_not_lead_to_broken_charmap(monkeypatch):
    def broken(*args, **kwargs):
        raise ValueError()

    cm._charmap = None
    monkeypatch.setattr(os.path, "exists", lambda p: False)
    monkeypatch.setattr(os, "rename", broken)

    cm.charmap()
    cm.charmap()


def test_regenerate_broken_charmap_file():
    cm.charmap()
    file_loc = cm.charmap_file()

    with open(file_loc, "wb"):
        pass

    cm._charmap = None
    cm.charmap()


def test_exclude_characters_are_included_in_key():
    assert cm.query() != cm.query(exclude_characters="0")


def test_error_writing_charmap_file_is_suppressed(monkeypatch):
    def broken_mkstemp(dir):
        raise RuntimeError()

    monkeypatch.setattr(tempfile, "mkstemp", broken_mkstemp)

    try:
        # Cache the charmap to avoid a performance hit the next time
        # somebody tries to use it.
        saved = cm._charmap
        cm._charmap = None
        os.unlink(cm.charmap_file())

        cm.charmap()
    finally:
        cm._charmap = saved