mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 18:47:04 +01:00
Some checks failed
dependency freshness / dependencies on newest stable (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Has been cancelled
Python tests / test (push) Has been cancelled
repo-contract / repo contract (push) Has been cancelled
Shell tests / shell-tests (push) Has been cancelled
Shell tests / lib-tests (push) Has been cancelled
Shell tests / arch-tests (push) Has been cancelled
Engine, fixtures and reference solutions moved to kuhyx/utils sql_drills (tag sql-drills-v0.1.0); the CLI keeps its commands. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WzxdWYGW5NZL5uVpnqmNKo
133 lines
3.8 KiB
Python
133 lines
3.8 KiB
Python
"""CLI wiring over the shared package: subcommands, exit codes, output."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
import sql_drills as sd
|
|
|
|
from python_pkg.sql_drills import __main__ as cli
|
|
|
|
|
|
def _result(
|
|
*,
|
|
match: bool,
|
|
ok: bool = True,
|
|
error: str | None = None,
|
|
diff: list[sd.CellDiff] | None = None,
|
|
) -> sd.RunResult:
|
|
return sd.RunResult(
|
|
ok=ok,
|
|
error=error,
|
|
columns=[],
|
|
rows=[["a"]],
|
|
expected_rows=[["b"]],
|
|
match=match,
|
|
cell_diff=diff or [],
|
|
)
|
|
|
|
|
|
def _sql(tmp_path: Path) -> str:
|
|
query = tmp_path / "q.sql"
|
|
query.write_text("SELECT 1;")
|
|
return str(query)
|
|
|
|
|
|
def test_list_prints_ids_and_titles(capsys: pytest.CaptureFixture[str]) -> None:
|
|
assert cli.main(["list"]) == 0
|
|
out = capsys.readouterr().out
|
|
assert "01_" in out
|
|
assert len(out.strip().splitlines()) >= 10
|
|
|
|
|
|
def test_show_prints_task_and_expected_sample(
|
|
capsys: pytest.CaptureFixture[str],
|
|
) -> None:
|
|
assert cli.main(["show", "01"]) == 0
|
|
out = capsys.readouterr().out
|
|
assert "CREATE TABLE" in out
|
|
assert "## Expected output (sample)" in out
|
|
|
|
|
|
def test_show_predict_drill_prints_the_query(
|
|
capsys: pytest.CaptureFixture[str],
|
|
) -> None:
|
|
assert cli.main(["show", "t03"]) == 0
|
|
out = capsys.readouterr().out
|
|
assert "## Query to predict" in out
|
|
assert "LEFT JOIN" in out
|
|
|
|
|
|
def test_show_unknown_drill_exit_2(capsys: pytest.CaptureFixture[str]) -> None:
|
|
assert cli.main(["show", "zzz"]) == 2
|
|
assert "unknown drill" in capsys.readouterr().err
|
|
|
|
|
|
def test_start_and_stop_call_engine(capsys: pytest.CaptureFixture[str]) -> None:
|
|
with (
|
|
patch.object(sd, "ensure_running") as start,
|
|
patch.object(sd, "stop") as stop,
|
|
):
|
|
assert cli.main(["start"]) == 0
|
|
assert cli.main(["stop"]) == 0
|
|
start.assert_called_once_with()
|
|
stop.assert_called_once_with()
|
|
assert "ready" in capsys.readouterr().out
|
|
|
|
|
|
def test_engine_error_is_exit_2(capsys: pytest.CaptureFixture[str]) -> None:
|
|
with patch.object(sd, "ensure_running", side_effect=sd.EngineError("boom")):
|
|
assert cli.main(["start"]) == 2
|
|
assert "boom" in capsys.readouterr().err
|
|
|
|
|
|
def test_check_pass_is_exit_0(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
with patch.object(sd, "run", return_value=_result(match=True)):
|
|
assert cli.main(["check", "01", _sql(tmp_path)]) == 0
|
|
assert "PASS 01" in capsys.readouterr().out
|
|
|
|
|
|
def test_check_fail_prints_cell_diff_exit_1(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
res = _result(match=False, diff=[(0, 1, "x", "y")])
|
|
with patch.object(sd, "run", return_value=res):
|
|
assert cli.main(["check", "01", _sql(tmp_path)]) == 1
|
|
out = capsys.readouterr().out
|
|
assert "FAIL 01" in out
|
|
assert "line 1 cell 2: expected 'x', actual 'y'" in out
|
|
|
|
|
|
def test_check_sql_error_is_exit_2(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
res = _result(match=False, ok=False, error="ERROR 1064")
|
|
with patch.object(sd, "run", return_value=res):
|
|
assert cli.main(["check", "01", _sql(tmp_path)]) == 2
|
|
assert "ERROR 1064" in capsys.readouterr().out
|
|
|
|
|
|
def test_check_missing_file_is_exit_2(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
assert cli.main(["check", "01", str(tmp_path / "nope.sql")]) == 2
|
|
assert "not found" in capsys.readouterr().out
|
|
|
|
|
|
def test_check_unknown_drill(tmp_path: Path) -> None:
|
|
assert cli.main(["check", "zzz", _sql(tmp_path)]) == 2
|
|
|
|
|
|
def test_check_engine_error_exit_2(tmp_path: Path) -> None:
|
|
with patch.object(sd, "run", side_effect=sd.EngineError("x")):
|
|
assert cli.main(["check", "01", _sql(tmp_path)]) == 2
|
|
|
|
|
|
def test_no_subcommand_is_usage_error() -> None:
|
|
with pytest.raises(SystemExit):
|
|
cli.main([])
|