Coverage for tests/test_cli.py: 100.00%
79 statements
« prev ^ index » next coverage.py v7.6.3, created at 2024-10-17 17:18 +0200
« prev ^ index » next coverage.py v7.6.3, created at 2024-10-17 17:18 +0200
1"""Tests for the `cli` module."""
3from __future__ import annotations
5import pytest
7from duty import cli, debug
10def test_no_duty(capsys: pytest.CaptureFixture) -> None:
11 """Run no duties.
13 Parameters:
14 capsys: Pytest fixture to capture output.
15 """
16 assert cli.main([]) == 1
17 captured = capsys.readouterr()
18 assert "Available duties" in captured.out
21def test_show_help(capsys: pytest.CaptureFixture) -> None:
22 """Show help.
24 Parameters:
25 capsys: Pytest fixture to capture output.
26 """
27 assert cli.main(["-h"]) == 0
28 captured = capsys.readouterr()
29 assert "duty" in captured.out
32def test_show_help_for_given_duties(capsys: pytest.CaptureFixture) -> None:
33 """Show help for given duties.
35 Parameters:
36 capsys: Pytest fixture to capture output.
37 """
38 assert cli.main(["-d", "tests/fixtures/basic.py", "-h", "hello"]) == 0
39 captured = capsys.readouterr()
40 assert "hello" in captured.out
43def test_show_help_unknown_duty(capsys: pytest.CaptureFixture) -> None:
44 """Show help for an unknown duty.
46 Parameters:
47 capsys: Pytest fixture to capture output.
48 """
49 assert cli.main(["-d", "tests/fixtures/basic.py", "-h", "not-here"]) == 0
50 captured = capsys.readouterr()
51 assert "Unknown duty" in captured.out
54def test_select_duties() -> None:
55 """Run a duty."""
56 assert cli.main(["-d", "tests/fixtures/basic.py", "hello"]) == 0
59def test_unknown_duty() -> None:
60 """Don't run an unknown duty."""
61 assert cli.main(["-d", "tests/fixtures/basic.py", "byebye"]) == 1
64def test_incorrect_arguments() -> None:
65 """Use incorrect arguments."""
66 assert cli.main(["-d", "tests/fixtures/basic.py", "hello=1"]) == 1
69# we use 300 because it's slightly above the valid maximum 255
70@pytest.mark.parametrize("code", range(-100, 300, 7))
71def test_duty_failure(code: int) -> None:
72 """Check exit code.
74 Parameters:
75 code: Code to match.
76 """
77 assert cli.main(["-d", "tests/fixtures/code.py", "exit_with", f"code={code}"]) == code
80def test_multiple_duties(capfd: pytest.CaptureFixture) -> None:
81 """Run multiple duties.
83 Parameters:
84 capfd: Pytest fixture to capture output.
85 """
86 assert cli.main(["-d", "tests/fixtures/multiple.py", "first_duty", "second_duty"]) == 0
87 captured = capfd.readouterr()
88 assert "first" in captured.out
89 assert "second" in captured.out
92def test_duty_arguments(capfd: pytest.CaptureFixture) -> None:
93 """Run duty with arguments.
95 Parameters:
96 capfd: Pytest fixture to capture output.
97 """
98 assert cli.main(["-d", "tests/fixtures/arguments.py", "say_hello", "cat=fabric"]) == 0
99 captured = capfd.readouterr()
100 assert "cat fabric" in captured.out
101 assert "dog dog" in captured.out
103 assert cli.main(["-d", "tests/fixtures/arguments.py", "say_hello", "dog=paramiko", "cat=invoke"]) == 0
104 captured = capfd.readouterr()
105 assert "cat invoke" in captured.out
106 assert "dog paramiko" in captured.out
109def test_list_duties(capsys: pytest.CaptureFixture) -> None:
110 """List duties.
112 Parameters:
113 capsys: Pytest fixture to capture output.
114 """
115 assert cli.main(["-d", "tests/fixtures/list.py", "-l"]) == 0
116 captured = capsys.readouterr()
117 assert "Tong..." in captured.out
118 assert "DEUM!" in captured.out
121def test_global_options() -> None:
122 """Test global options."""
123 assert cli.main(["-d", "tests/fixtures/code.py", "-z", "exit_with", "1"]) == 0
126def test_global_and_local_options() -> None:
127 """Test global and local options."""
128 assert cli.main(["-d", "tests/fixtures/code.py", "-z", "exit_with", "-Z", "1"]) == 1
131def test_options_precedence() -> None:
132 """Test options precedence."""
133 # @duty(nofail=True) is overridden by ctx.run(nofail=False)
134 assert cli.main(["-d", "tests/fixtures/precedence.py", "precedence"]) == 1
136 # ctx.run(nofail=False) is overridden by local option -z
137 assert cli.main(["-d", "tests/fixtures/precedence.py", "precedence", "-z"]) == 0
139 # ctx.run(nofail=False) is overridden by global option -z
140 assert cli.main(["-d", "tests/fixtures/precedence.py", "-z", "precedence"]) == 0
142 # global option -z is overridden by local option -z
143 assert cli.main(["-d", "tests/fixtures/precedence.py", "-z", "precedence", "-Z"]) == 1
146# test options precedence (CLI option, env var, ctx.run, @duty
147# test positional arguments
148# test extra keyword arguments
149# test complete (global options + local options + multi duties + positional args + keyword args + extra keyword args)
152@pytest.mark.parametrize(
153 ("param", "expected"),
154 [
155 ("", 1),
156 ("n", 1),
157 ("N", 1),
158 ("no", 1),
159 ("NO", 1),
160 ("false", 1),
161 ("FALSE", 1),
162 ("off", 1),
163 ("OFF", 1),
164 ("zero=", 1),
165 ("zero=0", 1),
166 ("zero=n", 1),
167 ("zero=N", 1),
168 ("zero=no", 1),
169 ("zero=NO", 1),
170 ("zero=false", 1),
171 ("zero=FALSE", 1),
172 ("zero=off", 1),
173 ("zero=OFF", 1),
174 ("y", 0),
175 ("Y", 0),
176 ("yes", 0),
177 ("YES", 0),
178 ("on", 0),
179 ("ON", 0),
180 ("true", 0),
181 ("TRUE", 0),
182 ("anything else", 0),
183 ("-1", 0),
184 ("1", 0),
185 ("zero=y", 0),
186 ("zero=Y", 0),
187 ("zero=yes", 0),
188 ("zero=YES", 0),
189 ("zero=on", 0),
190 ("zero=ON", 0),
191 ("zero=true", 0),
192 ("zero=TRUE", 0),
193 ("zero=anything else", 0),
194 ("zero=-1", 0),
195 ("zero=1", 0),
196 ],
197)
198def test_cast_bool_parameter(param: str, expected: int) -> None:
199 """Test parameters casting as boolean.
201 Parameters:
202 param: Pytest parametrization fixture.
203 expected: Pytest parametrization fixture.
204 """
205 assert cli.main(["-d", "tests/fixtures/booleans.py", "boolean", param]) == expected
208def test_invalid_params(capsys: pytest.CaptureFixture) -> None:
209 """Check that invalid parameters are early and correctly detected.
211 Parameters:
212 capsys: Pytest fixture to capture output.
213 """
214 assert cli.main(["-d", "tests/fixtures/booleans.py", "boolean", "zore=off"]) == 1
215 captured = capsys.readouterr()
216 assert "unexpected keyword argument 'zore'" in captured.err
218 assert cli.main(["-d", "tests/fixtures/code.py", "exit_with"]) == 1
219 captured = capsys.readouterr()
220 assert "missing 1 required positional argument: 'code'" in captured.err
223def test_show_version(capsys: pytest.CaptureFixture) -> None:
224 """Show version.
226 Parameters:
227 capsys: Pytest fixture to capture output.
228 """
229 with pytest.raises(SystemExit):
230 cli.main(["-V"])
231 captured = capsys.readouterr()
232 assert debug.get_version() in captured.out
235def test_show_debug_info(capsys: pytest.CaptureFixture) -> None:
236 """Show debug information.
238 Parameters:
239 capsys: Pytest fixture to capture output.
240 """
241 with pytest.raises(SystemExit):
242 cli.main(["--debug-info"])
243 captured = capsys.readouterr().out.lower()
244 assert "python" in captured
245 assert "system" in captured
246 assert "environment" in captured
247 assert "packages" in captured