dynamisk-rettsstat/tests/test_arbeidskopi.py
Kjell Tore Guttormsen 03151cfb3b
feat(scenario): scenario runner, extensions and working copy
scenario.py runs all five simulators of the core from a JSON scenario file,
with sweeps, and reproduces 20 of the note's data files (14 byte for byte,
6 column-wise). Extensions live outside the core and must reproduce it
exactly in a limit case; paadrag_tidsserie is the worked example.
arbeidskopi.py gives the user a copy of the model they can change.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-11 14:17:32 +01:00

102 lines
4.4 KiB
Python

# Copyright (c) 2026 Kjell Tore Guttormsen. MIT License, see LICENSE.
"""arbeidskopi.py: kopien lages, nekter en mappe som ikke er tom, og kan kjøres med --modell."""
from __future__ import annotations
from typing import TYPE_CHECKING
import pytest
from conftest import EKSEMPLER, FASIT, ROT, kjor
if TYPE_CHECKING:
from pathlib import Path
KJEDE_S2 = EKSEMPLER / "scenarioer" / "notatet" / "kjede_s2.json"
@pytest.fixture
def arbeidskopi(tmp_path: Path) -> Path:
"""En arbeidskopi laget med kjor.py arbeidskopi."""
mal = tmp_path / "rettsstat-modell"
prosess = kjor("arbeidskopi", str(mal))
assert prosess.returncode == 0, prosess.stderr
assert f"Arbeidskopien er laget i {mal}" in prosess.stdout
return mal
def test_kopien_har_mappene_og_les_meg(arbeidskopi: Path) -> None:
for navn in ("modell", "eksempler", "fasit", "tests"):
assert (arbeidskopi / navn).is_dir(), navn
for navn in ("modell/kjor.py", "modell/scenario.py", "modell/kjerne/sim.py", "modell/kjerne/KILDE.json",
"modell/utvidelser/paadrag_tidsserie.py", "fasit/data/p3.dat",
"eksempler/scenarioer/notatet/p3.json"):
assert (arbeidskopi / navn).is_file(), navn
for navn in ("modell/kjerne/sim.py", "fasit/data/endo_ko.dat"):
assert (arbeidskopi / navn).read_bytes() == (ROT / navn).read_bytes()
if (ROT / "docs").is_dir():
assert sorted(p.name for p in (arbeidskopi / "docs").iterdir()) == \
sorted(p.name for p in (ROT / "docs").iterdir() if p.is_file())
les_meg = (arbeidskopi / "LES-MEG.md").read_text(encoding="utf-8")
for tekst in ("Alt i mappa kan endres, også kjernen", f"python3 {arbeidskopi / 'modell' / 'kjor.py'} scenario",
"kontroll", "«bit for bit som notatet»", "«endret: ...»", "docs/", "BIDRA.md"):
assert tekst in les_meg, tekst
def test_kopien_har_ikke_mellomlagre_eller_resultater(arbeidskopi: Path) -> None:
uonsket = {".venv", "venv", "__pycache__", ".pytest_cache", ".mypy_cache", ".ruff_cache", "resultater"}
funnet = [p for p in arbeidskopi.rglob("*") if p.name in uonsket or p.suffix == ".pyc"]
assert funnet == []
def test_nekter_mappe_som_ikke_er_tom(tmp_path: Path) -> None:
mal = tmp_path / "opptatt"
mal.mkdir()
(mal / "notat.txt").write_text("mitt", encoding="utf-8")
prosess = kjor("arbeidskopi", str(mal))
assert prosess.returncode == 2
assert "finnes og er ikke tom" in prosess.stderr
assert sorted(p.name for p in mal.iterdir()) == ["notat.txt"]
def test_tom_mappe_er_greit(tmp_path: Path) -> None:
mal = tmp_path / "tom"
mal.mkdir()
assert kjor("arbeidskopi", str(mal)).returncode == 0
assert (mal / "LES-MEG.md").is_file()
@pytest.mark.parametrize("args", [[], ["a", "b"]])
def test_feil_bruk(args: list[str]) -> None:
prosess = kjor("arbeidskopi", *args)
assert prosess.returncode == 2
assert "arbeidskopi <mappe>" in prosess.stderr
def test_nekter_mappe_inne_i_det_som_kopieres(tmp_path: Path, arbeidskopi: Path) -> None:
mal = arbeidskopi / "eksempler" / "ny"
prosess = kjor("--modell", str(arbeidskopi), "arbeidskopi", str(mal))
assert prosess.returncode == 2, prosess.stdout
assert "ligger inne i" in prosess.stderr
assert not mal.exists()
assert not (tmp_path / "ny").exists()
def test_scenario_kjorer_fra_kopien_med_modell(arbeidskopi: Path, tmp_path: Path) -> None:
ut = tmp_path / "ut"
prosess = kjor("--modell", str(arbeidskopi), "scenario", str(KJEDE_S2), "--ut", str(ut))
assert prosess.returncode == 0, prosess.stderr
assert (ut / "kjede_s2.dat").read_bytes() == (FASIT / "data" / "kjede_s2.dat").read_bytes()
def test_endring_i_kopiens_kjerne_brukes(arbeidskopi: Path, tmp_path: Path) -> None:
sim = arbeidskopi / "modell" / "kjerne" / "sim.py"
tekst = sim.read_text(encoding="utf-8")
assert "shock=1.30," in tekst
sim.write_text(tekst.replace("shock=1.30,", "shock=1.40,", 1), encoding="utf-8")
ut = tmp_path / "ut"
prosess = kjor("--modell", str(arbeidskopi), "scenario", str(KJEDE_S2), "--ut", str(ut))
assert prosess.returncode == 0, prosess.stderr
assert (ut / "kjede_s2.dat").read_bytes() != (FASIT / "data" / "kjede_s2.dat").read_bytes()
plugin = kjor("scenario", str(KJEDE_S2), "--ut", str(tmp_path / "plugin"))
assert plugin.returncode == 0, plugin.stderr
assert (tmp_path / "plugin" / "kjede_s2.dat").read_bytes() == (FASIT / "data" / "kjede_s2.dat").read_bytes()