3e779be6f3
CI / lint (push) Failing after 13m4s
CI / test (3.11, ubuntu-latest) (push) Failing after 2m4s
CI / test (3.13, ubuntu-latest) (push) Successful in 13m30s
CI / test (3.14, ubuntu-latest) (push) Successful in 17m21s
CI / test (3.12, ubuntu-latest) (push) Successful in 17m55s
CI / discover-apps-ps (push) Successful in 1m56s
CI / test (3.9, ubuntu-latest) (push) Successful in 13m17s
CI / test (3.10, ubuntu-latest) (push) Successful in 26m21s
CI / audit (push) Successful in 13m38s
Deploy site / deploy (push) Has been cancelled
CI / test (3.14, ubuntu-24.04-arm) (push) Has been cancelled
195 lines
6.1 KiB
Python
195 lines
6.1 KiB
Python
# SPDX-License-Identifier: MIT
|
|
"""Tests for the CLI first-run setup prompt (#255 PR 1)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from winpodx.cli.first_run import (
|
|
_SKIP_COMMANDS,
|
|
maybe_run_first_run_prompt,
|
|
should_prompt,
|
|
)
|
|
from winpodx.core.config import Config
|
|
|
|
|
|
def _captured_print():
|
|
captured: list[str] = []
|
|
|
|
def _emit(line: str) -> None:
|
|
captured.append(line)
|
|
|
|
return _emit, captured
|
|
|
|
|
|
def _scripted_input(answers: list[str]):
|
|
it = iter(answers)
|
|
|
|
def _read(_prompt: str) -> str:
|
|
return next(it)
|
|
|
|
return _read
|
|
|
|
|
|
class TestShouldPrompt:
|
|
def test_none_command_skips(self):
|
|
assert should_prompt(None) is False
|
|
|
|
def test_skip_list_commands_skip(self):
|
|
for cmd in _SKIP_COMMANDS:
|
|
assert should_prompt(cmd) is False, f"{cmd} should be in skip list"
|
|
|
|
def test_other_commands_eligible(self, monkeypatch):
|
|
# Force TTY=True so the stdin check passes.
|
|
monkeypatch.setattr("sys.stdin.isatty", lambda: True)
|
|
for cmd in ("app", "pod", "check", "timesync", "debloat"):
|
|
assert should_prompt(cmd) is True
|
|
|
|
def test_non_tty_stdin_skips(self, monkeypatch):
|
|
monkeypatch.setattr("sys.stdin.isatty", lambda: False)
|
|
assert should_prompt("app") is False
|
|
|
|
|
|
class TestMaybeRunFirstRunPrompt:
|
|
def test_skipped_command_returns_false(self, monkeypatch, tmp_path):
|
|
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path))
|
|
out, _ = _captured_print()
|
|
ran = maybe_run_first_run_prompt(
|
|
"info",
|
|
input_fn=_scripted_input([]),
|
|
print_fn=out,
|
|
)
|
|
assert ran is False
|
|
|
|
def test_already_initialized_returns_false(self, monkeypatch, tmp_path):
|
|
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path))
|
|
monkeypatch.setattr("sys.stdin.isatty", lambda: True)
|
|
cfg = Config()
|
|
cfg.pod.initialized = True
|
|
cfg.save()
|
|
|
|
out, _ = _captured_print()
|
|
ran = maybe_run_first_run_prompt(
|
|
"app",
|
|
input_fn=_scripted_input([]),
|
|
print_fn=out,
|
|
)
|
|
assert ran is False
|
|
|
|
def test_no_answer_skips(self, monkeypatch, tmp_path):
|
|
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path))
|
|
monkeypatch.setattr("sys.stdin.isatty", lambda: True)
|
|
Config().save() # initialized = False
|
|
|
|
out, lines = _captured_print()
|
|
ran = maybe_run_first_run_prompt(
|
|
"app",
|
|
input_fn=_scripted_input(["n"]),
|
|
print_fn=out,
|
|
)
|
|
assert ran is False
|
|
joined = "\n".join(lines)
|
|
assert "Run setup now" in joined
|
|
|
|
def test_eof_skips(self, monkeypatch, tmp_path):
|
|
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path))
|
|
monkeypatch.setattr("sys.stdin.isatty", lambda: True)
|
|
Config().save()
|
|
|
|
def _eof(_prompt):
|
|
raise EOFError
|
|
|
|
out, _ = _captured_print()
|
|
ran = maybe_run_first_run_prompt("app", input_fn=_eof, print_fn=out)
|
|
assert ran is False
|
|
|
|
def test_yes_invokes_setup_auto(self, monkeypatch, tmp_path):
|
|
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path))
|
|
monkeypatch.setattr("sys.stdin.isatty", lambda: True)
|
|
Config().save()
|
|
|
|
called_with: dict = {}
|
|
|
|
def _fake_handle_setup(args):
|
|
called_with["non_interactive"] = args.non_interactive
|
|
called_with["customize"] = args.customize
|
|
|
|
monkeypatch.setattr("winpodx.cli.setup_cmd.handle_setup", _fake_handle_setup)
|
|
|
|
out, _ = _captured_print()
|
|
ran = maybe_run_first_run_prompt(
|
|
"app",
|
|
input_fn=_scripted_input(["y"]),
|
|
print_fn=out,
|
|
)
|
|
assert ran is True
|
|
assert called_with["non_interactive"] is True
|
|
assert called_with["customize"] is False
|
|
|
|
def test_custom_invokes_setup_customize(self, monkeypatch, tmp_path):
|
|
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path))
|
|
monkeypatch.setattr("sys.stdin.isatty", lambda: True)
|
|
Config().save()
|
|
|
|
called_with: dict = {}
|
|
|
|
def _fake_handle_setup(args):
|
|
called_with["non_interactive"] = args.non_interactive
|
|
called_with["customize"] = args.customize
|
|
|
|
monkeypatch.setattr("winpodx.cli.setup_cmd.handle_setup", _fake_handle_setup)
|
|
|
|
out, _ = _captured_print()
|
|
ran = maybe_run_first_run_prompt(
|
|
"app",
|
|
input_fn=_scripted_input(["c"]),
|
|
print_fn=out,
|
|
)
|
|
assert ran is True
|
|
assert called_with["non_interactive"] is False
|
|
assert called_with["customize"] is True
|
|
|
|
def test_empty_answer_defaults_to_yes(self, monkeypatch, tmp_path):
|
|
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path))
|
|
monkeypatch.setattr("sys.stdin.isatty", lambda: True)
|
|
Config().save()
|
|
|
|
called: list = []
|
|
monkeypatch.setattr(
|
|
"winpodx.cli.setup_cmd.handle_setup",
|
|
lambda args: called.append(("non_interactive", args.non_interactive)),
|
|
)
|
|
|
|
out, _ = _captured_print()
|
|
ran = maybe_run_first_run_prompt(
|
|
"app",
|
|
input_fn=_scripted_input([""]),
|
|
print_fn=out,
|
|
)
|
|
assert ran is True
|
|
assert called[0] == ("non_interactive", True)
|
|
|
|
def test_unrecognised_answer_skips(self, monkeypatch, tmp_path):
|
|
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path))
|
|
monkeypatch.setattr("sys.stdin.isatty", lambda: True)
|
|
Config().save()
|
|
|
|
out, lines = _captured_print()
|
|
ran = maybe_run_first_run_prompt(
|
|
"app",
|
|
input_fn=_scripted_input(["bogus"]),
|
|
print_fn=out,
|
|
)
|
|
assert ran is False
|
|
joined = "\n".join(lines)
|
|
assert "Unrecognised choice" in joined
|
|
|
|
|
|
class TestInstallSourceDetection:
|
|
"""Smoke test the install_source module from a known path."""
|
|
|
|
def test_unknown_when_no_binary(self):
|
|
from winpodx.utils.install_source import detect
|
|
|
|
result = detect(binary_path="/nonexistent/path/winpodx")
|
|
assert result.kind == "unknown"
|
|
assert "not detected" in result.label
|