diff options
Diffstat (limited to 'tests/conftest.py')
-rw-r--r-- | tests/conftest.py | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..9a021169e --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,231 @@ +# -*- coding: utf-8 -*- +import sys +import subprocess + +import pytest +from six import StringIO, string_types + +from util import SphinxTestApp, path + + +@pytest.fixture +def app_params(request): + """ + parameters that is specified by 'pytest.mark.sphinx' for + sphinx.application.Sphinx initialization + """ + markers = request.node.get_marker("sphinx") + pargs = {} + kwargs = {} + + if markers is not None: + # to avoid stacking positional args + for info in reversed(list(markers)): + for i, a in enumerate(info.args): + pargs[i] = a + kwargs.update(info.kwargs) + + args = [pargs[i] for i in sorted(pargs.keys())] + return args, kwargs + + +@pytest.fixture +def test_params(request): + """ + test parameters that is specified by 'pytest.mark.testenv' + + :param bool build: + If True, 'app' fixture will be build before test function is called. + Default is False. + :param Union[str, bool, None] specific_srcdir: + If True, testroot directory will be copied into + '<TMPDIR>/<TEST FUNCTION NAME>'. + If string is specified, it copied into '<TMPDIR>/<THE STRING>'. + You can used this feature for providing special crafted source + directory. Also you can used for sharing source directory for + parametrized testing and/or inter test functions. Default is None. + :param Union[str, bool, None] shared_result: + If True, app._status and app._warning objects will be shared in the + parametrized test functions. If string is specified, the objects will + be shred in the test functions that have same 'shared_result' value. + If you don't specify specific_srcdir, this option override + specific_srcdir param by 'shared_result' value. Default is None. + """ + env = request.node.get_marker('testenv') + kwargs = env.kwargs if env else {} + result = { + 'build': False, # pre build in fixture + 'specific_srcdir': None, + 'shared_result': None, + } + result.update(kwargs) + + if (result['shared_result'] and + not isinstance(result['shared_result'], string_types)): + r = result['shared_result'] = request.node.originalname or request.node.name + + if result['shared_result'] and not result['specific_srcdir']: + result['specific_srcdir'] = result['shared_result'] + + if (result['specific_srcdir'] and + not isinstance(result['specific_srcdir'], string_types)): + result['specific_srcdir'] = request.node.originalname or request.node.name + + return result + + +@pytest.fixture(scope='function') +def app(test_params, app_params, make_app, shared_result): + """ + provides sphinx.application.Sphinx object + """ + args, kwargs = app_params + if test_params['specific_srcdir'] and 'srcdir' not in kwargs: + kwargs['srcdir'] = test_params['specific_srcdir'] + + if test_params['shared_result']: + restore = shared_result.restore(test_params['shared_result']) + kwargs.update(restore) + + app_ = make_app(*args, **kwargs) + + if test_params['build']: + # if listdir is not empty, we can use built cache + if not app_.outdir.listdir(): + app_.build() + yield app_ + + if test_params['shared_result']: + shared_result.store(test_params['shared_result'], app_) + + +@pytest.fixture(scope='function') +def status(app): + """ + compat for testing with previous @with_app decorator + """ + return app._status + + +@pytest.fixture(scope='function') +def warning(app): + """ + compat for testing with previous @with_app decorator + """ + return app._warning + + +@pytest.fixture() +def make_app(): + """ + provides make_app function to initialize SphinxTestApp instance. + if you want to initialize 'app' in your test function. please use this + instead of using SphinxTestApp class directory. + """ + apps = [] + syspath = sys.path[:] + + def make(*args, **kwargs): + status, warning = StringIO(), StringIO() + kwargs.setdefault('status', status) + kwargs.setdefault('warning', warning) + app_ = SphinxTestApp(*args, **kwargs) + apps.append(app_) + return app_ + yield make + + sys.path[:] = syspath + for app_ in apps: + app_.cleanup() + + +class SharedResult(object): + cache = {} + + def store(self, key, app_): + if key in self.cache: + return + data = { + 'status': app_._status.getvalue(), + 'warning': app_._warning.getvalue(), + } + self.cache[key] = data + + def restore(self, key): + if key not in self.cache: + return {} + data = self.cache[key] + return { + 'status': StringIO(data['status']), + 'warning': StringIO(data['warning']), + } + + +@pytest.fixture +def shared_result(): + return SharedResult() + + +@pytest.fixture(scope='module', autouse=True) +def _shared_result_cache(): + SharedResult.cache.clear() + + +@pytest.fixture +def if_graphviz_found(app): + """ + The test will be skipped when using 'if_graphviz_found' fixture and graphviz + dot command is not found. + """ + graphviz_dot = getattr(app.config, 'graphviz_dot', '') + try: + if graphviz_dot: + dot = subprocess.Popen([graphviz_dot, '-V'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) # show version + dot.communicate() + return + except OSError: # No such file or directory + pass + + pytest.skip('graphviz "dot" is not available') + + +@pytest.fixture +def tempdir(tmpdir): + """ + temporary directory that wrapped with `path` class. + this fixture is for compat with old test implementation. + """ + return path(tmpdir) + + +def pytest_addoption(parser): + """ + the test that have pytest.mark.env('foobar') will be skipped when + '-S foobar' command-line option is provided. + """ + parser.addoption("-S", action="store", metavar="NAME", + help="skip tests matching the environment NAME.") + + +def pytest_configure(config): + """ + the test that have pytest.mark.env('foobar') will be skipped when + '-S foobar' command-line option is provided. + """ + # register an additional marker + config.addinivalue_line("markers", + "env(name): mark test to run only on named environment") + + +def pytest_runtest_setup(item): + """ + the test that have pytest.mark.env('foobar') will be skipped when + '-S foobar' command-line option is provided. + """ + envmarker = item.get_marker("env") + if envmarker is not None: + envname = envmarker.args[0] + if envname == item.config.getoption("-S"): + pytest.skip("skip test %r" % envname) |