-
-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit adds a new optional functional test exercising the syntactic validity of our front-facing "README.rst" file conditionally dependent on "docutils", the reference reStructuredText (reST) parser. This test is sufficiently expensive that we will probably *NOT* enable it under continuous integration (CI), as doing so would begin exhausting our precious GitHub Actions CI minutes. (*Extra extravagance of racy vagrancy!*)
- Loading branch information
Showing
12 changed files
with
346 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
.. # ------------------( SYNOPSIS )------------------ | ||
======================== | ||
Project Functional Tests | ||
======================== | ||
|
||
This subpackage provides *all* pytest_-based **functional tests** (i.e., | ||
callables exercising the functional behaviour of this project *without* regard | ||
to this project's public API) for this project. | ||
|
||
.. # ------------------( LINKS )------------------ | ||
.. _pytest: | ||
https://docs.pytest.org |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
#!/usr/bin/env python3 | ||
# --------------------( LICENSE )-------------------- | ||
# Copyright 2014-2021 by Cecil Curry. | ||
# See "LICENSE" for further details. | ||
|
||
''' | ||
**Project ``README.rst`` functional tests.** | ||
This submodule functionally tests the syntactic validity of this project's | ||
top-level ``README.rst`` file. | ||
''' | ||
|
||
# ....................{ IMPORTS }.................... | ||
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
# WARNING: To raise human-readable test errors, avoid importing from | ||
# package-specific submodules at module scope. | ||
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
from beartype_test.util.mark.pytskip import skip_unless_package | ||
|
||
# ....................{ TESTS }.................... | ||
#FIXME: Consider submitting as a StackOverflow post. Dis iz l33t, yo! | ||
|
||
# If the third-party "docutils" package satisfying this minimum version is | ||
# unavailable, skip this test. Note that: | ||
# | ||
# * "docutils" is the reference standard for parsing reStructuredText (reST). | ||
# Unsurprisingly, even Sphinx parses reST with "docutils". | ||
# * This test makes assumptions about the "docutils" public API satisfied | ||
# *ONLY* by this minimum version. | ||
@skip_unless_package(package_name='docutils', minimum_version='0.15') | ||
def test_doc_readme(monkeypatch) -> None: | ||
''' | ||
Functional test testing the syntactic validity of this project's top-level | ||
``README.rst`` file by monkeypatching the public :mod:`docutils` singleton | ||
responsible for emitting warnings and errors to instead convert these | ||
warnings and errors into a test failure. | ||
Parameters | ||
---------- | ||
monkeypatch : MonkeyPatch | ||
Builtin fixture object permitting object attributes to be safely | ||
modified for the duration of this unit test. | ||
''' | ||
|
||
# Defer heavyweight imports. | ||
from docutils.core import publish_parts | ||
from docutils.utils import Reporter | ||
from beartype_test.util.pytpath import get_repo_readme_file | ||
|
||
# Decoded plaintext contents of this project's readme file as a string. | ||
README_CONTENTS = get_repo_readme_file().read_text() | ||
|
||
# List of all warning and error messages emitted by "docutils" during | ||
# parsing of this project's top-level "README.rst" file. | ||
system_messages = [] | ||
|
||
# Original non-monkey-patched method of the public :mod:`docutils` | ||
# singleton emitting warnings and errors *BEFORE* patching this method. | ||
system_message_unpatched = Reporter.system_message | ||
|
||
def system_message_patched(reporter, level, message, *args, **kwargs): | ||
''' | ||
Method of the public :mod:`docutils` singleton emitting warnings and | ||
errors redefined as a closure collecting these warnings and errors into | ||
the local list defined above. | ||
''' | ||
|
||
# Call this non-monkey-patched method with all passed parameters as is. | ||
message_result = system_message_unpatched( | ||
reporter, level, message, *args, **kwargs) | ||
|
||
# If this message is either a warning *OR* error, append this message | ||
# to the above list. | ||
if level >= reporter.WARNING_LEVEL: | ||
system_messages.append(message) | ||
|
||
# Return value returned by the above call as is. | ||
return message_result | ||
|
||
# Temporarily install this monkey-patch for the duration of this test. | ||
monkeypatch.setattr( | ||
Reporter, | ||
name='system_message', | ||
value=system_message_patched, | ||
) | ||
|
||
# Attempt to render this "README.rst" file as reST, implicitly invoking | ||
# this monkey-patch. | ||
publish_parts(source=README_CONTENTS, writer_name='html4css1') | ||
|
||
# Assert "docutils" to have emitted *NO* warnings or errors. | ||
assert not system_messages |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
.. # ------------------( SYNOPSIS )------------------ | ||
================== | ||
Project Unit Tests | ||
================== | ||
|
||
This subpackage provides *all* pytest_-based **unit tests** (i.e., callables | ||
collectively exercising this project's public API but individually exercising | ||
only a small subset of that API referred to as a "unit") for this project. | ||
|
||
.. # ------------------( LINKS )------------------ | ||
.. _pytest: | ||
https://docs.pytest.org |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
.. # ------------------( SYNOPSIS )------------------ | ||
====================== | ||
Project Test Utilities | ||
====================== | ||
|
||
This subpackage provides pytest_-based **utilities** (i.e., general-purpose | ||
lower-level pytest_ fixtures and related functions leveraged by higher-level | ||
unit and functional tests) for this project's test suite. | ||
|
||
.. # ------------------( LINKS )------------------ | ||
.. _pytest: | ||
https://docs.pytest.org |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
#!/usr/bin/env python3 | ||
# --------------------( LICENSE )-------------------- | ||
# Copyright 2014-2021 by Cecil Curry. | ||
# See "LICENSE" for further details. | ||
|
||
''' | ||
**:mod:`pytest` **path** (i.e., directory and file) utilities.** | ||
''' | ||
|
||
# ....................{ IMPORTS }.................... | ||
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
# WARNING: To raise human-readable test errors, avoid importing from | ||
# package-specific submodules at module scope. | ||
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
from pathlib import Path | ||
from beartype_test.util.pytroar import BeartypeTestPathException | ||
|
||
# ....................{ GETTERS }.................... | ||
def get_repo_dir() -> Path: | ||
''' | ||
Concrete platform-agnostic :mod:`Path` object encapsulating this absolute | ||
dirname of this project's **repository directory** (i.e., directory | ||
containing both a ``.git/`` subdirectory and a subdirectory providing this | ||
project's package) if found *or* raise an exception otherwise. | ||
Returns | ||
---------- | ||
Path | ||
Concrete platform-agnostic object encapsulating the absolute dirname of | ||
this project's repository directory. | ||
Raises | ||
---------- | ||
BeartypeTestPathException | ||
If this path exists but is either: | ||
* *Not* a directory. | ||
* A directory *not* satisfying the expected filesystem structure. | ||
FileNotFoundError | ||
If this path does *not* exist. | ||
RuntimeError | ||
If this path exists but whose resolution to a physical path requires | ||
resolving one or more cyclic symbolic links inducing an infinite loop. | ||
''' | ||
# print(f'current module paths: {__package__} [{__file__}]') | ||
|
||
# Concrete platform-agnostic path encapsulating the absolute filename of | ||
# current module. | ||
MODULE_FILE = Path(__file__) | ||
|
||
# Concrete platform-agnostic path encapsulating the absolute dirname of the | ||
# package defining the current module. | ||
MODULE_PACKAGE_DIR = MODULE_FILE.parent | ||
|
||
# Concrete platform-agnostic path encapsulating the relative dirname of | ||
# this project's repository directory relative to the dirname of the | ||
# package defining the current module. | ||
# | ||
# Note that this path has *NOT* been validated to exist yet. | ||
REPO_DIR_UNRESOLVED = MODULE_PACKAGE_DIR.joinpath('../..') | ||
|
||
# Canonicalize this relative dirname into an absolute dirname if this path | ||
# exists *OR* raise a "FileNotFoundError" or "RuntimeError" exception | ||
# otherwise. | ||
REPO_DIR = REPO_DIR_UNRESOLVED.resolve() | ||
|
||
# If this path is *NOT* a directory, raise an exception. | ||
if not REPO_DIR.is_dir(): | ||
raise BeartypeTestPathException( | ||
f'Project repository path {REPO_DIR} not directory.') | ||
# Else, this path is a directory. | ||
|
||
# Concrete platform-agnostic path encapsulating the absolute dirname | ||
# of the ".git/" subdirectory of this project's repository directory. | ||
REPO_GIT_DIR = REPO_DIR.joinpath('.git') | ||
|
||
# If this subdirectory either does *NOT* exist or is *NOT* a directory, | ||
# raise an exception. | ||
if not REPO_GIT_DIR.is_dir(): | ||
raise BeartypeTestPathException( | ||
f'Project repository git subdirectory {REPO_GIT_DIR} not found.') | ||
# Else, this subdirectory exists. | ||
|
||
# Return this path. | ||
return REPO_DIR | ||
|
||
|
||
def get_repo_readme_file() -> Path: | ||
''' | ||
Concrete platform-agnostic :mod:`Path` object encapsulating the absolute | ||
filename of this project's **readme file** (i.e., this project's | ||
front-facing ``README.rst`` file) if found *or* raise an exception | ||
otherwise. | ||
Note that the :meth:`Path.read_text` method of this object trivially yields | ||
the decoded plaintext contents of this file as a string. | ||
Returns | ||
---------- | ||
Path | ||
Concrete platform-agnostic object encapsulating the absolute filename | ||
of this project's readme file. | ||
Raises | ||
---------- | ||
BeartypeTestPathException | ||
If this path exists but is *NOT* a file. | ||
FileNotFoundError | ||
If this path does *not* exist. | ||
RuntimeError | ||
If this path exists but whose resolution to a physical path requires | ||
resolving one or more cyclic symbolic links inducing an infinite loop. | ||
''' | ||
|
||
# Concrete platform-agnostic path encapsulating this project's | ||
# repository directory. | ||
REPO_DIR = get_repo_dir() | ||
|
||
# Concrete platform-agnostic path encapsulating the absolute filename of | ||
# this project's readme file. | ||
REPO_README_FILE = REPO_DIR.joinpath('README.rst') | ||
|
||
# If this file either does *NOT* exist or is *NOT* a file, raise an | ||
# exception. | ||
if not REPO_README_FILE.is_file(): | ||
raise BeartypeTestPathException( | ||
f'Project repository readme file {REPO_README_FILE} not found.') | ||
# Else, this file exists. | ||
|
||
# Return this path. | ||
return REPO_README_FILE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.