package intent import ( "context" "testing" ) // TestBoundaryCJKFalsePositiveSuppressed:词界开启后,「配置」不命中「配置项」(I3)。 func TestBoundaryCJKFalsePositiveSuppressed(t *testing.T) { mk := func(boundary bool) *Snapshot { b := NewRegistryBuilder(Options{}) if err := b.Register(IntentSpec{ ID: "demo.configure", Domain: "demo", Version: 1, Matcher: MatchSpec{IncludesAny: []string{"配置"}, Boundary: boundary}, }); err != nil { t.Fatal(err) } reg, err := b.Build() if err != nil { t.Fatal(err) } return reg.Snapshot() } res, err := NewRecognizer(Options{}, nil, nil).Recognize(context.Background(), "配置项在哪里", mk(true)) if err != nil { t.Fatal(err) } if res.Branch != BranchFallback { t.Fatalf("boundary on: branch = %s, want fallback", res.Branch) } // 词界关闭(旧行为):子串命中依旧,证明差异来自 boundary。 res, err = NewRecognizer(Options{}, nil, nil).Recognize(context.Background(), "配置项在哪里", mk(false)) if err != nil { t.Fatal(err) } if res.Branch != BranchMatched { t.Fatalf("boundary off: branch = %s, want matched", res.Branch) } // 词界开启时,独立成词的「配置」照常命中。 res, err = NewRecognizer(Options{}, nil, nil).Recognize(context.Background(), "我要改配置", mk(true)) if err != nil { t.Fatal(err) } if res.Branch != BranchMatched { t.Fatalf("boundary on, standalone term: branch = %s, want matched", res.Branch) } } // TestBoundaryLatinWordFlank:拉丁词界——write 不命中 rewrites。 func TestBoundaryLatinWordFlank(t *testing.T) { b := NewRegistryBuilder(Options{}) if err := b.Register(IntentSpec{ ID: "demo.write", Domain: "demo", Version: 1, Matcher: MatchSpec{IncludesAny: []string{"write"}, Boundary: true}, }); err != nil { t.Fatal(err) } reg, err := b.Build() if err != nil { t.Fatal(err) } snap := reg.Snapshot() res, err := NewRecognizer(Options{}, nil, nil).Recognize(context.Background(), "rewrites everything", snap) if err != nil { t.Fatal(err) } if res.Branch != BranchFallback { t.Fatalf("branch = %s, want fallback", res.Branch) } res, err = NewRecognizer(Options{}, nil, nil).Recognize(context.Background(), "please write this", snap) if err != nil { t.Fatal(err) } if res.Branch != BranchMatched { t.Fatalf("branch = %s, want matched", res.Branch) } } // TestTieBreakByPriority:同分时高 Priority 胜出(I5);同分同 Priority 仍标歧。 func TestTieBreakByPriority(t *testing.T) { mk := func(p1, p2 int) *Snapshot { b := NewRegistryBuilder(Options{}) if err := b.Register(IntentSpec{ID: "demo.alpha", Domain: "demo", Version: 1, Priority: p1, Matcher: MatchSpec{IncludesAny: []string{"同分词"}}}); err != nil { t.Fatal(err) } if err := b.Register(IntentSpec{ID: "demo.beta", Domain: "demo", Version: 1, Priority: p2, Matcher: MatchSpec{IncludesAny: []string{"同分词"}}}); err != nil { t.Fatal(err) } reg, err := b.Build() if err != nil { t.Fatal(err) } return reg.Snapshot() } res, err := NewRecognizer(Options{}, nil, nil).Recognize(context.Background(), "同分词", mk(10, 0)) if err != nil { t.Fatal(err) } if res.Branch != BranchMatched || res.Top == nil || res.Top.ID != "demo.alpha" { t.Fatalf("tie-break: branch = %s top = %+v", res.Branch, res.Top) } // 同分同 Priority:仍 ambiguous。 res, err = NewRecognizer(Options{}, nil, nil).Recognize(context.Background(), "同分词", mk(5, 5)) if err != nil { t.Fatal(err) } if res.Branch != BranchAmbiguous { t.Fatalf("same priority: branch = %s, want ambiguous", res.Branch) } // Explain 与裁决同规则。 tr := mk(10, 0).Explain("同分词") if tr.Branch != BranchMatched || tr.TopID != "demo.alpha" { t.Fatalf("explain = %+v", tr) } }