// Tests for instruction extraction helpers in handlers.go. package lsp import "testing" func TestFindFirstInstructionInLine_NoMarker(t *testing.T) { line := "fmt.Println(\"hello\")" s := newTestServer() instr, cleaned, ok := s.findFirstInstructionInLine(line) if ok { t.Fatalf("expected ok=false; got ok=true with instr=%q cleaned=%q", instr, cleaned) } if instr != "" || cleaned != line { t.Fatalf("unexpected outputs: instr=%q cleaned=%q", instr, cleaned) } } func TestFindFirstInstructionInLine_StrictInline_Basic(t *testing.T) { line := "prefix >!rename var> suffix" s := newTestServer() instr, cleaned, ok := s.findFirstInstructionInLine(line) if !ok { t.Fatalf("expected ok=true") } if instr != "rename var" { t.Fatalf("instr got %q want %q", instr, "rename var") } // Removal preserves inner spacing; trailing right spaces trimmed only. if cleaned != "prefix suffix" { t.Fatalf("cleaned got %q want %q", cleaned, "prefix suffix") } } func TestFindFirstInstructionInLine_StrictInline_TrailingSpacesTrimmed(t *testing.T) { line := "code>!fix> \t\t" s := newTestServer() instr, cleaned, ok := s.findFirstInstructionInLine(line) if !ok { t.Fatalf("expected ok=true") } if instr != "fix" { t.Fatalf("instr got %q want %q", instr, "fix") } if cleaned != "code" { t.Fatalf("cleaned got %q want %q", cleaned, "code") } } func TestFindFirstInstructionInLine_Inline_InvalidPatterns(t *testing.T) { cases := []string{ "prefix >! bad> suffix", // space after '!' "prefix >!bad > suffix", // space before closing '>' ⇒ invalid "prefix >! > suffix", // empty inner ⇒ invalid } for _, line := range cases { s := newTestServer() if instr, _, ok := s.findFirstInstructionInLine(line); ok && instr != "" { t.Fatalf("%q: expected no inline instruction; got instr=%q", line, instr) } } } func TestFindFirstInstructionInLine_CBlockComment(t *testing.T) { line := "foo /* update this part */ bar" s := newTestServer() instr, cleaned, ok := s.findFirstInstructionInLine(line) if !ok { t.Fatalf("expected ok=true") } if instr != "update this part" { t.Fatalf("instr got %q want %q", instr, "update this part") } if cleaned != "foo bar" { t.Fatalf("cleaned got %q want %q", cleaned, "foo bar") } } func TestFindFirstInstructionInLine_HTMLComment(t *testing.T) { line := "foo bar" s := newTestServer() instr, cleaned, ok := s.findFirstInstructionInLine(line) if !ok { t.Fatalf("expected ok=true") } if instr != "do x" { t.Fatalf("instr got %q want %q", instr, "do x") } if cleaned != "foo bar" { t.Fatalf("cleaned got %q want %q", cleaned, "foo bar") } } func TestFindFirstInstructionInLine_SlashSlash(t *testing.T) { line := "val // do this change" s := newTestServer() instr, cleaned, ok := s.findFirstInstructionInLine(line) if !ok { t.Fatalf("expected ok=true") } if instr != "do this change" { t.Fatalf("instr got %q want %q", instr, "do this change") } if cleaned != "val" { t.Fatalf("cleaned got %q want %q", cleaned, "val") } } func TestFindFirstInstructionInLine_Hash(t *testing.T) { line := "val # do this" s := newTestServer() instr, cleaned, ok := s.findFirstInstructionInLine(line) if !ok { t.Fatalf("expected ok=true") } if instr != "do this" { t.Fatalf("instr got %q want %q", instr, "do this") } if cleaned != "val" { t.Fatalf("cleaned got %q want %q", cleaned, "val") } } func TestFindFirstInstructionInLine_DoubleDash(t *testing.T) { line := "SQL -- fix query" s := newTestServer() instr, cleaned, ok := s.findFirstInstructionInLine(line) if !ok { t.Fatalf("expected ok=true") } if instr != "fix query" { t.Fatalf("instr got %q want %q", instr, "fix query") } if cleaned != "SQL" { t.Fatalf("cleaned got %q want %q", cleaned, "SQL") } } func TestFindFirstInstructionInLine_EarliestWins_CommentOverInline(t *testing.T) { line := "aa // comment >!not this> trailing" s := newTestServer() instr, cleaned, ok := s.findFirstInstructionInLine(line) if !ok { t.Fatalf("expected ok=true") } if instr != "comment >!not this> trailing" { t.Fatalf("instr got %q want %q", instr, "comment >!not this> trailing") } if cleaned != "aa" { t.Fatalf("cleaned got %q want %q", cleaned, "aa") } } func TestFindFirstInstructionInLine_EarliestWins_InlineOverComment(t *testing.T) { line := "aa >!short> // comment" s := newTestServer() instr, cleaned, ok := s.findFirstInstructionInLine(line) if !ok { t.Fatalf("expected ok=true") } if instr != "short" { t.Fatalf("instr got %q want %q", instr, "short") } // Only the earliest marker is removed; the later comment remains. if cleaned != "aa // comment" { t.Fatalf("cleaned got %q want %q", cleaned, "aa // comment") } } func TestFindStrictInlineTag_Various(t *testing.T) { // basic if text, l, r, ok := findStrictInlineTag("pre>!do it>post", ">!", '>', '>'); !ok || text != "do it" || l != 3 || r != 11 { t.Fatalf("unexpected: ok=%v text=%q l=%d r=%d", ok, text, l, r) } // at start if text, l, r, ok := findStrictInlineTag(">!x>", ">!", '>', '>'); !ok || text != "x" || l != 0 || r != 4 { t.Fatalf("unexpected at start: ok=%v text=%q l=%d r=%d", ok, text, l, r) } // double opening '>>!' should still allow a tag starting after the double marker when configured for '>!' if text, _, _, ok := findStrictInlineTag("prefix >>!bad> suffix", ">!", '>', '>'); !ok || text != "bad" { t.Fatalf("unexpected double-open handling: ok=%v text=%q", ok, text) } // inner spaces directly after first '>' or before last '>' invalidate the tag if _, _, _, ok := findStrictInlineTag("a>! inner >b", ">!", '>', '>'); ok { t.Fatalf("expected invalid strict tag due to spaces at boundaries") } }