Files
net-kingdom/local-identity/tests/test_cli.py
tegwick 666a56f4ed feat(local-identity): add --username and --fullname overrides to init
Resolves the system identity mismatch between the Linux username (worsch)
and the bootstrap identity (tegwick / Bernd Worsch / custom email).

Resolution order for all three fields: flag > config > system derivation.
Config is updated on every init so --force reinits are idempotent without
repeating the flags.

- cli.py: extract _resolve_init_params(); add --username / --fullname args;
  persist all three fields to config.yaml on init
- tests/test_cli.py: 13 new tests covering flag priority, config fallback,
  system derivation, config persistence, idempotent --force reinit

54 tests passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 00:11:04 +01:00

152 lines
6.4 KiB
Python

"""
Tests for CLI init parameter resolution and command behaviour.
cmd_init resolution order: flag > config > system derivation.
All three identity fields (username, fullname, email) follow this pattern.
"""
import argparse
from unittest.mock import patch
import pytest
from local_identity.cli import _resolve_init_params, cmd_init
from local_identity.store import init_dirs, list_users, read_config, read_user
def _args(username=None, fullname=None, email=None, force=False):
"""Build a minimal Namespace for _resolve_init_params / cmd_init."""
ns = argparse.Namespace()
ns.username = username
ns.fullname = fullname
ns.email = email
ns.force = force
ns.func = cmd_init
return ns
# ------------------------------------------------------------------ #
# _resolve_init_params #
# ------------------------------------------------------------------ #
class TestResolveInitParams:
def test_flags_take_priority_over_config_and_system(self):
config = {"username": "from_config", "fullname": "Config Name", "email": "config@x.com"}
with (
patch("local_identity.cli.current_username", return_value="system_user"),
patch("local_identity.cli.get_gecos_fullname", return_value="System Name"),
):
u, f, e = _resolve_init_params(
_args(username="tegwick", fullname="Bernd Worsch", email="bernd@example.com"),
config,
)
assert u == "tegwick"
assert f == "Bernd Worsch"
assert e == "bernd@example.com"
def test_config_takes_priority_over_system(self):
config = {"username": "tegwick", "fullname": "Bernd Worsch", "email": "bernd@example.com"}
with (
patch("local_identity.cli.current_username", return_value="worsch"),
patch("local_identity.cli.get_gecos_fullname", return_value="worsch"),
):
u, f, e = _resolve_init_params(_args(), config)
assert u == "tegwick"
assert f == "Bernd Worsch"
assert e == "bernd@example.com"
def test_system_derivation_when_no_flags_or_config(self):
config = {}
with (
patch("local_identity.cli.current_username", return_value="worsch"),
patch("local_identity.cli.get_gecos_fullname", return_value="Bernd Worsch"),
):
u, f, e = _resolve_init_params(_args(), config)
assert u == "worsch"
assert f == "Bernd Worsch"
assert e == "" # no default; caller must prompt
def test_flag_username_overrides_config_username(self):
config = {"username": "wrong", "fullname": "X", "email": "x@x.com"}
with patch("local_identity.cli.current_username", return_value="system"):
u, _, _ = _resolve_init_params(_args(username="tegwick"), config)
assert u == "tegwick"
def test_flag_fullname_overrides_config_fullname(self):
config = {"username": "u", "fullname": "Wrong Name", "email": "x@x.com"}
with patch("local_identity.cli.get_gecos_fullname", return_value="Gecos Name"):
_, f, _ = _resolve_init_params(_args(fullname="Bernd Worsch"), config)
assert f == "Bernd Worsch"
def test_gecos_used_when_no_fullname_flag_or_config(self):
config = {"username": "tegwick", "email": "x@x.com"}
with patch("local_identity.cli.get_gecos_fullname", return_value="Bernd Worsch"):
_, f, _ = _resolve_init_params(_args(), config)
assert f == "Bernd Worsch"
def test_empty_email_when_absent_everywhere(self):
config = {"username": "u", "fullname": "N"}
_, _, e = _resolve_init_params(_args(), config)
assert e == ""
# ------------------------------------------------------------------ #
# cmd_init integration (uses tmp_store fixture) #
# ------------------------------------------------------------------ #
class TestCmdInit:
def test_init_with_all_flags(self, tmp_store):
with (
patch("local_identity.cli.current_username", return_value="worsch"),
patch("local_identity.cli.get_gecos_fullname", return_value="worsch"),
):
cmd_init(_args(username="tegwick", fullname="Bernd Worsch", email="bernd@example.com"))
primary = read_user("tegwick")
assert primary.username == "tegwick"
assert primary.fullname == "Bernd Worsch"
assert primary.email == "bernd@example.com"
def test_test_users_derived_from_override_username(self, tmp_store):
with patch("local_identity.cli.current_username", return_value="worsch"):
cmd_init(_args(username="tegwick", fullname="Bernd Worsch", email="bernd@example.com"))
users = {u.username for u in list_users()}
assert users == {"tegwick", "tegwick1", "tegwick2"}
def test_test_user_email_uses_override_email(self, tmp_store):
with patch("local_identity.cli.current_username", return_value="worsch"):
cmd_init(_args(username="tegwick", fullname="Bernd Worsch", email="bernd@example.com"))
assert read_user("tegwick1").email == "bernd+test1@example.com"
assert read_user("tegwick2").email == "bernd+test2@example.com"
def test_overrides_persisted_to_config(self, tmp_store):
with patch("local_identity.cli.current_username", return_value="worsch"):
cmd_init(_args(username="tegwick", fullname="Bernd Worsch", email="bernd@example.com"))
cfg = read_config()
assert cfg["username"] == "tegwick"
assert cfg["fullname"] == "Bernd Worsch"
assert cfg["email"] == "bernd@example.com"
def test_force_reinit_reads_config_without_flags(self, tmp_store):
with patch("local_identity.cli.current_username", return_value="worsch"):
cmd_init(_args(username="tegwick", fullname="Bernd Worsch", email="bernd@example.com"))
# Second init with --force and no flags — should reuse config
cmd_init(_args(force=True))
primary = read_user("tegwick")
assert primary.username == "tegwick"
assert primary.fullname == "Bernd Worsch"
def test_fails_if_store_exists_without_force(self, tmp_store):
with (
patch("local_identity.cli.current_username", return_value="worsch"),
pytest.raises(SystemExit) as exc_info,
):
cmd_init(_args(email="a@b.com"))
cmd_init(_args(email="a@b.com")) # second call should fail
assert exc_info.value.code == 1