Skip to content

Commit 0094491

Browse files
author
DevForge Engineer
committed
test: add install/versions/dispatch test coverage and fix unknown tool UX
- Add 7 new tests (13 total, up from 6) covering: - install command: specific tool, all alias, unknown tool, pip failure - versions command: unknown tool error, per-tool not-installed state - dispatch: invalid tool subcommand rejection - Fix silent failure in versions command when unknown tool name is given (now prints error and exits with code 1)
1 parent 45e2919 commit 0094491

2 files changed

Lines changed: 68 additions & 2 deletions

File tree

src/revenueholdings/cli.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,11 @@ def show_versions(
120120
tool: str | None = typer.Argument(None, help="Check version of a specific tool."),
121121
):
122122
"""Show installed tool versions."""
123-
targets = ([tool] if tool in TOOLS else []) if tool else _builtins.list(TOOLS.keys())
123+
if tool is not None and tool not in TOOLS:
124+
console.print(f"[red]Unknown tool: {tool}[/red]")
125+
console.print(f"Available: {', '.join(TOOLS.keys())}")
126+
raise typer.Exit(code=1)
127+
targets = [tool] if tool else _builtins.list(TOOLS.keys())
124128

125129
for t in targets:
126130
info = TOOLS[t]

tests/test_cli.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from revenueholdings import TOOLS, __version__
55
from revenueholdings.cli import app
66
from typer.testing import CliRunner
7+
from unittest import mock
78

89
runner = CliRunner()
910

@@ -35,12 +36,73 @@ def test_unknown_tool(self):
3536
assert "Unknown" in result.stdout
3637

3738

39+
class TestInstallCommand:
40+
@mock.patch("revenueholdings.cli.subprocess.run")
41+
def test_install_specific_tool(self, mock_run):
42+
"""Install a specific tool by name."""
43+
mock_run.return_value = mock.MagicMock(returncode=0, stdout="", stderr="")
44+
result = runner.invoke(app, ["install", "guard"])
45+
assert result.exit_code == 0
46+
assert "Successfully" in result.stdout
47+
mock_run.assert_called_once()
48+
49+
@mock.patch("revenueholdings.cli.subprocess.run")
50+
def test_install_all(self, mock_run):
51+
"""Install all tools via the 'all' alias."""
52+
mock_run.return_value = mock.MagicMock(returncode=0, stdout="", stderr="")
53+
result = runner.invoke(app, ["install", "all"])
54+
assert result.exit_code == 0
55+
assert "Successfully" in result.stdout
56+
mock_run.assert_called_once()
57+
58+
def test_install_unknown_tool(self):
59+
"""Error on unknown tool name."""
60+
result = runner.invoke(app, ["install", "nonexistent"])
61+
assert result.exit_code == 1
62+
assert "Unknown" in result.stdout
63+
assert "Available:" in result.stdout
64+
65+
@mock.patch("revenueholdings.cli.subprocess.run")
66+
def test_install_failure(self, mock_run):
67+
"""Handle pip install failure gracefully."""
68+
mock_run.return_value = mock.MagicMock(returncode=1, stdout="", stderr="Error message")
69+
result = runner.invoke(app, ["install", "guard"])
70+
assert result.exit_code == 1
71+
assert "failed" in result.stdout.lower()
72+
73+
3874
class TestVersionsCommand:
3975
def test_versions_runs(self):
76+
"""List all tool versions without error."""
4077
result = runner.invoke(app, ["versions"])
41-
# Should succeed even if tools aren't installed
4278
assert result.exit_code == 0
4379

80+
def test_versions_unknown_tool_fails(self):
81+
"""Error on unknown tool name."""
82+
result = runner.invoke(app, ["versions", "nonexistent"])
83+
assert result.exit_code == 1
84+
assert "Unknown" in result.stdout
85+
86+
@mock.patch("revenueholdings.cli.subprocess.run")
87+
def test_versions_specific_tool_not_installed(self, mock_run):
88+
"""Show 'not installed' for a tool that isn't installed."""
89+
mock_run.return_value = mock.MagicMock(
90+
returncode=1, stdout="", stderr=""
91+
)
92+
result = runner.invoke(app, ["versions", "guard"])
93+
assert result.exit_code == 0
94+
assert "guard" in result.stdout
95+
assert "not installed" in result.stdout
96+
97+
98+
class TestDispatchCommands:
99+
def test_invalid_tool_subcommand(self):
100+
"""Reject dispatch to an unknown tool subcommand."""
101+
result = runner.invoke(app, ["nonexistent"])
102+
# typer outputs error to stderr, not stdout
103+
assert result.exit_code != 0
104+
assert "No such command" in result.stdout or "No such command" in result.stderr
105+
44106

45107
class TestHelp:
46108
def test_help(self):

0 commit comments

Comments
 (0)