# The summarisers turn tool chatter into one SHORT line each: the whole point is that a
# stage occupies one row of the terminal, so anything long enough to wrap defeats it.
test_eq(_version_summary("Old version: 0.0.185\nNew version: 0.0.186\n"), ["0.0.185 -> 0.0.186"])
_TESTOUT = "Success.\n" + "".join(f"{i:02d}_nb.ipynb: 0 secs\n" for i in range(26))
test_eq(_test_summary(_TESTOUT), ["26 notebooks, all under 1s"])
test_eq(_test_summary(_TESTOUT + "slow.ipynb: 12.5 secs\n"), ["27 notebooks, slowest slow.ipynb 12.5s"])
test_eq(_test_summary("Success.\n"), ["Success."])
_PUSH = ("Enumerating objects: 13, done.\n"
"Compressing objects: 100% (6/6), done.\n"
"Writing objects: 100% (7/7), 5.29 KiB | 2.65 MiB/s, done.\n"
"To github.com:bthek1/bthek1_blog.git\n"
" 797ca71..76bea07 main -> main\n")
test_eq(_push_summary(_PUSH), ["797ca71..76bea07 main -> main", "5.29 KiB"])
test_eq(_push_summary("Everything up-to-date\n"), ["everything up-to-date"])
test_eq(_commit_summary("[main 76bea07] update x\n 3 files changed, 30 insertions(+), 18 deletions(-)\n"),
["main 76bea07 3 files +30 -18"])
test_eq(_commit_summary("[main abc1234] x\n 1 file changed, 2 insertions(+)\n"),
["main abc1234 1 file +2 -0"])
# Every summariser has to fit the detail column, or the one-line grid wraps.
for _s in (_test_summary(_TESTOUT) + _push_summary(_PUSH) + _version_summary("Old version: 0.0.1\nNew version: 0.0.2\n")):
assert len(_s) <= _W_DETAIL, f"{_s!r} is {len(_s)} chars, over {_W_DETAIL}"
# Staged paths are trimmed to fit rather than wrapped, and the remainder is counted.
test_eq(_staged_summary(" M a.py\n M b.py\n"), ["2 staged: a.py, b.py"])
_many = _staged_summary("".join(f" M some/directory/file{i}.py\n" for i in range(9)))[0]
assert _many.startswith("9 staged:") and _many.endswith(("+7", "+8")), _many
assert len(_many) <= _W_DETAIL, _many
test_eq(_staged_summary(""), [])
# Without -m the subject used to be the porcelain blob itself. Mixed codes fall back to "update".
test_eq(_auto_msg(" M career/pipeline.md\n M career/companies.md\n"),
"update career/pipeline.md, career/companies.md")
test_eq(_auto_msg("A a.py\nA b.py\nA c.py\nA d.py\n"), "add a.py, b.py, c.py and 1 more")
test_eq(_auto_msg("R old.py -> new.py\n"), "rename new.py")
test_eq(_auto_msg(" M a.py\nA b.py\n"), "update a.py, b.py")
test_eq(_auto_msg(""), "update")
# A non-zero exit has to reach `_step`, or the green OK is a lie. Note `git rev-parse
# --anything` exits 0 INSIDE a repo, so an unknown subcommand is the portable failure.
try:
_run("git", "not-a-real-subcommand")
assert False, "a failing command must raise"
except StepFailed as e:
assert e.code != 0 and e.output.strip()
# `_quiet` must swallow SUBPROCESS output too. redirect_stdout alone does not: a child
# writing to fd 1 goes straight past it, which is how pandoc used to leak 16 lines into
# the middle of a run.
with _quiet() as _buf:
print("python-level")
subprocess.run([sys.executable, "-c", "print('subprocess-level')"], check=True)
_got = _buf.getvalue()
assert "python-level" in _got and "subprocess-level" in _got, _got
# One stage, one line: label, outcome, duration and detail all on the same row.
with _step(1, 2, "demo") as d: d += ["one thing"]
_skip(2, 2, "demo skipped", "nothing to do")
try:
with _step(2, 2, "demo fail"): raise StepFailed("git push", 128, "fatal: no upstream")
except StepFailed: pass
# The grid has to hold inside 88 columns. Rendered for real and measured, because the
# widths are the whole reason the one-line form is readable.
# A console pinned to the target width, so the assertion measures the design and not
# whatever width the test runner happens to have.
_saved_console, console = console, Console(width=_WIDTH, no_color=True)
with console.capture() as _cap:
with _step(1, 6, "bump version (part 2)") as d: d += _version_summary("Old version: 0.3.67\nNew version: 0.3.68\n")
with _step(3, 6, "nbdev_test") as d: d += _test_summary(_TESTOUT + "slow.ipynb: 12.5 secs\n")
with _step(1, 3, "git add") as d: d += _staged_summary(" M README.md\n M nbdevAuto/__init__.py\n M nbs/index.ipynb\n")
with _step(3, 3, "git push") as d: d += _push_summary(_PUSH)
_skip(2, 3, "git commit", "nothing staged")
console = _saved_console
_rendered = [re.sub(r"\x1b\[[0-9;]*m", "", l) for l in _cap.get().splitlines() if l.strip()]
test_eq(len(_rendered), 5) # five stages, five lines
for _l in _rendered: assert len(_l) <= _WIDTH, f"{len(_l)} cols: {_l!r}"
# and the outcome really is on the same row as the label
assert all(any(w in l for w in ("OK", "SKIP")) for l in _rendered), _rendered