defmodule Symbiont.DispatcherTest do use ExUnit.Case, async: false @moduletag :capture_log setup do tmp_dir = Path.join(System.tmp_dir!(), "symbiont_dispatch_test_#{:rand.uniform(999_999)}") File.mkdir_p!(tmp_dir) # Start a fresh ledger for logging if Process.whereis(Symbiont.Ledger), do: GenServer.stop(Symbiont.Ledger) {:ok, _pid} = Symbiont.Ledger.start_link(data_dir: tmp_dir) on_exit(fn -> if Process.whereis(Symbiont.Ledger), do: GenServer.stop(Symbiont.Ledger) File.rm_rf!(tmp_dir) end) %{tmp_dir: tmp_dir} end test "invoke with echo CLI returns result and logs to ledger" do # In test config, claude_cli is "echo" — so System.cmd("echo", [...], input: prompt) # echo doesn't actually read stdin, it echoes its args result = Symbiont.Dispatcher.invoke(:haiku, "Hello world") case result do {:ok, entry} -> assert entry.model == "haiku" assert entry.success == true assert is_float(entry.elapsed_seconds) assert entry.estimated_cost_usd >= 0 # Ledger should have recorded it Process.sleep(50) entries = Symbiont.Ledger.recent() assert length(entries) >= 1 {:error, _reason} -> # echo might not be on path in all environments :ok end end test "invoke records prompt preview in ledger entry" do long_prompt = String.duplicate("x", 200) result = Symbiont.Dispatcher.invoke(:sonnet, long_prompt) case result do {:ok, entry} -> # Prompt preview should be truncated to 100 chars assert String.length(entry.prompt_preview) <= 100 {:error, _} -> :ok end end test "cost estimation is reasonable" do # Test that the internal cost math works # Haiku: 0.00000025/input + 0.00000125/output # 1000 input + 500 output = 0.00025 + 0.000625 = 0.000875 result = Symbiont.Dispatcher.invoke(:haiku, "test") case result do {:ok, entry} -> assert entry.estimated_cost_usd >= 0 assert entry.estimated_cost_usd < 1.0 {:error, _} -> :ok end end end