#!/usr/bin/env python3 """Fixture и побайтная проверка транзакционного overwrite P19.""" from __future__ import annotations import pathlib import sys def payload(seed: int, size: int) -> bytes: return bytes(((index * 29 + seed) & 0xFF) for index in range(size)) SOURCES = { "NORMAL.BIN": payload(11, 4097), "READONLY.BIN": payload(23, 8193), "ABSENT.BIN": payload(37, 17), "COLLIDE.BIN": payload(51, 4096), "ROLLBACK.BIN": payload(67, 4096), } OLD = { "NORMAL.BIN": b"old-normal-target", "READONLY.BIN": b"old-readonly-target", "COLLIDE.BIN": b"old-collision-target", "ROLLBACK.BIN": b"old-rollback-must-survive", } COLLISION = b"pre-existing backup name must survive" def create(root: pathlib.Path) -> None: source = root / "SOURCE" target = root / "TARGET" source.mkdir(parents=True) target.mkdir(parents=True) for name, data in SOURCES.items(): (source / name).write_bytes(data) for name, data in OLD.items(): (target / name).write_bytes(data) (target / "~SB0000.BAK").write_bytes(COLLISION) def verify(root: pathlib.Path) -> None: target = root / "TARGET" expected = { "NORMAL.BIN": SOURCES["NORMAL.BIN"], "READONLY.BIN": SOURCES["READONLY.BIN"], "COLLIDE.BIN": SOURCES["COLLIDE.BIN"], "ABSENT.BIN": SOURCES["ABSENT.BIN"], "RENAMED.BIN": SOURCES["ABSENT.BIN"], "ROLLBACK.BIN": OLD["ROLLBACK.BIN"], "~SB0000.BAK": COLLISION, } failures: list[str] = [] for name, data in expected.items(): path = target / name if not path.is_file() or path.read_bytes() != data: failures.append(f"неверный target {name}") unexpected = sorted( path.name for path in target.glob("~SB*.BAK") if path.name.upper() != "~SB0000.BAK" ) if unexpected: failures.append(f"оставлены служебные backup: {unexpected!r}") result = root / "RESULT.TXT" text = result.read_text("ascii", errors="replace") if result.exists() else "" if "ALL PASS" not in text: failures.append("target-probe не записал ALL PASS") if failures: for failure in failures: print(f"FAIL: {failure}") raise SystemExit(1) print("PASS: transactional overwrite, readonly, collision and rollback.") def main() -> None: if len(sys.argv) != 3 or sys.argv[1] not in {"create", "verify"}: raise SystemExit(f"usage: {sys.argv[0]} create|verify PATH") root = pathlib.Path(sys.argv[2]) if sys.argv[1] == "create": create(root) else: verify(root) if __name__ == "__main__": main()