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
|
from __future__ import annotations
import contextlib
import os
import textwrap
from functools import wraps
from tempfile import TemporaryDirectory
import markdown
from mkdocs import utils
from mkdocs.config.defaults import MkDocsConfig
def dedent(text):
return textwrap.dedent(text).strip()
def get_markdown_toc(markdown_source):
"""Return TOC generated by Markdown parser from Markdown source text."""
md = markdown.Markdown(extensions=['toc'])
md.convert(markdown_source)
return md.toc_tokens
def load_config(config_file_path: str | None = None, **cfg) -> MkDocsConfig:
"""Helper to build a simple config for testing."""
path_base = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'integration', 'minimal')
if 'site_name' not in cfg:
cfg['site_name'] = 'Example'
if 'docs_dir' not in cfg:
# Point to an actual dir to avoid a 'does not exist' error on validation.
cfg['docs_dir'] = os.path.join(path_base, 'docs')
if 'plugins' not in cfg:
cfg['plugins'] = []
conf = MkDocsConfig(config_file_path=config_file_path or os.path.join(path_base, 'mkdocs.yml'))
conf.load_dict(cfg)
errors_warnings = conf.validate()
assert errors_warnings == ([], []), errors_warnings
return conf
def tempdir(files=None, **kw):
"""
A decorator for building a temporary directory with prepopulated files.
The temporary directory and files are created just before the wrapped function is called and are destroyed
immediately after the wrapped function returns.
The `files` keyword should be a dict of file paths as keys and strings of file content as values.
If `files` is a list, then each item is assumed to be a path of an empty file. All other
keywords are passed to `tempfile.TemporaryDirectory` to create the parent directory.
In the following example, two files are created in the temporary directory and then are destroyed when
the function exits:
@tempdir(files={
'foo.txt': 'foo content',
'bar.txt': 'bar content'
})
def example(self, tdir):
assert os.path.isfile(os.path.join(tdir, 'foo.txt'))
pth = os.path.join(tdir, 'bar.txt')
assert os.path.isfile(pth)
with open(pth, 'r', encoding='utf-8') as f:
assert f.read() == 'bar content'
"""
files = {f: '' for f in files} if isinstance(files, (list, tuple)) else files or {}
kw['prefix'] = 'mkdocs_test-' + kw.get('prefix', '')
def decorator(fn):
@wraps(fn)
def wrapper(self, *args):
with TemporaryDirectory(**kw) as td:
for path, content in files.items():
pth = os.path.join(td, path)
utils.write_file(content.encode(encoding='utf-8'), pth)
return fn(self, td, *args)
return wrapper
return decorator
@contextlib.contextmanager
def change_dir(path):
old_cwd = os.getcwd()
os.chdir(path)
try:
yield
finally:
os.chdir(old_cwd)
class PathAssertionMixin:
"""
Assertion methods for testing paths.
Each method accepts one or more strings, which are first joined using os.path.join.
"""
def assertPathsEqual(self, a, b, msg=None):
self.assertEqual(a.replace(os.sep, '/'), b.replace(os.sep, '/'), msg=msg)
def assertPathExists(self, *parts):
path = os.path.join(*parts)
if not os.path.exists(path):
msg = self._formatMessage(None, f"The path '{path}' does not exist")
raise self.failureException(msg)
def assertPathNotExists(self, *parts):
path = os.path.join(*parts)
if os.path.exists(path):
msg = self._formatMessage(None, f"The path '{path}' does exist")
raise self.failureException(msg)
def assertPathIsFile(self, *parts):
path = os.path.join(*parts)
if not os.path.isfile(path):
msg = self._formatMessage(None, f"The path '{path}' is not a file that exists")
raise self.failureException(msg)
def assertPathIsDir(self, *parts):
path = os.path.join(*parts)
if not os.path.isdir(path):
msg = self._formatMessage(None, f"The path '{path}' is not a directory that exists")
raise self.failureException(msg)
|