diff --git a/src/flight_cli/_watch.py b/src/flight_cli/_watch.py index f81972fd..4f57849e 100644 --- a/src/flight_cli/_watch.py +++ b/src/flight_cli/_watch.py @@ -171,10 +171,16 @@ def _locked() -> Generator[None]: os.close(fd) +# The currency and the exception name are remote text, and a reader of stdout takes +# each line as one watch, so the newline CTRL keeps would split a record in two. A +# failure line is one record too: the store path comes from the environment. +_ONE_LINE: Final = {**CTRL, ord("\n"): " "} + + def _fail(message: str, code: int) -> typer.Exit: """The store path comes from the environment and a key in an unusable store from the file, so either can carry characters a terminal acts on.""" - typer.echo(message.translate(CTRL), err=True) + typer.echo(message.translate(_ONE_LINE), err=True) return typer.Exit(code) @@ -314,11 +320,6 @@ def _poll(w: Watch, last: _Seen | None) -> tuple[str, _Seen | None]: return f"{head}: lowest {amount} on {day}{verdict}{change}", fare -# The currency and the exception name are remote text, and a reader of stdout takes -# each line as one watch, so the newline CTRL keeps would split a record in two. -_ONE_LINE: Final = {**CTRL, ord("\n"): " "} - - @watch_app.command("run") def watch_run() -> None: """Price each saved watch once and print a line each, with the change since the last diff --git a/tests/test_watch_config_path_newline.py b/tests/test_watch_config_path_newline.py new file mode 100644 index 00000000..e0a77bb6 --- /dev/null +++ b/tests/test_watch_config_path_newline.py @@ -0,0 +1,28 @@ +"""`flight watch add` names a config path that carries a newline on one stderr line.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +from typer.testing import CliRunner + +from flight_cli import cli + +if TYPE_CHECKING: + from pathlib import Path + + import pytest + + +def test_a_config_path_with_a_newline_is_named_on_one_line( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + directory = tmp_path / "h" / "line1\nline2" + assert directory.is_relative_to(tmp_path) + directory.parent.mkdir() + _ = directory.write_text("not a directory") + monkeypatch.setenv("FLIGHT_CLI_CONFIG_DIR", str(directory)) + result = CliRunner().invoke(cli.app, ["watch", "add", "JFK", "LHR"]) + assert (result.exit_code, type(result.exception).__name__) == (1, "SystemExit"), result.output + named = str(directory).replace("\n", " ") + assert result.output.splitlines() == [f"{named} cannot be created: File exists"]