73 lines
2.6 KiB
Python
73 lines
2.6 KiB
Python
"""Unit tests for porcelain parsing and ChangeType mapping (Section 6)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from git_auto_tracker.changes.models import ChangeType
|
|
from git_auto_tracker.errors import GitError
|
|
from git_auto_tracker.git.status import RawStatusEntry, parse_porcelain_z
|
|
|
|
|
|
def _build(entries: list[tuple[str, str, str | None]]) -> bytes:
|
|
"""Serialize porcelain -z records: 'XY path' + optional origin path."""
|
|
parts: list[bytes] = []
|
|
for xy, path, previous in entries:
|
|
parts.append(f"{xy} {path}".encode())
|
|
if previous:
|
|
parts.append(previous.encode())
|
|
return b"\x00".join(parts) + b"\x00"
|
|
|
|
|
|
class TestParsePorcelainZ:
|
|
def test_modified(self) -> None:
|
|
raw = _build([(" M", "config.xml", None)])
|
|
(entry,) = parse_porcelain_z(raw)
|
|
assert entry.path == "config.xml"
|
|
assert entry.change_type is ChangeType.MODIFIED
|
|
|
|
def test_untracked_is_added(self) -> None:
|
|
raw = _build([("??", "new.xml", None)])
|
|
(entry,) = parse_porcelain_z(raw)
|
|
assert entry.change_type is ChangeType.ADDED
|
|
|
|
def test_deleted(self) -> None:
|
|
raw = _build([(" D", "gone.xml", None)])
|
|
(entry,) = parse_porcelain_z(raw)
|
|
assert entry.change_type is ChangeType.DELETED
|
|
|
|
def test_staged_deletion(self) -> None:
|
|
raw = _build([("D ", "gone.xml", None)])
|
|
(entry,) = parse_porcelain_z(raw)
|
|
assert entry.change_type is ChangeType.DELETED
|
|
|
|
def test_rename_with_previous(self) -> None:
|
|
raw = _build([("R ", "new.xml", "old.xml")])
|
|
(entry,) = parse_porcelain_z(raw)
|
|
assert entry.change_type is ChangeType.RENAMED
|
|
assert entry.previous_path == "old.xml"
|
|
|
|
def test_filenames_with_spaces_and_unicode(self) -> None:
|
|
raw = _build([(" M", "Station PS101/räumliche Datei.xml", None)])
|
|
(entry,) = parse_porcelain_z(raw)
|
|
assert entry.path == "Station PS101/räumliche Datei.xml"
|
|
|
|
def test_trailing_empty_chunks_ignored(self) -> None:
|
|
raw = b"\x00\x00 M a.xml\x00\x00"
|
|
entries = parse_porcelain_z(raw)
|
|
assert len(entries) == 1
|
|
|
|
def test_invalid_xy_rejected(self) -> None:
|
|
with pytest.raises(GitError):
|
|
parse_porcelain_z(b"XX path.xml\x00")
|
|
|
|
|
|
class TestChangeTypeMapping:
|
|
def test_staged_addition(self) -> None:
|
|
entry = RawStatusEntry.from_zy_pair("A ", "a.xml", None)
|
|
assert entry.change_type is ChangeType.ADDED
|
|
|
|
def test_staged_rename(self) -> None:
|
|
entry = RawStatusEntry.from_zy_pair("R ", "a.xml", "b.xml")
|
|
assert entry.change_type is ChangeType.RENAMED
|