thread-master/apps/backend/internal/module/scout/usecase/activity_terms_test.go

114 lines
3.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package usecase
import (
"context"
"strings"
"testing"
"apps/backend/internal/module/scout/domain"
radarDomain "apps/backend/internal/module/radar/domain"
)
func TestPrepareActivityBriefUsesGeneratedTerms(t *testing.T) {
svc := &Service{}
brief, err := svc.PrepareBrief(context.Background(), 1, "市集", "", "", "activity", true)
if err != nil {
t.Fatalf("PrepareBrief: %v", err)
}
if brief.Mode != domain.ModeActivity {
t.Fatalf("mode=%q want %q", brief.Mode, domain.ModeActivity)
}
if len(brief.ScanTerms) < 2 {
t.Fatalf("ScanTerms=%v want generated variants", brief.ScanTerms)
}
}
func TestPlanActivityTermsGeneratesVariantsNotJustSplit(t *testing.T) {
// 單一字主題:應產出「核 + 口語錨點」,不是只有原字
got := planActivityTerms("市集")
if len(got) < 3 {
t.Fatalf("市集 variants=%v want >=3 generated terms", got)
}
hasPair := false
for _, term := range got {
if !radarDomain.IsThreadsSearchable(term) {
t.Fatalf("term %q not Threads-searchable", term)
}
if strings.Contains(term, " ") {
hasPair = true
}
}
if !hasPair {
t.Fatalf("expected multi-token variants, got %v", got)
}
// 長句:不應只回整句,要抽出核並產變體
got2 := planActivityTerms("想找台北週末市集可以拍什麼")
if len(got2) < 2 {
t.Fatalf("long intent variants=%v want >=2", got2)
}
for _, term := range got2 {
if !radarDomain.IsThreadsSearchable(term) {
t.Fatalf("long-intent term %q not searchable", term)
}
// 不應留下整句長字串
if utf8Count(term) > 12 {
t.Fatalf("term too long: %q", term)
}
}
// 應含地區或市集相關
joined := strings.Join(got2, "|")
if !strings.Contains(joined, "市集") && !strings.Contains(joined, "台北") {
t.Fatalf("expected 市集/台北 in variants, got %v", got2)
}
}
func TestPlanActivityTermsNotJustTokenizeIntent(t *testing.T) {
// 舊行為tokenizeIntent("週末市集") → ["週末市集"] 或空拆
// 新行為:至少有錨點變體
got := planActivityTerms("週末市集")
if len(got) < 2 {
t.Fatalf("got %v, want multiple generated variants", got)
}
// 若只有把四字當一詞,也要再有「週末 市集」類或「市集 推薦」
onlyExact := len(got) == 1 && got[0] == "週末市集"
if onlyExact {
t.Fatal("still only returning exact intent — not generating")
}
}
func TestMergeActivityTermsPrefersAI(t *testing.T) {
ai := []string{"市集 分享", "文青 市集", "太長了吧這整句不行"}
rules := []string{"市集 推薦", "市集"}
got := mergeActivityTerms(ai, rules, 6)
if len(got) == 0 {
t.Fatal("empty merge")
}
if got[0] != "市集 分享" {
t.Fatalf("AI term should come first, got %v", got)
}
// 長詞應被濾掉
for _, t2 := range got {
if strings.Contains(t2, "太長") {
t.Fatalf("unssearchable term leaked: %v", got)
}
}
}
func TestParseActivityAITerms(t *testing.T) {
raw := "這裡是開場\n[\"市集 分享\", \"週末 市集\"]\n結尾"
got := parseActivityAITerms(raw)
if len(got) != 2 {
t.Fatalf("parse strings: %v", got)
}
raw2 := `[{"term":"市集 心得","reason":"x"},{"term":"活動 市集"}]`
got2 := parseActivityAITerms(raw2)
if len(got2) != 2 {
t.Fatalf("parse objects: %v", got2)
}
}
func utf8Count(s string) int {
return len([]rune(strings.ReplaceAll(s, " ", "")))
}