Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0145ZKPLMVeqM47z2jxxokym
78 lines
2.5 KiB
Python
78 lines
2.5 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))
|
|
|
|
|
|
def test_estimate_equals_hand_computed() -> None:
|
|
"""Anchor the integer-øre math: m-cheap = 10 øre/1k, effort standard (100%), max_tokens 100_000
|
|
→ 100_000*100//100 * 10 // 1000 = 1000 øre/run; 3 projects → 3000 øre."""
|
|
pricing = costsim.PricingContract(**_VALID_PRICING)
|
|
assert costsim.estimate_run_ore("m-cheap", "standard", pricing, max_tokens=100_000) == 1000
|
|
assert (
|
|
costsim.estimate_portfolio_ore(
|
|
"m-cheap", "standard", pricing, n_projects=3, max_tokens=100_000
|
|
)
|
|
== 3000
|
|
)
|
|
|
|
|
|
def test_unknown_effort_raises() -> None:
|
|
pricing = costsim.PricingContract(**_VALID_PRICING)
|
|
with pytest.raises(ValueError, match="unknown effort"):
|
|
costsim.estimate_run_ore("m-cheap", "turbo", pricing)
|