Coverage for gws-app/gws/lib/cli/_test.py: 100%
133 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-16 22:59 +0200
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-16 22:59 +0200
1"""Tests for the cli module."""
3from unittest import mock
4import pytest
6import gws
7import gws.lib.cli as cli
8import gws.test.util as u
11def test_cprint(capsys):
12 cli.SCRIPT_NAME = ''
14 # Test with color
15 with mock.patch('sys.stdout.isatty', return_value=True):
16 cli.cprint('red', 'test message')
17 captured = capsys.readouterr()
18 assert '\x1b[31mtest message\x1b[0m' in captured.out
20 # Test without color (non-tty)
21 with mock.patch('sys.stdout.isatty', return_value=False):
22 cli.cprint('red', 'test message')
23 captured = capsys.readouterr()
24 assert 'test message' in captured.out
25 assert '\x1b[31m' not in captured.out
27 # Test with script name
28 cli.SCRIPT_NAME = 'testscript'
29 cli.cprint('blue', 'test message')
30 captured = capsys.readouterr()
31 assert '[testscript] test message' in captured.out
32 cli.SCRIPT_NAME = '' # Reset for other tests
35def test_error_warning_info(capsys):
36 cli.error('error message')
37 captured = capsys.readouterr()
38 assert 'error message' in captured.out
40 cli.warning('warning message')
41 captured = capsys.readouterr()
42 assert 'warning message' in captured.out
44 cli.info('info message')
45 captured = capsys.readouterr()
46 assert 'info message' in captured.out
49def test_fatal(capsys):
50 with u.raises(SystemExit) as excinfo:
51 cli.fatal('fatal message')
52 assert excinfo.value.code == 1
53 captured = capsys.readouterr()
54 assert 'fatal message' in captured.out
57def test_run(capsys):
58 # Test successful command
59 with mock.patch('subprocess.run') as mock_run:
60 mock_run.return_value.returncode = 0
61 cli.run('echo test')
62 mock_run.assert_called_once()
63 captured = capsys.readouterr()
64 assert '> echo test' in captured.out
66 # Test command as list
67 with mock.patch('subprocess.run') as mock_run:
68 mock_run.return_value.returncode = 0
69 cli.run(['echo', 'test'])
70 mock_run.assert_called_once()
71 captured = capsys.readouterr()
72 assert '> echo test' in captured.out
74 # Test failing command
75 with mock.patch('subprocess.run') as mock_run:
76 mock_run.return_value.returncode = 1
77 with pytest.raises(SystemExit):
78 cli.run('false')
79 captured = capsys.readouterr()
80 assert 'COMMAND FAILED' in captured.out
83def test_exec():
84 # Test successful command
85 result = cli.exec('echo "hello world"')
86 assert result == "hello world"
88 # Test failing command
89 with mock.patch('subprocess.run') as mock_run:
90 mock_run.side_effect = Exception("Command failed")
91 result = cli.exec('invalid command')
92 assert 'FAILED' in result
95def test_find_dirs(tmp_path):
96 # Create test directory structure
97 (tmp_path / "dir1").mkdir()
98 (tmp_path / "dir2").mkdir()
99 (tmp_path / ".hidden_dir").mkdir()
100 (tmp_path / "file1").write_text("test")
102 # Test finding directories
103 dirs = list(cli.find_dirs(tmp_path))
104 assert len(dirs) == 2
105 assert str(tmp_path / "dir1") in dirs
106 assert str(tmp_path / "dir2") in dirs
107 assert str(tmp_path / ".hidden_dir") not in dirs
109 # Test with non-existent directory
110 dirs = list(cli.find_dirs(tmp_path / "nonexistent"))
111 assert len(dirs) == 0
114def test_find_files(tmp_path):
115 # Create test directory structure
116 (tmp_path / "dir1").mkdir()
117 (tmp_path / "dir1" / "file1.txt").write_text("test")
118 (tmp_path / "dir1" / "file2.py").write_text("test")
119 (tmp_path / "dir2").mkdir()
120 (tmp_path / "dir2" / "file3.txt").write_text("test")
121 (tmp_path / ".hidden_dir").mkdir()
122 (tmp_path / ".hidden_dir" / "file4.txt").write_text("test")
123 (tmp_path / "file5.txt").write_text("test")
125 # Test finding all files
126 files = list(cli.find_files(tmp_path))
127 assert len(files) == 4
128 assert str(tmp_path / "dir1" / "file1.txt") in files
129 assert str(tmp_path / "dir1" / "file2.py") in files
130 assert str(tmp_path / "dir2" / "file3.txt") in files
131 assert str(tmp_path / "file5.txt") in files
133 # Test with pattern
134 files = list(cli.find_files(tmp_path, pattern=r'\.txt$'))
135 assert len(files) == 3
136 assert str(tmp_path / "dir1" / "file1.txt") in files
137 assert str(tmp_path / "dir2" / "file3.txt") in files
138 assert str(tmp_path / "file5.txt") in files
139 assert str(tmp_path / "dir1" / "file2.py") not in files
141 # Test without recursion
142 files = list(cli.find_files(tmp_path, deep=False))
143 assert len(files) == 1
144 assert str(tmp_path / "file5.txt") in files
146 # Test with non-existent directory
147 files = list(cli.find_files(tmp_path / "nonexistent"))
148 assert len(files) == 0
151def test_read_write_file(tmp_path):
152 test_file = tmp_path / "test.txt"
154 # Test writing to file
155 cli.write_file(str(test_file), "test content")
156 assert test_file.read_text() == "test content"
158 # Test reading from file
159 content = cli.read_file(str(test_file))
160 assert content == "test content"
163def test_parse_args():
164 # Test basic arguments
165 args = cli.parse_args(["script.py", "arg1", "arg2"])
166 assert args[0] == "script.py"
167 assert args[1] == "arg1"
168 assert args[2] == "arg2"
170 # Test options
171 args = cli.parse_args(["script.py", "-o", "value", "--long", "longval"])
172 assert args["o"] == "value"
173 assert args["long"] == "longval"
175 # Test flags
176 args = cli.parse_args(["script.py", "-f", "--flag"])
177 assert args["f"] is True
178 assert args["flag"] is True
180 # Test rest arguments
181 args = cli.parse_args(["script.py", "-", "rest1", "rest2"])
182 assert args["_rest"] == ["rest1", "rest2"]
185def test_main():
186 # Test help flag
187 with mock.patch('sys.argv', ['script.py', '-h']), \
188 mock.patch('sys.exit') as mock_exit, \
189 mock.patch('builtins.print') as mock_print:
190 cli.main("test", lambda x: 0, "Usage: test")
191 mock_print.assert_called()
192 mock_exit.assert_called_with(0)
194 # Test normal execution
195 with mock.patch('sys.argv', ['script.py', 'arg']), \
196 mock.patch('sys.exit') as mock_exit:
197 cli.main("test", lambda x: 42, "Usage: test")
198 mock_exit.assert_called_with(42)
200 # Test exception handling
202 def failing_func(args):
203 raise Exception("Test exception")
205 with mock.patch('sys.argv', ['script.py', 'arg']), \
206 mock.patch('sys.exit') as mock_exit, \
207 mock.patch('gws.lib.cli.error') as mock_error:
208 cli.main("test", failing_func, "Usage: test")
209 mock_error.assert_called()
212# def test_text_table():
213# # Test with list of dicts
214# data = [
215# {"name": "Alice", "age": 30},
216# {"name": "Bob", "age": 25}
217# ]
218#
219# # With header
220# table = cli.text_table(data, header=["name", "age"])
221# assert "name | age" in table
222# assert "Alice | 30" in table
223#
224# # With auto header
225# table = cli.text_table(data, header="auto")
226# assert "name | age" in table
227# assert "Alice | 30" in table
228#
229# # Without header
230# table = cli.text_table(data, header=None)
231# assert "name | age" not in table
232# assert "Alice | 30" in table
233#
234# # Test with list of lists
235# data = [
236# ["Alice", 30],
237# ["Bob", 25]
238# ]
239#
240# table = cli.text_table(data, header=["name", "age"])
241# assert "name | age" in table
242# assert "Alice | 30" in table
243#
244# # Test with empty data
245# assert cli.text_table([]) == ""
248# def test_progress_indicator(capsys):
249# # Test initialization and basic logging
250# with mock.patch('time.time', side_effect=[0,
251# 1.5]): # Mock time to get consistent results
252# with cli.ProgressIndicator("Test", total=100) as progress:
253# captured = capsys.readouterr()
254# assert "START" in captured.out
255# assert "100" in captured.out
257# # Test update
258# progress.update(10)
259# captured = capsys.readouterr()
260# assert captured.out.strip() == "[test] Test: 10%"
262# # Test update reaching threshold
263# progress.update(40)
264# captured = capsys.readouterr()
265# assert "50%" in captured.out
267# # Test end message
268# captured = capsys.readouterr()
269# assert "END" in captured.out
271# # Test without
272# with cli.ProgressIndicator("NoTotal") as progress:
273# captured = capsys.readouterr()
274# assert "START" in captured.out
276# # Updates should do nothing
277# progress.update(50)
278# captured = capsys.readouterr()
279# assert captured.out.strip() == ""