Coverage for tests/output/test_prompts.py: 86%
67 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-02-09 12:09 +0100
« prev ^ index » next coverage.py v6.5.0, created at 2023-02-09 12:09 +0100
1from __future__ import annotations
3import io
4from pathlib import Path
5from typing import Iterator
7import pytest
8from hypothesis import assume
9from hypothesis import given
10from hypothesis import HealthCheck
11from hypothesis import settings
12from hypothesis import strategies as st
13from pytest import CaptureFixture
14from pytest import MonkeyPatch
16from harbor_cli.output.prompts import float_prompt
17from harbor_cli.output.prompts import int_prompt
18from harbor_cli.output.prompts import path_prompt
19from harbor_cli.output.prompts import str_prompt
21# TODO: test defaults
24def leading_newline() -> Iterator[str]:
25 """Yields a leading newline and then no leading newline.
27 This helps us test whether or not empty inputs prompts the user to
28 input again.
29 """
30 yield "\n"
31 yield ""
34@pytest.mark.skip(reason="Flaky test in CI. Need to investigate.")
35@pytest.mark.parametrize("leading_newline", leading_newline())
36@given(st.text(min_size=1))
37@settings(suppress_health_check=[HealthCheck.function_scoped_fixture])
38def test_str_prompt(monkeypatch: MonkeyPatch, leading_newline: str, text: str) -> None:
39 assume(not text.isspace()) # not testing pure whitespace
40 stdin_str = leading_newline + text + "\n"
41 monkeypatch.setattr("sys.stdin", io.StringIO(stdin_str))
42 # Result is always stripped of whitespace, and newline = enter
43 # So anything after \n is
44 expect = next(t.strip() for t in text.split("\n") if t)
45 assert str_prompt("foo") == expect
48@pytest.mark.skip(reason="Flaky test in CI. Need to investigate.")
49@given(st.text())
50@settings(suppress_health_check=[HealthCheck.function_scoped_fixture])
51def test_str_prompt_empty_ok(monkeypatch: MonkeyPatch, text: str) -> None:
52 stdin_str = text + "\n"
53 monkeypatch.setattr("sys.stdin", io.StringIO(stdin_str))
54 # Result is always stripped of whitespace, and newline = enter
55 # So anything after \n is ignored
56 assert str_prompt("foo", empty_ok=True) == text.split("\n")[0].strip()
59@pytest.mark.parametrize("leading_newline", leading_newline())
60@pytest.mark.parametrize("leading_float", ["", "3.14159265358979\n"])
61@given(st.integers())
62@settings(suppress_health_check=[HealthCheck.function_scoped_fixture])
63def test_int_prompt(
64 monkeypatch: MonkeyPatch,
65 # Leading newline prompts for new input
66 leading_newline: str,
67 # Floating point numbers are invalid, and will prompt for new input
68 leading_float: str,
69 inp: int,
70) -> None:
71 stdin_str = leading_newline + leading_float + str(inp) + "\n"
72 monkeypatch.setattr("sys.stdin", io.StringIO(stdin_str))
73 assert int_prompt("foo") == inp
76@pytest.mark.parametrize("leading_newline", leading_newline())
77@given(st.floats(allow_nan=False))
78@settings(suppress_health_check=[HealthCheck.function_scoped_fixture])
79def test_float_prompt(
80 monkeypatch: MonkeyPatch, capsys: CaptureFixture, leading_newline: str, inp: float
81) -> None:
82 # so we can test that empty input prompts again
83 stdin_str = leading_newline + str(inp) + "\n"
84 monkeypatch.setattr("sys.stdin", io.StringIO(stdin_str))
85 assert float_prompt("foo") == inp
86 if leading_newline:
87 # Rich prints this message to stdout for some reason
88 assert "Please enter a number" in capsys.readouterr().out
91@pytest.mark.parametrize("leading_newline", leading_newline())
92def test_float_prompt_nan(
93 monkeypatch: MonkeyPatch, leading_newline: str, capsys: CaptureFixture
94) -> None:
95 # if we give it a nan, it will prompt for new input
96 # so we need to give it a valid input after that
97 stdin_str = leading_newline + "nan\n" + "0.0\n"
98 monkeypatch.setattr("sys.stdin", io.StringIO(stdin_str))
99 assert float_prompt("foo") == 0.0
100 stdout, stderr = capsys.readouterr()
101 assert "NaN" in stderr
102 if leading_newline:
103 # Rich prints this message to stdout for some reason
104 assert "Please enter a number" in stdout
107def test_path_prompt(monkeypatch: MonkeyPatch, tmp_path: Path) -> None:
108 p = tmp_path / "test.txt"
109 p = p.resolve().absolute()
110 monkeypatch.setattr("sys.stdin", io.StringIO(f"{p}\n"))
111 assert path_prompt("foo") == p