mirror of
https://github.com/harvard-edge/cs249r_book.git
synced 2026-05-07 02:03:55 -05:00
Pyproject.toml with Typer+Rich+Pydantic+PyYAML deps. Console entry point 'vault' → vault_cli.main:app. Smoke tests cover --version, --help, and the exit-code taxonomy regression guard. Module layout: src/vault_cli/__init__.py src/vault_cli/_version.py — single source for __version__ src/vault_cli/exit_codes.py — stable IntEnum taxonomy (§4.6) src/vault_cli/main.py — Typer app, --version flag tests/test_smoke.py — 4 tests, all green in 0.04s Subcommands land incrementally from Phase 1 per ARCHITECTURE.md §14. Python ≥3.12 required; CI pins 3.12 for hash stability. Milestone gate: pip install -e interviews/vault-cli/[dev] && vault --version passes. Tests green. Ready for Phase 1.
50 lines
1.6 KiB
Python
50 lines
1.6 KiB
Python
"""Phase 0 smoke tests.
|
|
|
|
These assert the package imports, exposes a version, and the Typer app's
|
|
``--version`` flag returns cleanly. They are intentionally minimal —
|
|
per-command contract tests arrive in Phase 1.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typer.testing import CliRunner
|
|
|
|
from vault_cli import __version__
|
|
from vault_cli.exit_codes import ExitCode
|
|
from vault_cli.main import app
|
|
|
|
|
|
def test_package_exposes_version() -> None:
|
|
"""__version__ matches semver-ish shape."""
|
|
parts = __version__.split(".")
|
|
assert len(parts) == 3
|
|
assert all(p.isdigit() for p in parts)
|
|
|
|
|
|
def test_cli_version_flag() -> None:
|
|
"""``vault --version`` prints the version and exits 0."""
|
|
runner = CliRunner()
|
|
result = runner.invoke(app, ["--version"])
|
|
assert result.exit_code == ExitCode.SUCCESS
|
|
assert "vault" in result.stdout
|
|
assert __version__ in result.stdout
|
|
|
|
|
|
def test_cli_no_args_shows_help() -> None:
|
|
"""Bare ``vault`` invocation shows help and exits non-zero (Typer default)."""
|
|
runner = CliRunner()
|
|
result = runner.invoke(app, [])
|
|
# Typer exits 2 when no_args_is_help is set and no args were passed.
|
|
assert result.exit_code != ExitCode.SUCCESS
|
|
assert "Usage" in result.stdout or "Usage" in result.output
|
|
|
|
|
|
def test_exit_code_taxonomy_is_stable() -> None:
|
|
"""Regression guard: renumbering exit codes breaks scripts pinned to them."""
|
|
assert ExitCode.SUCCESS == 0
|
|
assert ExitCode.VALIDATION_FAILURE == 1
|
|
assert ExitCode.USAGE_ERROR == 2
|
|
assert ExitCode.IO_ERROR == 3
|
|
assert ExitCode.NETWORK_ERROR == 4
|
|
assert ExitCode.USER_ABORTED == 5
|