1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
|
# SPDX-FileCopyrightText: 2024-present Hinrich Mahler <chango@mahlerhome.de>
#
# SPDX-License-Identifier: MIT
import traceback
import unittest.mock
from collections.abc import Mapping, Sequence
from typing import IO, Any, Literal
import pytest
from click.testing import Result
from typer import Typer
from typer.testing import CliRunner
import chango
from chango._cli import app as chango_app
class CLIResult:
def __init__(self, result: Result) -> None:
self._result = result
def __getattr__(self, name: str) -> Any:
# only called if attribute is not found in self
return getattr(self._result, name)
def check_exit_code(self, expected_code: int = 0) -> Literal[True]:
text = f"stdout:\n{self.stdout}"
if self.exception:
text += f"\nexception:\n{self.exception}"
text += f"\ntraceback:\n{'\n'.join(traceback.format_exception(*self.exc_info))}"
if self.exit_code != expected_code:
raise AssertionError(
f"Expected exit code {expected_code}, got {self.exit_code}\n{text}"
)
return True
class ReuseCliRunner(CliRunner):
def __init__(self, app: Typer, *args: Any, **kwargs: Any) -> None:
self.app = app
# For easier testing, disable rich markup mode
self.app.rich_markup_mode = None
super().__init__(*args, **kwargs)
def invoke(
self,
args: str | Sequence[str] | None = None,
input: bytes | str | IO[Any] | None = None,
env: Mapping[str, str] | None = None,
catch_exceptions: bool = True,
color: bool = False,
**extra: Any,
) -> CLIResult:
return CLIResult(
super().invoke(
self.app,
args=args,
input=input,
env=env,
catch_exceptions=catch_exceptions,
color=color,
**extra,
)
)
@pytest.fixture(scope="session")
def cli():
return ReuseCliRunner(chango_app)
@pytest.fixture
def mock_chango_instance(monkeypatch):
chango_config = unittest.mock.MagicMock()
monkeypatch.setattr(chango.config.ChanGoConfig, "load", lambda *_, **__: chango_config)
yield chango_config.import_chango_instance()
# This is required to ensure that each test gets a new instance of the mock
chango.config.get_chango_instance.cache_clear()
|