diff --git a/tests/test_cli.py b/tests/test_cli.py index 004b0da..cc7af41 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -10,7 +10,44 @@ from rexi.cli import app, is_stdin_a_tty +@pytest.mark.parametrize("input_value", [True, False]) +def test_is_stdin_a_tty(monkeypatch: MonkeyPatch, input_value: bool) -> None: + isatty_mock = Mock() + with monkeypatch.context(): + isatty_mock.return_value = input_value + monkeypatch.setattr("rexi.cli.sys.stdin.isatty", isatty_mock) + assert is_stdin_a_tty() == input_value + + def test_no_args(monkeypatch: MonkeyPatch) -> None: + runner = CliRunner() + class_mock = Mock() + instance_mock = Mock() + with monkeypatch.context(): + class_mock.return_value = instance_mock + monkeypatch.setattr("rexi.cli.RexiApp", class_mock) + result = runner.invoke(app) + + assert result.exit_code == 0 + class_mock.assert_called_once_with("", initial_mode=None, initial_pattern=None) + + +def test_string_input(monkeypatch: MonkeyPatch) -> None: + runner = CliRunner() + text = "This iS! aTe xt2 F0r T3sT!ng" + class_mock = Mock() + instance_mock = Mock() + with monkeypatch.context(): + class_mock.return_value = instance_mock + monkeypatch.setattr("rexi.cli.is_stdin_a_tty", lambda: True) + monkeypatch.setattr("rexi.cli.RexiApp", class_mock) + result = runner.invoke(app, args=[text]) + + assert result.exit_code == 0 + class_mock.assert_called_once_with(text, initial_mode=None, initial_pattern=None) + + +def test_stdin_input(monkeypatch: MonkeyPatch) -> None: """ Couldn't find a better way to test the CLI without patching everything :( """ @@ -21,19 +58,19 @@ def test_no_args(monkeypatch: MonkeyPatch) -> None: instance_mock = Mock() open_mock = Mock() read_mock = Mock() - isatty_mock = Mock() with monkeypatch.context(): read_mock.return_value = "" class_mock.return_value = instance_mock - isatty_mock.return_value = False - monkeypatch.setattr("rexi.cli.is_stdin_a_tty", isatty_mock) + monkeypatch.setattr("rexi.cli.is_stdin_a_tty", lambda: False) monkeypatch.setattr("rexi.cli.RexiApp", class_mock) monkeypatch.setattr("builtins.open", open_mock) - runner.invoke(app, input=a) + result = runner.invoke(app, input=a) open_mock.assert_called_once_with( "con:" if os.name == "nt" else "/dev/tty", "rb" ) + + assert result.exit_code == 0 class_mock.assert_called_once_with( text.decode(), initial_mode=None, initial_pattern=None ) @@ -49,53 +86,106 @@ def test_file_input(monkeypatch: MonkeyPatch, tmp_path: Path) -> None: with monkeypatch.context(): class_mock.return_value = instance_mock monkeypatch.setattr("rexi.cli.RexiApp", class_mock) - runner.invoke(app, args=["-i", str(tmp_path / "text_file")]) + monkeypatch.setattr("rexi.cli.is_stdin_a_tty", lambda: True) + result = runner.invoke(app, args=["-i", str(tmp_path / "text_file")]) + + assert result.exit_code == 0 class_mock.assert_called_once_with(text, initial_mode=None, initial_pattern=None) +@pytest.mark.parametrize("use_stdin", [False, True]) +@pytest.mark.parametrize("use_input", [False, True]) +@pytest.mark.parametrize("use_string", [False, True]) +def test_argument_conflicts( + monkeypatch: MonkeyPatch, + tmp_path: Path, + use_stdin: bool, + use_input: bool, + use_string: bool, +) -> None: + """ + Couldn't find a better way to test the CLI without patching everything :( + """ + # Text stdin + text_stdin = "stdin: This iS! aTe xt2 F0r T3sT!ng" + a = BytesIO(text_stdin.encode()) + # Text string + text_string = "string: ThaT iS! éhé" + # Text input file + text_input = "input: This iS! aTe xt2 F0r T3sT!ng" + tmp_file = (tmp_path / "text_file") + tmp_file.write_text(text_input) + + # Initialize mocks + runner = CliRunner() + class_mock = Mock() + instance_mock = Mock() + read_mock = Mock() + + with monkeypatch.context(): + read_mock.return_value = "" + monkeypatch.setattr("rexi.cli.is_stdin_a_tty", lambda: not use_stdin) + monkeypatch.setattr("rexi.cli.RexiApp", class_mock) + class_mock.return_value = instance_mock + + kwargs = {} + args = [] + if use_stdin: + kwargs["input"] = a + if use_input: + args.extend(["-i", os.fspath(tmp_file)]) + if use_string: + args.extend([text_string]) + if args: + kwargs["args"] = args + # Call CLI + result = runner.invoke(app, **kwargs) + + # Check result + has_conflict = int(use_stdin + use_string + use_input) > 1 + if has_conflict: + assert result.exit_code > 0 + assert "Invalid value" in result.output + return + + expected_text = "" + if use_stdin: + expected_text = text_stdin + elif use_input: + expected_text = text_input + elif use_string: + expected_text = text_string + + assert result.exit_code == 0 + class_mock.assert_called_once_with( + expected_text, + initial_mode=None, + initial_pattern=None, + ) + instance_mock.run.assert_called_once() + + def test_initial_pattern(monkeypatch: MonkeyPatch, tmp_path: Path) -> None: runner = CliRunner() text = "This iS! aTe xt2 F0r T3sT!ng" - (tmp_path / "text_file").write_text(text) class_mock = Mock() instance_mock = Mock() with monkeypatch.context(): class_mock.return_value = instance_mock + monkeypatch.setattr("rexi.cli.is_stdin_a_tty", lambda: True) monkeypatch.setattr("rexi.cli.RexiApp", class_mock) - runner.invoke(app, args=["-i", str(tmp_path / "text_file"), "--pattern", "wtf"]) + runner.invoke(app, args=[text, "--pattern", "wtf"]) class_mock.assert_called_once_with(text, initial_mode=None, initial_pattern="wtf") def test_initial_mode(monkeypatch: MonkeyPatch, tmp_path: Path) -> None: runner = CliRunner() text = "This iS! aTe xt2 F0r T3sT!ng" - (tmp_path / "text_file").write_text(text) class_mock = Mock() instance_mock = Mock() with monkeypatch.context(): class_mock.return_value = instance_mock + monkeypatch.setattr("rexi.cli.is_stdin_a_tty", lambda: True) monkeypatch.setattr("rexi.cli.RexiApp", class_mock) - runner.invoke(app, args=["-i", str(tmp_path / "text_file"), "--mode", "match"]) + runner.invoke(app, args=[text, "--mode", "match"]) class_mock.assert_called_once_with(text, initial_mode="match", initial_pattern=None) - - -def test_no_stdin_error(monkeypatch: MonkeyPatch) -> None: - """ - Couldn't find a better way to test the CLI without patching everything :( - """ - runner = CliRunner() - isatty_mock = Mock() - with monkeypatch.context(): - isatty_mock.return_value = True - monkeypatch.setattr("rexi.cli.is_stdin_a_tty", isatty_mock) - result = runner.invoke(app) - assert "Invalid value" in result.output - - -@pytest.mark.parametrize("input_value", [True, False]) -def test_is_stdin_a_tty(monkeypatch: MonkeyPatch, input_value: bool) -> None: - isatty_mock = Mock() - with monkeypatch.context(): - isatty_mock.return_value = input_value - monkeypatch.setattr("rexi.cli.sys.stdin.isatty", isatty_mock) - assert is_stdin_a_tty() == input_value