portfolio-optimiser/tests/test_costsim.py

59 lines
1.8 KiB
Python

"""S3.6 costsim — unit tests: pricing load/fail-fast, deterministic estimate, table, CLI.
Load-bearing detach seams live in ``test_costsim_loadbearing.py``; these are the happy-path +
schema unit tests.
"""
from __future__ import annotations
import json
from pathlib import Path
import pytest
from pydantic import ValidationError
from portfolio_optimiser import costsim
_VALID_PRICING = {
"source": "unit-test prices",
"date": "2026-07-15",
"models": {
"m-cheap": {
"ore_per_1k_tokens": 10,
"quality_guidance": {"note": "cheap draft model", "source": "test-src 2026-07-15"},
},
"m-dear": {
"ore_per_1k_tokens": 50,
"quality_guidance": {"note": "stronger reasoning", "source": "test-src 2026-07-15"},
},
},
}
def _write(tmp_path: Path, data: dict) -> Path:
p = tmp_path / "pricing.json"
p.write_text(json.dumps(data), encoding="utf-8")
return p
def test_load_pricing_valid(tmp_path: Path) -> None:
pricing = costsim.load_pricing(_write(tmp_path, _VALID_PRICING))
assert pricing.models["m-cheap"].ore_per_1k_tokens == 10
assert pricing.source == "unit-test prices"
def test_load_pricing_bundled_default() -> None:
"""No path → the packaged data/pricing.example.json loads and prices the local model."""
pricing = costsim.load_pricing()
assert "qwen3:4b" in pricing.models
def test_load_pricing_missing_file_raises(tmp_path: Path) -> None:
with pytest.raises(FileNotFoundError):
costsim.load_pricing(tmp_path / "nope.json")
def test_load_pricing_missing_provenance_raises(tmp_path: Path) -> None:
bad = {"models": _VALID_PRICING["models"]} # no source/date
with pytest.raises(ValidationError):
costsim.load_pricing(_write(tmp_path, bad))