package style8d import ( "strings" "testing" ) func TestParseLLMOutput(t *testing.T) { raw := `{"d1Tone":{"summary":"口語親近","evidence":["真的太好笑"]},"d2Structure":{"summary":"短段落開場","evidence":[]},"d3Interaction":{"summary":"常用提問","evidence":[]},"d4Topics":{"summary":"生活與成長","evidence":[]},"d5Rhythm":{"summary":"晚間發文較多","evidence":[]},"d6Visual":{"summary":"愛用換行與 emoji","evidence":[]},"d7Conversion":{"summary":"自然導留言","evidence":[]},"d8Risk":{"summary":"避免照抄","evidence":[]},"personaDraft":{"identity":"生活觀察者","tone":"輕鬆","audience":"同齡上班族","hooks":"先丟痛點","languageFingerprint":"常用有時候、後來當轉折","rhythm":"短段落加空行","punctuation":"保留逗號與問號","contentPatterns":"心情文先承接情緒","knowledgeTranslation":"先講情境再整理重點","ctaStyle":"自然邀請留言","examples":"有時候真的會累","avoid":"不要硬銷"}}` out, err := ParseLLMOutput(raw) if err != nil { t.Fatalf("unexpected error: %v", err) } if out.D1Tone.Summary != "口語親近" { t.Fatalf("d1=%q", out.D1Tone.Summary) } profile := BuildStoredProfile("demo", []Post{{ Text: "sample", Permalink: "https://www.threads.net/@demo/post/abc", LikeCount: 3, ReplyCount: 1, }}, out) if profile.Analysis["d1Tone"].Summary == "" { t.Fatal("stored profile missing d1") } if len(profile.SamplePosts) != 1 || profile.SamplePosts[0].Permalink == "" { t.Fatalf("samplePosts=%+v", profile.SamplePosts) } if !strings.Contains(profile.PersonaDraft, "【語言指紋】") { t.Fatalf("personaDraft missing language fingerprint: %q", profile.PersonaDraft) } }