|
1 | 1 | import pathlib
|
2 | 2 | import subprocess
|
| 3 | +import sys |
| 4 | +import textwrap |
3 | 5 | from typing import Any
|
| 6 | +from unittest import mock |
4 | 7 |
|
5 | 8 | import pytest
|
6 | 9 |
|
@@ -136,3 +139,157 @@ def test_run(tmp_path: pathlib.Path, args: list, kwargs: dict, run_kwargs: dict)
|
136 | 139 | response = cmd.run(**run_kwargs)
|
137 | 140 |
|
138 | 141 | assert response.returncode == 0
|
| 142 | + |
| 143 | + |
| 144 | +@pytest.mark.parametrize( |
| 145 | + "args,kwargs,run_kwargs", |
| 146 | + [ |
| 147 | + [ |
| 148 | + ["ls"], |
| 149 | + {}, |
| 150 | + {}, |
| 151 | + ], |
| 152 | + [[["ls", "-l"]], {}, {}], |
| 153 | + [[["ls", "-al"]], {}, {"stdout": subprocess.DEVNULL}], |
| 154 | + ], |
| 155 | + ids=idfn, |
| 156 | +) |
| 157 | +@mock.patch("subprocess.Popen") |
| 158 | +def test_Popen_mock( |
| 159 | + mock_subprocess_popen, |
| 160 | + tmp_path: pathlib.Path, |
| 161 | + args: list, |
| 162 | + kwargs: dict, |
| 163 | + run_kwargs: dict, |
| 164 | + capsys: pytest.LogCaptureFixture, |
| 165 | +): |
| 166 | + process_mock = mock.Mock() |
| 167 | + attrs = {"communicate.return_value": ("output", "error"), "returncode": 1} |
| 168 | + process_mock.configure_mock(**attrs) |
| 169 | + mock_subprocess_popen.return_value = process_mock |
| 170 | + cmd = SubprocessCommand(*args, cwd=tmp_path, **kwargs) |
| 171 | + response = cmd.Popen(**run_kwargs) |
| 172 | + |
| 173 | + assert response.returncode == 1 |
| 174 | + |
| 175 | + |
| 176 | +@pytest.mark.parametrize( |
| 177 | + "args,kwargs,run_kwargs", |
| 178 | + [ |
| 179 | + [[["git", "pull", "--progress"]], {}, {}], |
| 180 | + ], |
| 181 | + ids=idfn, |
| 182 | +) |
| 183 | +@mock.patch("subprocess.Popen") |
| 184 | +def test_Popen_git_mock( |
| 185 | + mock_subprocess_popen, |
| 186 | + tmp_path: pathlib.Path, |
| 187 | + args: list, |
| 188 | + kwargs: dict, |
| 189 | + run_kwargs: dict, |
| 190 | + capsys: pytest.LogCaptureFixture, |
| 191 | +): |
| 192 | + process_mock = mock.Mock() |
| 193 | + attrs = {"communicate.return_value": ("output", "error"), "returncode": 1} |
| 194 | + process_mock.configure_mock(**attrs) |
| 195 | + mock_subprocess_popen.return_value = process_mock |
| 196 | + cmd = SubprocessCommand(*args, cwd=tmp_path, **kwargs) |
| 197 | + response = cmd.Popen(**run_kwargs) |
| 198 | + |
| 199 | + stdout, stderr = response.communicate() |
| 200 | + |
| 201 | + assert response.returncode == 1 |
| 202 | + assert stdout == "output" |
| 203 | + assert stderr == "error" |
| 204 | + |
| 205 | + |
| 206 | +CODE = ( |
| 207 | + textwrap.dedent( |
| 208 | + r""" |
| 209 | + import sys |
| 210 | + import time |
| 211 | + size = 10 |
| 212 | + for i in range(10): |
| 213 | + time.sleep(.01) |
| 214 | + sys.stderr.write( |
| 215 | + '[' + "#" * i + "." * (size-i) + ']' + f' {i}/{size}' + '\n' |
| 216 | + ) |
| 217 | + sys.stderr.flush() |
| 218 | +""" |
| 219 | + ) |
| 220 | + .strip("\n") |
| 221 | + .lstrip() |
| 222 | +) |
| 223 | + |
| 224 | + |
| 225 | +def test_Popen_stderr( |
| 226 | + tmp_path: pathlib.Path, |
| 227 | + capsys: pytest.LogCaptureFixture, |
| 228 | +): |
| 229 | + cmd = SubprocessCommand( |
| 230 | + [ |
| 231 | + sys.executable, |
| 232 | + "-c", |
| 233 | + CODE, |
| 234 | + ], |
| 235 | + stdout=subprocess.PIPE, |
| 236 | + stderr=subprocess.PIPE, |
| 237 | + cwd=tmp_path, |
| 238 | + ) |
| 239 | + response = cmd.Popen() |
| 240 | + while response.poll() is None: |
| 241 | + stdout, stderr = response.communicate() |
| 242 | + |
| 243 | + assert stdout != "output" |
| 244 | + assert stderr != "1" |
| 245 | + assert response.returncode == 0 |
| 246 | + |
| 247 | + |
| 248 | +def test_CaptureStderrMixin( |
| 249 | + tmp_path: pathlib.Path, |
| 250 | + capsys: pytest.LogCaptureFixture, |
| 251 | +): |
| 252 | + cmd = SubprocessCommand( |
| 253 | + [ |
| 254 | + sys.executable, |
| 255 | + "-c", |
| 256 | + CODE, |
| 257 | + ], |
| 258 | + stdout=subprocess.PIPE, |
| 259 | + stderr=subprocess.PIPE, |
| 260 | + cwd=tmp_path, |
| 261 | + ) |
| 262 | + response = cmd.Popen() |
| 263 | + while response.poll() is None: |
| 264 | + line = response.stderr.readline().decode("utf-8").strip() |
| 265 | + if line: |
| 266 | + assert line.startswith("[") |
| 267 | + assert response.returncode == 0 |
| 268 | + |
| 269 | + |
| 270 | +def test_CaptureStderrMixin_error( |
| 271 | + tmp_path: pathlib.Path, |
| 272 | + capsys: pytest.LogCaptureFixture, |
| 273 | +): |
| 274 | + cmd = SubprocessCommand( |
| 275 | + [ |
| 276 | + sys.executable, |
| 277 | + "-c", |
| 278 | + CODE |
| 279 | + + textwrap.dedent( |
| 280 | + """ |
| 281 | + sys.exit("FATAL") |
| 282 | + """ |
| 283 | + ), |
| 284 | + ], |
| 285 | + stdout=subprocess.PIPE, |
| 286 | + stderr=subprocess.PIPE, |
| 287 | + cwd=tmp_path, |
| 288 | + ) |
| 289 | + response = cmd.Popen() |
| 290 | + while response.poll() is None: |
| 291 | + line = response.stderr.readline().decode("utf-8").strip() |
| 292 | + if line: |
| 293 | + assert line.startswith("[") or line == "FATAL" |
| 294 | + |
| 295 | + assert response.returncode == 1 |
0 commit comments