package opencode import ( "strings" "testing" ) func TestExtractVerdict(t *testing.T) { cases := []struct { name string in string want string }{ { name: "один text-парт NDJSON", in: `{"type":"text","part":{"text":"hello"}}`, want: "hello", }, { name: "несколько партов — берём последний text", in: "{\"type\":\"step_start\",\"part\":{}}\n{\"type\":\"text\",\"part\":{\"text\":\"первый\"}}\n{\"type\":\"reasoning\",\"part\":{}}\n{\"type\":\"text\",\"part\":{\"text\":\"финал\"}}", want: "финал", }, { name: "нет JSON — возвращаем строку как есть", in: "простой текст без json", want: "простой текст без json", }, { name: "пустая строка", in: "", want: "", }, { name: "text с пустым текстом пропускается", in: "{\"type\":\"text\",\"part\":{\"text\":\"\"}}\n{\"type\":\"text\",\"part\":{\"text\":\"вал\"}}", want: "вал", }, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { if got := ExtractVerdict(c.in); got != c.want { t.Errorf("ExtractVerdict(%q) = %q, want %q", c.in, got, c.want) } }) } } func TestExtractJSON(t *testing.T) { cases := []struct { name string in string want map[string]string ok bool }{ { name: "fenced json", in: "Вот ответ:\n```json\n{\"decision\":\"go\"}\n```", want: map[string]string{"decision": "go"}, ok: true, }, { name: "fenced json без тега", in: "```\n{\"a\":1}\n```", want: map[string]string{"a": "1"}, ok: true, }, { name: "голый json-объект в тексте", in: "Решение: {\"phase\":\"propose\"}", want: map[string]string{"phase": "propose"}, ok: true, }, { name: "нет json", in: "просто текст", ok: false, }, { name: "невалидный json в fence", in: "```json\n{no:json}\n```", ok: false, }, { name: "пустая строка", in: " ", ok: false, }, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { got, ok := ExtractJSON(c.in) if ok != c.ok { t.Fatalf("ExtractJSON(%q) ok = %v, want %v", c.in, ok, c.ok) } if !ok { return } for k, v := range c.want { if !strings.Contains(string(got[k]), v) { t.Errorf("ExtractJSON(%q)[%s] = %s, want to contain %s", c.in, k, got[k], v) } } }) } }