Files
PuGa/tests/test_plan_push.py
T
dodoxandClaude Sonnet 5 4c186ac677 Add the puga command and plan pull; document the UI plan workflow
- pyproject.toml + puga/cli.py: `pip install -e .` installs a `puga <tool>` command, so no
  venv path is needed (replaces requirements.txt)
- tools/plan_push.py: `pull <uuid>` reads a plan (incl. UI edits) back into a YAML spec;
  recipe entries may carry an amount so switched-off recipes round trip; fixes a variable
  that overwrote the plan name in build_payload, with a regression test
- README: usage with the puga command, and a section on working on the same plans in the
  PRUNplanner UI and from Claude (write, edit in UI, read back)
- CLAUDE.md updated accordingly

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 00:37:20 +02:00

45 lines
2.2 KiB
Python

import importlib.util, sys
from pathlib import Path
import pytest
spec = importlib.util.spec_from_file_location("plan_push", Path(__file__).resolve().parent.parent / "tools" / "plan_push.py")
pp_tool = importlib.util.module_from_spec(spec)
spec.loader.exec_module(pp_tool)
R = [
{"recipe_id": "SME#6xALO 1xO 1xC=>3xAL", "building_ticker": "SME", "inputs": [{"material_ticker": t} for t in ("ALO", "O", "C")], "outputs": [{"material_ticker": "AL"}]},
{"recipe_id": "SME#6xALO 1xO 1xC 1xFLX=>4xAL", "building_ticker": "SME", "inputs": [{"material_ticker": t} for t in ("ALO", "O", "C", "FLX")], "outputs": [{"material_ticker": "AL"}]},
]
def test_resolve_by_ticker_sets_distinguishes_flux():
assert pp_tool.resolve_recipe("ALO,FLX,C,O=>AL", "SME", R).endswith("=>4xAL")
assert pp_tool.resolve_recipe("ALO,C,O=>AL", "SME", R).endswith("=>3xAL")
assert pp_tool.resolve_recipe("EXT#ALO", "EXT", R) == "EXT#ALO"
with pytest.raises(ValueError):
pp_tool.resolve_recipe("ALO=>AL", "SME", R)
def _spec(**kw):
s = dict(name="[PuGa] x", planet="ZV-759c", permits=1, cogc="METALLURGY", buildings=[{"building": "SME", "amount": 1, "recipes": ["ALO,C,O=>AL"]}])
s.update(kw)
return s
def test_guardrail_requires_prefix_and_validates():
ok = pp_tool.build_payload(_spec(), R, {"SME"})
assert ok["plan_cogc"] == "METALLURGY" and len(ok["plan_data"]["experts"]) == 9 and len(ok["plan_data"]["workforce"]) == 5
for bad in (dict(name="My plan"), dict(planet="ZV759c"), dict(permits=4), dict(cogc="FOO")):
with pytest.raises(ValueError):
pp_tool.build_payload(_spec(**bad), R, {"SME"})
with pytest.raises(ValueError):
pp_tool.build_payload(_spec(buildings=[{"building": "ZZZ", "amount": 1}]), R, {"SME"})
def test_recipe_dict_keeps_amount_and_does_not_clobber_plan_name():
"""Regression: a loop variable once overwrote the plan name; also switched-off recipes (amount 0) must round trip."""
spec = _spec(buildings=[{"building": "SME", "amount": 1, "recipes": [{"recipe": "ALO,C,O=>AL", "amount": 0}]}])
out = pp_tool.build_payload(spec, R, {"SME"})
assert out["plan_name"] == "[PuGa] x"
assert out["plan_data"]["buildings"][0]["active_recipes"] == [{"recipeid": "SME#6xALO 1xO 1xC=>3xAL", "amount": 0}]