More test coverage (71%)
This commit is contained in:
parent
9a2516d858
commit
f82fd894ca
8 changed files with 605 additions and 10 deletions
177
tests/test_cli_helpers.py
Normal file
177
tests/test_cli_helpers.py
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import configparser
|
||||
import types
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def test_discover_config_path_precedence(tmp_path: Path, monkeypatch):
|
||||
"""_discover_config_path: --config > ENROLL_CONFIG > ./enroll.ini > XDG."""
|
||||
from enroll.cli import _discover_config_path
|
||||
|
||||
cfg1 = tmp_path / "one.ini"
|
||||
cfg1.write_text("[enroll]\n", encoding="utf-8")
|
||||
|
||||
# Explicit --config should win.
|
||||
assert _discover_config_path(["--config", str(cfg1)]) == cfg1
|
||||
|
||||
# --no-config disables config loading.
|
||||
assert _discover_config_path(["--no-config", "--config", str(cfg1)]) is None
|
||||
|
||||
monkeypatch.chdir(tmp_path)
|
||||
|
||||
cfg2 = tmp_path / "two.ini"
|
||||
cfg2.write_text("[enroll]\n", encoding="utf-8")
|
||||
monkeypatch.setenv("ENROLL_CONFIG", str(cfg2))
|
||||
assert _discover_config_path([]) == cfg2
|
||||
|
||||
# Local ./enroll.ini fallback.
|
||||
monkeypatch.delenv("ENROLL_CONFIG", raising=False)
|
||||
local = tmp_path / "enroll.ini"
|
||||
local.write_text("[enroll]\n", encoding="utf-8")
|
||||
assert _discover_config_path([]) == local
|
||||
|
||||
# XDG fallback.
|
||||
local.unlink()
|
||||
xdg = tmp_path / "xdg"
|
||||
cfg3 = xdg / "enroll" / "enroll.ini"
|
||||
cfg3.parent.mkdir(parents=True)
|
||||
cfg3.write_text("[enroll]\n", encoding="utf-8")
|
||||
monkeypatch.setenv("XDG_CONFIG_HOME", str(xdg))
|
||||
assert _discover_config_path([]) == cfg3
|
||||
|
||||
|
||||
def test_config_value_parsing_and_list_splitting():
|
||||
from enroll.cli import _parse_bool, _split_list_value
|
||||
|
||||
assert _parse_bool("1") is True
|
||||
assert _parse_bool("yes") is True
|
||||
assert _parse_bool("false") is False
|
||||
|
||||
assert _parse_bool("maybe") is None
|
||||
|
||||
assert _split_list_value("a,b , c") == ["a", "b", "c"]
|
||||
# When newlines are present, we split on lines (not commas within a line).
|
||||
assert _split_list_value("a,b\nc") == ["a,b", "c"]
|
||||
assert _split_list_value("a\n\n b\n") == ["a", "b"]
|
||||
assert _split_list_value(" ") == []
|
||||
|
||||
|
||||
def test_section_to_argv_handles_types_and_unknown_keys(capsys):
|
||||
from enroll.cli import _section_to_argv
|
||||
|
||||
p = argparse.ArgumentParser(add_help=False)
|
||||
p.add_argument("--dangerous", action="store_true")
|
||||
p.add_argument("--no-color", dest="color", action="store_false")
|
||||
p.add_argument("--include-path", dest="include_path", action="append")
|
||||
p.add_argument("-v", action="count", default=0)
|
||||
p.add_argument("--out")
|
||||
|
||||
cfg = configparser.ConfigParser()
|
||||
cfg.read_dict(
|
||||
{
|
||||
"harvest": {
|
||||
"dangerous": "true",
|
||||
# Keys are matched by argparse dest; store_false actions still use dest.
|
||||
"color": "false",
|
||||
"include-path": "a,b,c",
|
||||
"v": "2",
|
||||
"out": "/tmp/bundle",
|
||||
"unknown": "ignored",
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
argv = _section_to_argv(p, cfg, "harvest")
|
||||
|
||||
# Boolean store_true.
|
||||
assert "--dangerous" in argv
|
||||
|
||||
# Boolean store_false: include the flag only when config wants False.
|
||||
assert "--no-color" in argv
|
||||
|
||||
# Append: split lists and add one flag per item.
|
||||
assert argv.count("--include-path") == 3
|
||||
assert "a" in argv and "b" in argv and "c" in argv
|
||||
|
||||
# Count: repeats.
|
||||
assert argv.count("-v") == 2
|
||||
|
||||
# Scalar.
|
||||
assert "--out" in argv and "/tmp/bundle" in argv
|
||||
|
||||
err = capsys.readouterr().err
|
||||
assert "unknown option" in err
|
||||
|
||||
|
||||
def test_inject_config_argv_inserts_global_and_subcommand(tmp_path: Path, capsys):
|
||||
from enroll.cli import _inject_config_argv
|
||||
|
||||
cfg = tmp_path / "enroll.ini"
|
||||
cfg.write_text(
|
||||
textwrap.dedent(
|
||||
"""
|
||||
[enroll]
|
||||
dangerous = true
|
||||
|
||||
[harvest]
|
||||
include-path = /etc/foo
|
||||
unknown = 1
|
||||
"""
|
||||
).strip()
|
||||
+ "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
root = argparse.ArgumentParser(add_help=False)
|
||||
root.add_argument("--dangerous", action="store_true")
|
||||
|
||||
harvest_p = argparse.ArgumentParser(add_help=False)
|
||||
harvest_p.add_argument("--include-path", dest="include_path", action="append")
|
||||
|
||||
argv = _inject_config_argv(
|
||||
["harvest", "--out", "x"],
|
||||
cfg_path=cfg,
|
||||
root_parser=root,
|
||||
subparsers={"harvest": harvest_p},
|
||||
)
|
||||
|
||||
# Global tokens should appear before the subcommand.
|
||||
assert argv[0] == "--dangerous"
|
||||
assert argv[1] == "harvest"
|
||||
|
||||
# Subcommand tokens should appear right after the subcommand.
|
||||
assert argv[2:4] == ["--include-path", "/etc/foo"]
|
||||
|
||||
# Unknown option should have produced a warning.
|
||||
assert "unknown option" in capsys.readouterr().err
|
||||
|
||||
|
||||
def test_resolve_sops_out_file(tmp_path: Path, monkeypatch):
|
||||
from enroll import cli
|
||||
|
||||
# Make a predictable cache dir for the default case.
|
||||
fake_cache = types.SimpleNamespace(dir=tmp_path / "cache")
|
||||
fake_cache.dir.mkdir(parents=True)
|
||||
monkeypatch.setattr(cli, "new_harvest_cache_dir", lambda hint=None: fake_cache)
|
||||
|
||||
# If out is a directory, use it directly.
|
||||
out_dir = tmp_path / "out"
|
||||
out_dir.mkdir()
|
||||
# The output filename is fixed; hint is only used when creating a cache dir.
|
||||
assert (
|
||||
cli._resolve_sops_out_file(out=out_dir, hint="bundle.tar.gz")
|
||||
== out_dir / "harvest.tar.gz.sops"
|
||||
)
|
||||
|
||||
# If out is a file path, keep it.
|
||||
out_file = tmp_path / "x.sops"
|
||||
assert cli._resolve_sops_out_file(out=out_file, hint="bundle.tar.gz") == out_file
|
||||
|
||||
# None uses the cache dir, and the name is fixed.
|
||||
assert (
|
||||
cli._resolve_sops_out_file(out=None, hint="bundle.tar.gz")
|
||||
== fake_cache.dir / "harvest.tar.gz.sops"
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue