generated from coulomb/repo-seed
Deliverables: - src/local_identity/gecos.py: /etc/passwd GECOS parsing, current_username() - src/local_identity/user.py: UserRecord dataclass, ProductionIdentity, make_test_user() - Pure test-user derivation: <user>N / +testN email alias / source_user tracking - src/local_identity/store.py: file store CRUD backed by LOCAL_IDENTITY_HOME - ~/.local-identity/ mode 700, user files mode 600 - All path lookups dynamic (env-var override enables clean test isolation) - src/local_identity/cli.py: init/list/show commands; email from flag > config > prompt - pyproject.toml + uv.lock: pyyaml dep, local-identity script entry point Tests (41 passing): - test_gecos.py: 9 tests — simple/comma/empty/non-ASCII/whitespace GECOS, fallback - test_user.py: 14 tests — test-user derivation, YAML roundtrip, non-ASCII, idempotency - test_store.py: 18 tests — dir creation, permissions (700/600), CRUD, list, config, idempotency (reinit with --force produces identical users) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
56 lines
2.0 KiB
Python
56 lines
2.0 KiB
Python
"""Tests for GECOS / passwd parsing."""
|
|
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
import pytest
|
|
|
|
from local_identity.gecos import get_gecos_fullname, current_username
|
|
|
|
|
|
def _mock_entry(gecos: str) -> MagicMock:
|
|
entry = MagicMock()
|
|
entry.pw_gecos = gecos
|
|
return entry
|
|
|
|
|
|
class TestGetGecosFullname:
|
|
def test_simple_name(self):
|
|
with patch("pwd.getpwnam", return_value=_mock_entry("Bernd Worsch")):
|
|
assert get_gecos_fullname("tegwick") == "Bernd Worsch"
|
|
|
|
def test_name_with_comma_fields(self):
|
|
with patch("pwd.getpwnam", return_value=_mock_entry("Bernd Worsch,Room 42,+49-555-1234")):
|
|
assert get_gecos_fullname("tegwick") == "Bernd Worsch"
|
|
|
|
def test_empty_gecos_falls_back_to_username(self):
|
|
with patch("pwd.getpwnam", return_value=_mock_entry("")):
|
|
assert get_gecos_fullname("tegwick") == "tegwick"
|
|
|
|
def test_only_commas(self):
|
|
with patch("pwd.getpwnam", return_value=_mock_entry(",,,,")):
|
|
assert get_gecos_fullname("tegwick") == "tegwick"
|
|
|
|
def test_whitespace_stripped(self):
|
|
with patch("pwd.getpwnam", return_value=_mock_entry(" Bernd Worsch ,,")):
|
|
assert get_gecos_fullname("tegwick") == "Bernd Worsch"
|
|
|
|
def test_non_ascii_name(self):
|
|
with patch("pwd.getpwnam", return_value=_mock_entry("Ärger Müller,,")):
|
|
assert get_gecos_fullname("amueller") == "Ärger Müller"
|
|
|
|
def test_user_not_in_passwd(self):
|
|
with patch("pwd.getpwnam", side_effect=KeyError("nobody")):
|
|
assert get_gecos_fullname("nobody") == "nobody"
|
|
|
|
|
|
class TestCurrentUsername:
|
|
def test_reads_user_env_var(self, monkeypatch):
|
|
monkeypatch.setenv("USER", "tegwick")
|
|
monkeypatch.delenv("LOGNAME", raising=False)
|
|
assert current_username() == "tegwick"
|
|
|
|
def test_falls_back_to_logname(self, monkeypatch):
|
|
monkeypatch.delenv("USER", raising=False)
|
|
monkeypatch.setenv("LOGNAME", "tegwick")
|
|
assert current_username() == "tegwick"
|