mirror of
https://github.com/jrnl-org/jrnl.git
synced 2025-06-28 13:36:14 +02:00
Improve handling of mocking logic in pytest (#1382)
* WIP * fix handling of user input (stdin, input, getpass) * take out redundant pytest step * fix handling of 'we should' statements * fix test that doesn't use a config file * fix another test that uses stdin Co-authored-by: Micah Jerome Ellison <micah.jerome.ellison@gmail.com> * remove .tool-versions file per PR feedback * add comment to clarify why disembodied variables are here Co-authored-by: Micah Jerome Ellison <micah.jerome.ellison@gmail.com>
This commit is contained in:
parent
3518e37087
commit
2ab485de8c
16 changed files with 259 additions and 197 deletions
|
@ -8,17 +8,19 @@ import tempfile
|
|||
|
||||
from keyring import backend
|
||||
from keyring import errors
|
||||
from keyring import set_keyring
|
||||
from pytest import fixture
|
||||
from unittest.mock import patch
|
||||
from .helpers import get_fixture
|
||||
import toml
|
||||
|
||||
from jrnl.config import load_config
|
||||
from jrnl.os_compat import split_args
|
||||
|
||||
|
||||
# --- Keyring --- #
|
||||
@fixture
|
||||
def keyring():
|
||||
set_keyring(NoKeyring())
|
||||
return NoKeyring()
|
||||
|
||||
|
||||
@fixture
|
||||
|
@ -75,13 +77,90 @@ class FailedKeyring(backend.KeyringBackend):
|
|||
|
||||
# ----- Misc ----- #
|
||||
@fixture
|
||||
def cli_run():
|
||||
return {"status": 0, "stdout": None, "stderr": None}
|
||||
def cli_run(
|
||||
mock_factories,
|
||||
mock_args,
|
||||
mock_is_tty,
|
||||
mock_config_path,
|
||||
mock_editor,
|
||||
mock_user_input,
|
||||
mock_overrides,
|
||||
mock_password,
|
||||
):
|
||||
# Check if we need more mocks
|
||||
mock_factories.update(mock_args)
|
||||
mock_factories.update(mock_is_tty)
|
||||
mock_factories.update(mock_overrides)
|
||||
mock_factories.update(mock_editor)
|
||||
mock_factories.update(mock_config_path)
|
||||
mock_factories.update(mock_user_input)
|
||||
mock_factories.update(mock_password)
|
||||
|
||||
return {
|
||||
"status": 0,
|
||||
"stdout": None,
|
||||
"stderr": None,
|
||||
"mocks": {},
|
||||
"mock_factories": mock_factories,
|
||||
}
|
||||
|
||||
|
||||
@fixture
|
||||
def mocks():
|
||||
return dict()
|
||||
def mock_factories():
|
||||
return {}
|
||||
|
||||
|
||||
@fixture
|
||||
def mock_args(cache_dir, request):
|
||||
def _mock_args():
|
||||
command = get_fixture(request, "command", "")
|
||||
|
||||
if cache_dir["exists"]:
|
||||
command = command.format(cache_dir=cache_dir["path"])
|
||||
|
||||
args = split_args(command)
|
||||
|
||||
return patch("sys.argv", ["jrnl"] + args)
|
||||
|
||||
return {"args": _mock_args}
|
||||
|
||||
|
||||
@fixture
|
||||
def mock_is_tty(is_tty):
|
||||
return {"is_tty": lambda: patch("sys.stdin.isatty", return_value=is_tty)}
|
||||
|
||||
|
||||
@fixture
|
||||
def mock_overrides(config_in_memory):
|
||||
from jrnl.override import apply_overrides
|
||||
|
||||
def my_overrides(*args, **kwargs):
|
||||
result = apply_overrides(*args, **kwargs)
|
||||
config_in_memory["overrides"] = result
|
||||
return result
|
||||
|
||||
return {
|
||||
"overrides": lambda: patch(
|
||||
"jrnl.jrnl.apply_overrides", side_effect=my_overrides
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@fixture
|
||||
def mock_config_path(request):
|
||||
config_path = get_fixture(request, "config_path")
|
||||
|
||||
if not config_path:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"config_path_install": lambda: patch(
|
||||
"jrnl.install.get_config_path", return_value=config_path
|
||||
),
|
||||
"config_path_config": lambda: patch(
|
||||
"jrnl.config.get_config_path", return_value=config_path
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@fixture
|
||||
|
@ -94,12 +173,6 @@ def working_dir(request):
|
|||
return os.path.join(request.config.rootpath, "tests")
|
||||
|
||||
|
||||
@fixture
|
||||
def config_path(temp_dir):
|
||||
os.chdir(temp_dir.name)
|
||||
return temp_dir.name + "/jrnl.yaml"
|
||||
|
||||
|
||||
@fixture
|
||||
def toml_version(working_dir):
|
||||
pyproject = os.path.join(working_dir, "..", "pyproject.toml")
|
||||
|
@ -108,8 +181,23 @@ def toml_version(working_dir):
|
|||
|
||||
|
||||
@fixture
|
||||
def password():
|
||||
return ""
|
||||
def mock_password(request):
|
||||
def _mock_password():
|
||||
password = get_fixture(request, "password")
|
||||
user_input = get_fixture(request, "user_input")
|
||||
|
||||
if password:
|
||||
password = password.splitlines()
|
||||
|
||||
elif user_input:
|
||||
password = user_input.splitlines()
|
||||
|
||||
if not password:
|
||||
password = Exception("Unexpected call for password")
|
||||
|
||||
return patch("getpass.getpass", side_effect=password)
|
||||
|
||||
return {"getpass": _mock_password}
|
||||
|
||||
|
||||
@fixture
|
||||
|
@ -127,19 +215,36 @@ def str_value():
|
|||
return ""
|
||||
|
||||
|
||||
@fixture
|
||||
def command():
|
||||
return ""
|
||||
|
||||
|
||||
@fixture
|
||||
def should_not():
|
||||
return False
|
||||
|
||||
|
||||
@fixture
|
||||
def user_input():
|
||||
return ""
|
||||
def mock_user_input(request, is_tty):
|
||||
def _generator(target):
|
||||
def _mock_user_input():
|
||||
user_input = get_fixture(request, "user_input", None)
|
||||
|
||||
if user_input is None:
|
||||
user_input = Exception("Unexpected call for user input")
|
||||
else:
|
||||
user_input = user_input.splitlines() if is_tty else [user_input]
|
||||
|
||||
return patch(target, side_effect=user_input)
|
||||
|
||||
return _mock_user_input
|
||||
|
||||
return {
|
||||
"stdin": _generator("sys.stdin.read"),
|
||||
"input": _generator("builtins.input"),
|
||||
}
|
||||
|
||||
|
||||
@fixture
|
||||
def is_tty(input_method):
|
||||
assert input_method in ["", "enter", "pipe"]
|
||||
return input_method != "pipe"
|
||||
|
||||
|
||||
@fixture
|
||||
|
@ -187,7 +292,7 @@ def editor_state():
|
|||
|
||||
|
||||
@fixture
|
||||
def editor(editor_state):
|
||||
def mock_editor(editor_state):
|
||||
def _mock_editor(editor_command):
|
||||
tmpfile = editor_command[-1]
|
||||
|
||||
|
@ -203,4 +308,4 @@ def editor(editor_state):
|
|||
file_content = f.read()
|
||||
editor_state["tmpfile"]["content"] = file_content
|
||||
|
||||
return _mock_editor
|
||||
return {"editor": lambda: patch("subprocess.call", side_effect=_mock_editor)}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue