Skip to content

Commit

Permalink
Tests: Use pytest-regression for sphinx extension test
Browse files Browse the repository at this point in the history
The tests for the Sphinx extension for process specifications worked
using a direct comparison of the parsed XML file. Although this worked
fine, we have the `pytest-regressions` plugin for this which handles
this automatically, including a useful switch `--force-regen` to
regenerate the reference file if it is supposed to change.
  • Loading branch information
sphuber committed Nov 2, 2022
1 parent 9c54b73 commit 51c9939
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 51 deletions.
57 changes: 11 additions & 46 deletions tests/sphinxext/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,22 @@
# For further information please visit http://www.aiida.net #
###########################################################################
"""Pytest fixtures for AiiDA sphinx extension tests."""
import os
from pathlib import Path
import pathlib
import shutil
import sys
import xml.etree.ElementTree as ET

import pytest
from sphinx.testing.path import path as sphinx_path
from sphinx.testing.util import SphinxTestApp

SRC_DIR = Path(__file__).parent / 'sources'
WORKCHAIN_DIR = Path(__file__).parent / 'workchains'


@pytest.fixture
def reference_result():
"""Return reference results (for check)."""

def inner(name):
return os.path.join(os.path.dirname(__file__), 'reference_results', name)

return inner
SRC_DIR = pathlib.Path(__file__).parent / 'sources'
WORKCHAIN_DIR = pathlib.Path(__file__).parent / 'workchains'


class SphinxBuild:
"""Class for testing sphinx builds"""

def __init__(self, app: SphinxTestApp, src: Path):
def __init__(self, app: SphinxTestApp, src: pathlib.Path):
self.app = app
self.src = src

Expand All @@ -44,7 +32,7 @@ def build(self, assert_pass=True):
:param assert_pass: if True, assert that no warnings are raised during build"""
try:
sys.path.append(os.path.abspath(WORKCHAIN_DIR))
sys.path.append(str(WORKCHAIN_DIR.absolute()))
self.app.build()
finally:
sys.path.pop()
Expand All @@ -62,7 +50,7 @@ def warnings(self):

@property
def outdir(self):
return Path(self.app.outdir)
return pathlib.Path(self.app.outdir)


@pytest.fixture
Expand All @@ -78,33 +66,10 @@ def test_wc(sphinx_build_factory):
"""

def _func(src_folder, **kwargs):
shutil.copytree(SRC_DIR / src_folder, tmp_path / src_folder)
app = make_app(srcdir=sphinx_path(os.path.abspath((tmp_path / src_folder))), **kwargs)
return SphinxBuild(app, tmp_path / src_folder)
filepath_source = SRC_DIR / src_folder
filepath_target = tmp_path / src_folder
shutil.copytree(filepath_source, filepath_target)
app = make_app(srcdir=sphinx_path(filepath_target.absolute()), **kwargs)
return SphinxBuild(app, filepath_target)

yield _func


@pytest.fixture
def xml_equal():
"""Check whether output and reference XML are identical."""

def inner(test_file, reference_file):
if not os.path.isfile(reference_file):
shutil.copyfile(test_file, reference_file)
raise ValueError('Reference file does not exist!')
try:
assert _flatten_xml(test_file) == _flatten_xml(reference_file)
except AssertionError:
print(Path(test_file.read_text()))
raise

return inner


def _flatten_xml(filename):
"""Flatten XML to list of tuples of tag and dictionary."""
return [(el.tag, {k: v
for k, v in el.attrib.items()
if k not in ['source']}, el.text)
for el in ET.parse(filename).iter()]
11 changes: 8 additions & 3 deletions tests/sphinxext/test_workchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,24 @@
# For further information please visit http://www.aiida.net #
###########################################################################
"""Tests for the AiiDA workchain Sphinx directive."""
import re

import pytest


def test_workchain_build(sphinx_build_factory, reference_result, xml_equal):
def test_workchain_build(sphinx_build_factory, file_regression):
"""Test building sphinx documentation for WorkChain.
Builds Sphinx documentation for workchain and compares against expected XML result.
"""
sphinx_build = sphinx_build_factory('workchain', buildername='xml')
sphinx_build.build(assert_pass=True)

index_file = sphinx_build.outdir / 'index.xml'
xml_equal(index_file, reference_result('workchain.xml'))
# Need to remove the ``source`` attribute of the ``document`` tag as that is variable.
output = (sphinx_build.outdir / 'index.xml').read_text()
output = re.sub(r'source=".*"', '', output)

file_regression.check(output, encoding='utf-8', extension='.xml')


def test_broken_workchain_build(sphinx_build_factory):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE document PUBLIC "+/IDN docutils.sourceforge.net/DTD Docutils Generic/EN/XML" "http:/docutils.sourceforge.net/docs/ref/docutils.dtd">
<!DOCTYPE document PUBLIC "+//IDN docutils.sourceforge.net//DTD Docutils Generic//EN//XML" "http://docutils.sourceforge.net/docs/ref/docutils.dtd">
<!-- Generated by Docutils 0.16 -->
<document source="/private/var/folders/t2/xbl15_3n4tsb1vr_ccmmtmbr0000gn/T/pytest-of-chrisjsewell/pytest-187/test_workchain_build0/workchain/index.rst" xmlns:c="https:/www.sphinx-doc.org/" xmlns:changeset="https:/www.sphinx-doc.org/" xmlns:citation="https:/www.sphinx-doc.org/" xmlns:cpp="https:/www.sphinx-doc.org/" xmlns:index="https:/www.sphinx-doc.org/" xmlns:js="https:/www.sphinx-doc.org/" xmlns:math="https:/www.sphinx-doc.org/" xmlns:py="https:/www.sphinx-doc.org/" xmlns:rst="https:/www.sphinx-doc.org/" xmlns:std="https:/www.sphinx-doc.org/">
<document >
<section ids="sphinx-aiida-demo" names="sphinx-aiida\ demo">
<title>sphinx-aiida demo</title>
<paragraph>This is a demo documentation to show off the features of the <literal>sphinx-aiida</literal> extension.</paragraph>
Expand Down

0 comments on commit 51c9939

Please sign in to comment.