51 lines
1.9 KiB
Python
51 lines
1.9 KiB
Python
"""Golden-file comparison, with regeneration that has to be asked for.
|
|
|
|
A golden test is only worth its file if updating that file is a deliberate
|
|
act. The failure mode this module exists to prevent is the silent
|
|
self-heal: a comparator that rewrites the reference whenever it disagrees
|
|
turns every golden into a mirror and every golden test into a no-op. So the
|
|
rewrite lives behind the ``--update-golden`` flag, and the flag defaults off.
|
|
|
|
The update flag is a parameter rather than something this module reads off
|
|
the pytest config, so the rewrite path is reachable from an ordinary test
|
|
without running pytest inside pytest. `tests/conftest.py` binds the flag to
|
|
the `golden` fixture for callers who want the wiring instead.
|
|
"""
|
|
|
|
import difflib
|
|
import os
|
|
|
|
|
|
def assert_golden(path, actual, update=False):
|
|
"""Compare ``actual`` against the golden file at ``path``.
|
|
|
|
With ``update`` the file is rewritten and nothing is asserted. Without it,
|
|
a missing golden and a differing golden both raise, and the message
|
|
carries a unified diff -- "golden mismatch" on its own sends the reader
|
|
back to the file to work out what moved.
|
|
"""
|
|
if update:
|
|
with open(path, "w", encoding="utf-8") as handle:
|
|
handle.write(actual)
|
|
return
|
|
|
|
if not os.path.exists(path):
|
|
raise AssertionError(
|
|
"golden %r does not exist yet. Re-run with --update-golden to "
|
|
"create it, having first read the output you are blessing." % path
|
|
)
|
|
|
|
with open(path, "r", encoding="utf-8") as handle:
|
|
expected = handle.read()
|
|
if expected == actual:
|
|
return
|
|
|
|
diff = "".join(
|
|
difflib.unified_diff(
|
|
expected.splitlines(keepends=True),
|
|
actual.splitlines(keepends=True),
|
|
fromfile="golden: %s" % path,
|
|
tofile="actual",
|
|
)
|
|
)
|
|
raise AssertionError("golden %r does not match actual output:\n%s" % (path, diff))
|