Skip to content

Commit

Permalink
Use Mock more in tests (#986)
Browse files Browse the repository at this point in the history
* Replace FakeSphinxApp with a Mock

No need to re-implement something that's in the standard library.

* Use a Mock in gallery_conf fixture

This also drops the last use of `Bunch`.
  • Loading branch information
QuLogic authored Aug 6, 2022
1 parent 4072df4 commit edf8a01
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 71 deletions.
44 changes: 4 additions & 40 deletions sphinx_gallery/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,19 @@
"""
from __future__ import division, absolute_import, print_function

import collections
from contextlib import contextmanager
from io import StringIO
import os
import shutil
from unittest.mock import Mock

import pytest

import sphinx
from sphinx.application import Sphinx
from sphinx.errors import ExtensionError
from sphinx.util.docutils import docutils_namespace
from sphinx_gallery import (docs_resolv, gen_gallery, gen_rst, utils,
py_source_parser)
from sphinx_gallery import docs_resolv, gen_gallery, gen_rst, py_source_parser
from sphinx_gallery.scrapers import _import_matplotlib
from sphinx_gallery.utils import _get_image

Expand All @@ -27,54 +26,19 @@ def pytest_report_header(config, startdir):
return 'Sphinx: %s (%s)' % (sphinx.__version__, sphinx.__file__)


Params = collections.namedtuple('Params', 'args kwargs')


class FakeSphinxApp:
def __init__(self):
self.calls = collections.defaultdict(list)

def status_iterator(self, *args, **kwargs):
self.calls['status_iterator'].append(Params(args, kwargs))
for it in args[0]:
yield it

def warning(self, *args, **kwargs):
self.calls['warning'].append(Params(args, kwargs))

def warn(self, *args, **kwargs):
self.calls['warn'].append(Params(args, kwargs))

def info(self, *args, **kwargs):
self.calls['info'].append(Params(args, kwargs))

def verbose(self, *args, **kwargs):
self.calls['verbose'].append(Params(args, kwargs))

def debug(self, *args, **kwargs):
self.calls['debug'].append(Params(args, kwargs))


@pytest.fixture
def gallery_conf(tmpdir):
"""Set up a test sphinx-gallery configuration."""
app = utils.Bunch()
app.add_css_file = lambda x: None
app.config = dict(source_suffix={'.rst': None})
app = Mock(spec=Sphinx, config=dict(source_suffix={'.rst': None}))
gallery_conf = gen_gallery._complete_gallery_conf(
{}, str(tmpdir), True, False, app=app)
gallery_conf.update(examples_dir=str(tmpdir), gallery_dir=str(tmpdir))
return gallery_conf


@pytest.fixture
def fakesphinxapp():
yield FakeSphinxApp()


@pytest.fixture
def log_collector(monkeypatch):
app = FakeSphinxApp()
app = Mock(spec=Sphinx, name='FakeSphinxApp')()
monkeypatch.setattr(docs_resolv, 'logger', app)
monkeypatch.setattr(gen_gallery, 'logger', app)
monkeypatch.setattr(py_source_parser, 'logger', app)
Expand Down
39 changes: 19 additions & 20 deletions sphinx_gallery/tests/test_gen_rst.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,8 @@ def test_fail_example(gallery_conf, failing_code, want,

sg.generate_file_rst('raise.py', gallery_conf['gallery_dir'],
gallery_conf['examples_dir'], gallery_conf)
assert len(log_collector.calls['warning']) == 1
msg = log_collector.calls['warning'][0].args[2]
log_collector.warning.assert_called_once()
msg = log_collector.warning.call_args[0][2]
assert want in msg
assert 'gen_gallery' not in msg
# can only check that gen_rst is removed on non-input ones
Expand Down Expand Up @@ -549,7 +549,7 @@ def test_exclude_implicit(gallery_conf,


@pytest.mark.parametrize('ext', ('.txt', '.rst', '.bad'))
def test_gen_dir_rst(gallery_conf, fakesphinxapp, ext):
def test_gen_dir_rst(gallery_conf, ext):
"""Test gen_dir_rst."""
print(os.listdir(gallery_conf['examples_dir']))
fname_readme = os.path.join(gallery_conf['src_dir'], 'README.txt')
Expand Down Expand Up @@ -993,51 +993,50 @@ def test_full_line(log_collector_wrap):
tee.write('Output\n')
tee.flush()
assert output_file.getvalue() == 'Output\n'
assert len(log_collector.calls['verbose']) == 2
assert src_filename in log_collector.calls['verbose'][0].args
assert 'Output' in log_collector.calls['verbose'][1].args
assert log_collector.verbose.call_count == 2
assert src_filename in log_collector.verbose.call_args_list[0][0]
assert 'Output' in log_collector.verbose.call_args_list[1][0]


def test_incomplete_line_with_flush(log_collector_wrap):
# An incomplete line ...
log_collector, src_filename, tee, output_file = log_collector_wrap
tee.write('Output')
assert output_file.getvalue() == 'Output'
assert len(log_collector.calls['verbose']) == 1
assert src_filename in log_collector.calls['verbose'][0].args
log_collector.verbose.assert_called_once()
assert src_filename in log_collector.verbose.call_args[0]

# ... should appear when flushed.
tee.flush()
assert len(log_collector.calls['verbose']) == 2
assert 'Output' in log_collector.calls['verbose'][1].args
assert log_collector.verbose.call_count == 2
assert 'Output' in log_collector.verbose.call_args_list[1][0]


def test_incomplete_line_with_more_output(log_collector_wrap):
# An incomplete line ...
log_collector, src_filename, tee, output_file = log_collector_wrap
tee.write('Output')
assert output_file.getvalue() == 'Output'
assert len(log_collector.calls['verbose']) == 1
assert src_filename in log_collector.calls['verbose'][0].args
log_collector.verbose.assert_called_once()
assert src_filename in log_collector.verbose.call_args[0]

# ... should appear when more data is written.
tee.write('\nMore output\n')
assert output_file.getvalue() == 'Output\nMore output\n'
assert len(log_collector.calls['verbose']) == 3
assert 'Output' in log_collector.calls['verbose'][1].args
assert 'More output' in log_collector.calls['verbose'][2].args
assert log_collector.verbose.call_count == 3
assert 'Output' in log_collector.verbose.call_args_list[1][0]
assert 'More output' in log_collector.verbose.call_args_list[2][0]


def test_multi_line(log_collector_wrap):
log_collector, src_filename, tee, output_file = log_collector_wrap
tee.write('first line\rsecond line\nthird line')
assert (output_file.getvalue() ==
'first line\rsecond line\nthird line')
verbose_calls = log_collector.calls['verbose']
assert len(verbose_calls) == 3
assert src_filename in verbose_calls[0].args
assert 'first line' in verbose_calls[1].args
assert 'second line' in verbose_calls[2].args
assert log_collector.verbose.call_count == 3
assert src_filename in log_collector.verbose.call_args_list[0][0]
assert 'first line' in log_collector.verbose.call_args_list[1][0]
assert 'second line' in log_collector.verbose.call_args_list[2][0]
assert tee.logger_buffer == 'third line'


Expand Down
6 changes: 3 additions & 3 deletions sphinx_gallery/tests/test_py_source_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ def test_get_docstring_and_rest(unicode_sample, tmpdir, monkeypatch):
def test_extract_file_config(content, file_conf, log_collector):
if file_conf is None:
assert sg.extract_file_config(content) == {}
assert len(log_collector.calls['warning']) == 1
assert '1foo' == log_collector.calls['warning'][0].args[2]
log_collector.warning.assert_called_once()
assert '1foo' == log_collector.warning.call_args[0][2]
else:
assert sg.extract_file_config(content) == file_conf
assert len(log_collector.calls['warning']) == 0
log_collector.warning.assert_not_called()


@pytest.mark.parametrize('contents, result', [
Expand Down
8 changes: 0 additions & 8 deletions sphinx_gallery/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,6 @@ def _replace_md5(fname_new, fname_old=None, method='move', mode='b'):
assert os.path.isfile(fname_old)


class Bunch(dict):
"""Dictionary-like object that exposes its keys as attributes."""

def __init__(self, **kwargs): # noqa: D102
dict.__init__(self, kwargs)
self.__dict__ = self


def _has_pypandoc():
"""Check if pypandoc package available."""
try:
Expand Down

0 comments on commit edf8a01

Please sign in to comment.