2019-01-13 11:36:44 +00:00
|
|
|
"""
|
|
|
|
Integration tests found in:
|
|
|
|
- test_cli.py
|
2019-02-18 10:10:17 +00:00
|
|
|
- test_renderer.py
|
2019-01-13 11:36:44 +00:00
|
|
|
- test_output.py
|
|
|
|
"""
|
|
|
|
|
2018-08-27 11:15:50 +00:00
|
|
|
import os
|
|
|
|
import subprocess
|
2019-02-16 11:09:56 +00:00
|
|
|
from pathlib import Path
|
2019-05-08 11:57:17 +00:00
|
|
|
from typing import TYPE_CHECKING, Optional
|
2018-08-27 11:15:50 +00:00
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
if TYPE_CHECKING:
|
|
|
|
import pytest_mock
|
|
|
|
|
|
|
|
|
2019-02-16 11:09:56 +00:00
|
|
|
# Pycharm sets cwd to /tests/.
|
|
|
|
# To ensure tests can find WAV files (based on /), jump from /tests/conftest.py to /.
|
|
|
|
os.chdir(Path(__file__).parent.parent)
|
|
|
|
|
|
|
|
|
2018-08-27 11:15:50 +00:00
|
|
|
@pytest.fixture
|
2019-01-03 08:57:30 +00:00
|
|
|
def Popen(mocker: "pytest_mock.MockFixture"):
|
2019-05-08 11:57:17 +00:00
|
|
|
"""
|
|
|
|
- This fixture function is called Popen.
|
|
|
|
- pytest names our yield-value Popen too.
|
|
|
|
- The yielded Popen imitates `class Popen`, but is actually a MagicMock instance.
|
|
|
|
- We can't make Popen a class, because a test uses `Popen.call_args`.
|
|
|
|
- To "add class-methods" to Popen, I create a `class MockPopen`
|
|
|
|
and give its classmethods to Popen.
|
|
|
|
"""
|
2018-08-29 07:57:08 +00:00
|
|
|
real_Popen = subprocess.Popen
|
2018-08-27 11:15:50 +00:00
|
|
|
|
2019-05-08 11:57:17 +00:00
|
|
|
class MockPopen(real_Popen):
|
|
|
|
exception_on_write: Optional[Exception] = None
|
2018-08-29 08:08:05 +00:00
|
|
|
|
2019-05-08 11:57:17 +00:00
|
|
|
@classmethod
|
|
|
|
def set_exception(cls, exc: Exception):
|
|
|
|
cls.exception_on_write = exc
|
2018-08-29 08:08:05 +00:00
|
|
|
|
2019-05-08 11:57:17 +00:00
|
|
|
@classmethod
|
|
|
|
def __new__(cls, *args, **kwargs):
|
|
|
|
popen = mocker.create_autospec(real_Popen)
|
|
|
|
|
|
|
|
popen.stdin = mocker.mock_open()(os.devnull, "wb")
|
|
|
|
popen.stdout = mocker.mock_open()(os.devnull, "rb")
|
|
|
|
assert popen.stdin != popen.stdout
|
|
|
|
|
|
|
|
if cls.exception_on_write is not None:
|
|
|
|
popen.stdin.write.side_effect = cls.exception_on_write
|
|
|
|
|
|
|
|
popen.wait.return_value = 0
|
|
|
|
return popen
|
|
|
|
|
|
|
|
# Popen acts exactly the same as MockPopen
|
|
|
|
# when calling classmethods or creating instances.
|
|
|
|
# But Popen is a MagicMock, and captures Popen() call arguments.
|
2018-08-27 11:15:50 +00:00
|
|
|
|
2019-01-03 08:57:30 +00:00
|
|
|
Popen = mocker.patch.object(subprocess, "Popen", autospec=True)
|
2019-05-08 11:57:17 +00:00
|
|
|
Popen.set_exception = MockPopen.set_exception
|
|
|
|
Popen.side_effect = MockPopen.__new__
|
2018-08-27 11:15:50 +00:00
|
|
|
yield Popen
|