File: test_ext_doctest.py

package info (click to toggle)
sphinx 1.8.4-1
  • links: PTS, VCS
  • area: main
  • in suites: buster, buster-backports, buster-backports-sloppy
  • size: 20,864 kB
  • sloc: python: 56,100; perl: 410; makefile: 204; sh: 78; xml: 16; ansic: 1
file content (133 lines) | stat: -rw-r--r-- 5,158 bytes parent folder | download | duplicates (6)
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
# -*- coding: utf-8 -*-
"""
    test_doctest
    ~~~~~~~~~~~~

    Test the doctest extension.

    :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
    :license: BSD, see LICENSE for details.
"""
import os
from collections import Counter

import pytest
from packaging.specifiers import InvalidSpecifier
from packaging.version import InvalidVersion
from six import PY2

from sphinx.ext.doctest import is_allowed_version

cleanup_called = 0


@pytest.mark.sphinx('doctest', testroot='ext-doctest')
def test_build(app, status, warning):
    global cleanup_called
    cleanup_called = 0
    app.builder.build_all()
    if app.statuscode != 0:
        assert False, 'failures in doctests:' + status.getvalue()
    # in doctest.txt, there are two named groups and the default group,
    # so the cleanup function must be called three times
    assert cleanup_called == 3, 'testcleanup did not get executed enough times'


def test_is_allowed_version():
    assert is_allowed_version('<3.4', '3.3') is True
    assert is_allowed_version('<3.4', '3.3') is True
    assert is_allowed_version('<3.2', '3.3') is False
    assert is_allowed_version('<=3.4',  '3.3') is True
    assert is_allowed_version('<=3.2',  '3.3') is False
    assert is_allowed_version('==3.3',  '3.3') is True
    assert is_allowed_version('==3.4',  '3.3') is False
    assert is_allowed_version('>=3.2',  '3.3') is True
    assert is_allowed_version('>=3.4',  '3.3') is False
    assert is_allowed_version('>3.2', '3.3') is True
    assert is_allowed_version('>3.4', '3.3') is False
    assert is_allowed_version('~=3.4', '3.4.5') is True
    assert is_allowed_version('~=3.4', '3.5.0') is True

    # invalid spec
    with pytest.raises(InvalidSpecifier):
        is_allowed_version('&3.4', '3.5')

    # invalid version
    with pytest.raises(InvalidVersion):
        is_allowed_version('>3.4', 'Sphinx')


def cleanup_call():
    global cleanup_called
    cleanup_called += 1


recorded_calls = Counter()


@pytest.mark.sphinx('doctest', testroot='ext-doctest-skipif')
def test_skipif(app, status, warning):
    """Tests for the :skipif: option

    The tests are separated into a different test root directory since the
    ``app`` object only evaluates options once in its lifetime. If these tests
    were combined with the other doctest tests, the ``:skipif:`` evaluations
    would be recorded only on the first ``app.builder.build_all()`` run, i.e.
    in ``test_build`` above, and the assertion below would fail.

    """
    global recorded_calls
    recorded_calls = Counter()
    app.builder.build_all()
    if app.statuscode != 0:
        assert False, 'failures in doctests:' + status.getvalue()
    # The `:skipif:` expressions are always run.
    # Actual tests and setup/cleanup code is only run if the `:skipif:`
    # expression evaluates to a False value.
    # Global setup/cleanup are run before/after evaluating the `:skipif:`
    # option in each directive - thus 11 additional invocations for each on top
    # of the ones made for the whole test file.
    assert recorded_calls == {('doctest_global_setup', 'body', True): 13,
                              ('testsetup', ':skipif:', True): 1,
                              ('testsetup', ':skipif:', False): 1,
                              ('testsetup', 'body', False): 1,
                              ('doctest', ':skipif:', True): 1,
                              ('doctest', ':skipif:', False): 1,
                              ('doctest', 'body', False): 1,
                              ('testcode', ':skipif:', True): 1,
                              ('testcode', ':skipif:', False): 1,
                              ('testcode', 'body', False): 1,
                              ('testoutput-1', ':skipif:', True): 1,
                              ('testoutput-2', ':skipif:', True): 1,
                              ('testoutput-2', ':skipif:', False): 1,
                              ('testcleanup', ':skipif:', True): 1,
                              ('testcleanup', ':skipif:', False): 1,
                              ('testcleanup', 'body', False): 1,
                              ('doctest_global_cleanup', 'body', True): 13}


def record(directive, part, should_skip):
    global recorded_calls
    recorded_calls[(directive, part, should_skip)] += 1
    return 'Recorded {} {} {}'.format(directive, part, should_skip)


@pytest.mark.xfail(
    PY2, reason='node.source points to document instead of filename',
)
@pytest.mark.sphinx('doctest', testroot='ext-doctest-with-autodoc')
def test_reporting_with_autodoc(app, status, warning, capfd):
    # Patch builder to get a copy of the output
    written = []
    app.builder._warn_out = written.append
    app.builder.build_all()
    lines = '\n'.join(written).replace(os.sep, '/').split('\n')
    failures = [l for l in lines if l.startswith('File')]
    expected = [
        'File "dir/inner.rst", line 1, in default',
        'File "dir/bar.py", line ?, in default',
        'File "foo.py", line ?, in default',
        'File "index.rst", line 4, in default',
    ]
    for location in expected:
        assert location in failures