|
4 | 4 | from revenueholdings import TOOLS, __version__ |
5 | 5 | from revenueholdings.cli import app |
6 | 6 | from typer.testing import CliRunner |
| 7 | +from unittest import mock |
7 | 8 |
|
8 | 9 | runner = CliRunner() |
9 | 10 |
|
@@ -35,12 +36,73 @@ def test_unknown_tool(self): |
35 | 36 | assert "Unknown" in result.stdout |
36 | 37 |
|
37 | 38 |
|
| 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 | + |
38 | 74 | class TestVersionsCommand: |
39 | 75 | def test_versions_runs(self): |
| 76 | + """List all tool versions without error.""" |
40 | 77 | result = runner.invoke(app, ["versions"]) |
41 | | - # Should succeed even if tools aren't installed |
42 | 78 | assert result.exit_code == 0 |
43 | 79 |
|
| 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 | + |
44 | 106 |
|
45 | 107 | class TestHelp: |
46 | 108 | def test_help(self): |
|
0 commit comments