1package tools
2
3import (
4 "context"
5 "encoding/json"
6 "path/filepath"
7 "strings"
8 "testing"
9)
10
11func TestGrepASTHintClassifiesPatterns(t *testing.T) {
12 for _, tc := range []struct {
13 pattern string
14 want string // substring of the hint; empty means no hint
15 }{
16 {`fmt\.Errorf\(`, `"fmt.Errorf($$$ARGS)"`},
17 {`\bNewClient\(`, `"NewClient($$$ARGS)"`},
18 {`os\.ReadFile\(`, `"os.ReadFile($$$ARGS)"`},
19 {`os.ReadFile\(`, ""},
20 {`^func `, "for definitions"},
21 {`^\s*def\s`, "for definitions"},
22 {`class\b`, "for definitions"},
23 {`TODO`, ""},
24 {`fmt\.Errorf`, ""},
25 {`error: .*\(`, ""},
26 {`foo\(bar\)`, ""},
27 {`functional`, ""},
28 } {
29 got := grepASTHint(tc.pattern)
30 if tc.want == "" {
31 if got != "" {
32 t.Errorf("grepASTHint(%q) = %q, want none", tc.pattern, got)
33 }
34 continue
35 }
36 if !strings.Contains(got, tc.want) {
37 t.Errorf("grepASTHint(%q) = %q, want substring %q", tc.pattern, got, tc.want)
38 }
39 }
40}
41
42func TestGrepAppendsASTHintOnlyWhenAvailable(t *testing.T) {
43 skipGrepScriptTestsOnWindows(t)
44 root := t.TempDir()
45 rg := writeGrepScript(t, "#!/bin/sh\nprintf 'main.go:3:\\treturn fmt.Errorf(\"x\")\\n'\n")
46 args := json.RawMessage(`{"pattern":"fmt\\.Errorf\\(","path":"."}`)
47 for _, tc := range []struct {
48 name string
49 available func() bool
50 wantHint bool
51 }{
52 {"not wired", nil, false},
53 {"missing backend", func() bool { return false }, false},
54 {"available", func() bool { return true }, true},
55 } {
56 t.Run(tc.name, func(t *testing.T) {
57 tool := &GrepTool{CWD: root, ASTAvailable: tc.available, LookPath: lookupScripts(map[string]string{"rg": rg})}
58 result, err := tool.Execute(context.Background(), args, nil)
59 if err != nil {
60 t.Fatal(err)
61 }
62 text := grepText(result)
63 if got := strings.Contains(text, "Tip:"); got != tc.wantHint {
64 t.Fatalf("hint present = %v, want %v; output %q", got, tc.wantHint, text)
65 }
66 // The hint must never be read back as a discovered file.
67 want := filepath.Join(root, "main.go")
68 if len(result.Context.Discovers) != 1 || result.Context.Discovers[0] != want {
69 t.Fatalf("discovers = %v, want [%s]", result.Context.Discovers, want)
70 }
71 })
72 }
73}