package service import ( "testing" "github.com/Wei-Shaw/sub2api/internal/pkg/windsurf" ) func TestShouldRunNLUFallback(t *testing.T) { // Force the fallback-enabled path; tests below cover the disabled path // via withNLUFallbackDisabledFn directly. The production env-Once design // makes t.Setenv ineffective once init has fired in a prior test. prev := nluFallbackDisabledFn nluFallbackDisabledFn = func() bool { return false } t.Cleanup(func() { nluFallbackDisabledFn = prev }) tests := []struct { name string meta *windsurf.ModelMeta text string want bool }{ {"empty text never runs", &windsurf.ModelMeta{Provider: "zhipu"}, "", false}, {"explicit nlu always runs", &windsurf.ModelMeta{Provider: "zhipu"}, "Sure, I helped.", true}, {"explicit override nlu wins over provider", &windsurf.ModelMeta{Provider: "anthropic", EmulationFlavor: "nlu"}, "any text", true}, {"explicit tool_use never runs", &windsurf.ModelMeta{Provider: "anthropic"}, "function: edit_file {}", false}, {"auto with no signal skips", &windsurf.ModelMeta{Provider: "openai"}, "Just a chat reply.", false}, {"auto with signal runs", &windsurf.ModelMeta{Provider: "openai"}, `function: edit_file {"x":1}`, true}, {"nil meta auto, signal", nil, "function: edit_file {}", true}, {"nil meta auto, no signal", nil, "Hello world", false}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { if got := shouldRunNLUFallback(tc.meta, tc.text); got != tc.want { t.Fatalf("shouldRunNLUFallback = %v, want %v", got, tc.want) } }) } } func TestShouldRunNLUFallback_DisabledByOverride(t *testing.T) { prev := nluFallbackDisabledFn nluFallbackDisabledFn = func() bool { return true } t.Cleanup(func() { nluFallbackDisabledFn = prev }) got := shouldRunNLUFallback(&windsurf.ModelMeta{Provider: "zhipu"}, "function: x {}") if got { t.Fatal("expected disabled by override, got enabled") } } func TestAvailableToolNames(t *testing.T) { tests := []struct { name string preamble string want []string }{ {"empty preamble", "", nil}, { name: "function-call format with parens", preamble: `Tools: - edit_file(path, content) - read_file(path) - run_command(cmd)`, want: []string{"edit_file", "read_file", "run_command"}, }, { name: "name: form", preamble: `tools: - name: foo - name: bar`, want: []string{"foo", "bar"}, }, { name: "deduplicates", preamble: `- edit_file(p) - edit_file(p)`, want: []string{"edit_file"}, }, { name: "ignores non-identifier lines", preamble: `Use the following tools:`, want: nil, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { got := availableToolNames(tc.preamble) if len(got) != len(tc.want) { t.Fatalf("expected %v, got %v", tc.want, got) } for i := range got { if got[i] != tc.want[i] { t.Fatalf("expected %v, got %v", tc.want, got) } } }) } } func TestIsIdentifier(t *testing.T) { cases := []struct { s string want bool }{ {"", false}, {"foo", true}, {"foo_bar", true}, {"FooBar", true}, {"foo123", true}, {"123foo", false}, {"foo bar", false}, {"foo-bar", false}, {"foo.bar", false}, } for _, tc := range cases { t.Run(tc.s, func(t *testing.T) { if got := isIdentifier(tc.s); got != tc.want { t.Fatalf("isIdentifier(%q) = %v, want %v", tc.s, got, tc.want) } }) } }