Files
net-kingdom/local-identity/tests/test_gecos.py
tegwick 4491beaffe feat(local-identity): implement Stage 1 — core file store (NK-WP-0002-T01)
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>
2026-03-02 00:01:54 +01:00

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"