summaryrefslogtreecommitdiff
path: root/internal/lsp/helpers_more_test.go
blob: 64631f76c3ee36447bc80a88776ec0a31ef00e39 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package lsp

import ("testing")

func TestComputeWordStart(t *testing.T) {
    s := "fooBar 123"
    if i := computeWordStart(s, 5); i != 0 { t.Fatalf("start=%d", i) }
    if i := computeWordStart(s, len(s)); i != 7 { t.Fatalf("end start=%d", i) }
}

func TestLeadingAndApplyIndent(t *testing.T) {
    if got := leadingIndent("\t  abc"); got == "" { t.Fatalf("expected indent") }
    out := applyIndent("  ", "x\n y\n\n z")
    if out == "" || out[:2] != "  " { t.Fatalf("applyIndent failed: %q", out) }
}

func TestFindStrictSemicolonTag(t *testing.T) {
    if _, _, _, ok := findStrictSemicolonTag(";do this; next"); !ok { t.Fatalf("expected strict tag") }
    if _, _, _, ok := findStrictSemicolonTag("; spaced ;"); ok { t.Fatalf("should ignore spaced tag") }
}

// hasDoubleSemicolonTrigger tested elsewhere

func TestStripDuplicatePrefixes(t *testing.T) {
    if got := stripDuplicateAssignmentPrefix("name := ", "name := 123"); got == "name := 123" { t.Fatalf("expected trim") }
    if got := stripDuplicateGeneralPrefix("fmt.", "fmt.Println"); got == "fmt.Println" { t.Fatalf("expected trim general") }
}

func TestExtractRangeText(t *testing.T) {
    d := &document{text: "a\nbc\nxyz", lines: []string{"a","bc","xyz"}}
    // single line
    got := extractRangeText(d, Range{Start: Position{Line:1, Character:0}, End: Position{Line:1, Character:2}})
    if got != "bc" { t.Fatalf("got %q", got) }
    // multi-line
    got = extractRangeText(d, Range{Start: Position{Line:0, Character:0}, End: Position{Line:2, Character:2}})
    if got != "a\nbc\nxy" { t.Fatalf("got %q", got) }
}

func TestRangesOverlapAndOrder(t *testing.T) {
    a := Range{Start: Position{Line:1, Character:2}, End: Position{Line:1, Character:5}}
    b := Range{Start: Position{Line:1, Character:4}, End: Position{Line:1, Character:8}}
    if !rangesOverlap(a, b) { t.Fatalf("expected overlap") }
    c := Range{Start: Position{Line:2, Character:0}, End: Position{Line:2, Character:1}}
    if rangesOverlap(a, c) { t.Fatalf("no overlap expected") }
    if !lessPos(Position{Line:0, Character:1}, Position{Line:1, Character:0}) { t.Fatalf("lessPos failed") }
    if !greaterPos(Position{Line:2, Character:0}, Position{Line:1, Character:9}) { t.Fatalf("greaterPos failed") }
}

func TestPromptRemovalEditsForLine(t *testing.T) {
    edits := promptRemovalEditsForLine(";;do thing;", 3)
    if len(edits) != 1 || edits[0].Range.Start.Line != 3 {
        t.Fatalf("expected full-line removal for double-semicolon")
    }
    edits2 := promptRemovalEditsForLine(";act; and ;b;", 1)
    if len(edits2) == 0 { t.Fatalf("expected edits to remove strict markers") }
}

func TestCollectPromptRemovalEdits_MultiLine(t *testing.T) {
    s := newTestServer()
    uri := "file:///t.go"
    s.setDocument(uri, "a\n;do; x\n;;wipe;\nend")
    edits := s.collectPromptRemovalEdits(uri)
    if len(edits) < 2 { t.Fatalf("expected >=2 edits, got %d", len(edits)) }
}

func TestInParamListAndBuildPrompts(t *testing.T) {
    cur := "func add(a int, b string) int"
    if !inParamList(cur, 12) { t.Fatalf("expected in param list") }
    p := CompletionParams{TextDocument: TextDocumentIdentifier{URI: "file:///x.go"}, Position: Position{Line: 0, Character: 5}}
    sys, user := buildPrompts(false, p, "above", "current", "below", "func add")
    if sys == "" || user == "" { t.Fatalf("prompts empty") }
}

func TestLabelForCompletion(t *testing.T) {
    if got := labelForCompletion("line one\nline two", "lin"); got != "line one" { t.Fatalf("expected label, got %q", got) }
    if got := labelForCompletion("result", "zzz"); got != "zzz" { t.Fatalf("expected filter preferred when not prefix, got %q", got) }
    if got := labelForCompletion("result", "re"); got != "result" { t.Fatalf("expected label when filter prefixes label, got %q", got) }
}

func TestComputeTextEditAndFilter(t *testing.T) {
    // non-params edit
    p := CompletionParams{Position: Position{Line: 1, Character: 4}}
    te, filter := computeTextEditAndFilter("X", false, "ab cd", p)
    if te == nil || filter == "" { t.Fatalf("expected edit and filter") }
    // inside params
    line := "func add(a int, b int)"
    p2 := CompletionParams{Position: Position{Line: 0, Character: 12}}
    te2, _ := computeTextEditAndFilter("string", true, line, p2)
    if te2 == nil || te2.Range.Start.Character == 0 { t.Fatalf("expected param-range edit") }
}

func TestIsBareDoubleSemicolon(t *testing.T) {
    if !isBareDoubleSemicolon(";;   ") { t.Fatalf("expected true") }
    if isBareDoubleSemicolon(";;x;") { t.Fatalf("expected false for content form") }
}

func TestIsDefiningNewFunction(t *testing.T) {
    s := newTestServer()
    uri := "file:///z.go"
    s.setDocument(uri, "package p\n\nfunc add(a int) int\n{")
    if !s.isDefiningNewFunction(uri, Position{Line:2, Character:10}) {
        t.Fatalf("expected true before opening brace")
    }
    if s.isDefiningNewFunction(uri, Position{Line:3, Character:1}) {
        t.Fatalf("expected false inside body")
    }
}