Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

312 lines
10 KiB
Go

package mcp
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNormalizeCRLF(t *testing.T) {
tests := []struct {
name string
in string
want string
removals []int
}{
{"no terminators", "abc", "abc", nil},
{"pure LF untouched", "a\nb\n", "a\nb\n", nil},
{"single CRLF", "a\r\nb", "a\nb", []int{1}},
{"trailing CRLF", "a\r\n", "a\n", []int{1}},
{"consecutive CRLF", "\r\n\r\n", "\n\n", []int{0, 1}},
{"multiple lines", "a\r\nb\r\nc", "a\nb\nc", []int{1, 3}},
{"lone CR untouched", "a\rb", "a\rb", nil},
{"lone CR at EOF untouched", "ab\r", "ab\r", nil},
{"CR before CRLF keeps lone CR", "a\r\r\nb", "a\r\nb", []int{2}},
{"mixed LF and CRLF", "a\nb\r\nc", "a\nb\nc", []int{3}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, removals := normalizeCRLF(tt.in)
assert.Equal(t, tt.want, got)
assert.Equal(t, tt.removals, removals)
})
}
}
func TestOrigOffset(t *testing.T) {
// orig "a\r\nb" -> norm "a\nb", removals [1].
removals := []int{1}
assert.Equal(t, 0, origOffset(removals, 0), "byte before the removal is unshifted")
assert.Equal(t, 1, origOffset(removals, 1), "offset on the recorded LF resolves to its removed CR")
assert.Equal(t, 3, origOffset(removals, 2), "byte after the removal shifts by one")
assert.Equal(t, 4, origOffset(removals, 3), "end-of-string maps to original length")
// orig "\r\n\r\n" -> norm "\n\n", removals [0, 1].
removals = []int{0, 1}
assert.Equal(t, 0, origOffset(removals, 0))
assert.Equal(t, 2, origOffset(removals, 1))
assert.Equal(t, 4, origOffset(removals, 2))
assert.Equal(t, 5, origOffset(nil, 5), "no removals is identity")
}
func TestFindEOLMatches_ExactLF(t *testing.T) {
m := findEOLMatches("foo bar foo", "foo")
assert.Equal(t, 2, m.count)
assert.False(t, m.normalized)
assert.Equal(t, []eolSpan{{0, 3}, {8, 11}}, m.spans)
}
func TestFindEOLMatches_NonOverlapping(t *testing.T) {
m := findEOLMatches("aaa", "aa")
assert.Equal(t, 1, m.count, "strings.Count semantics: non-overlapping")
assert.Equal(t, []eolSpan{{0, 2}}, m.spans)
}
func TestFindEOLMatches_EmptyNeedle(t *testing.T) {
m := findEOLMatches("abc", "")
assert.Equal(t, 4, m.count, "mirrors strings.Count for the empty needle")
assert.Empty(t, m.spans)
assert.False(t, m.normalized)
}
func TestFindEOLMatches_NoMatch(t *testing.T) {
m := findEOLMatches("hello\r\nworld", "absent")
assert.Equal(t, 0, m.count)
assert.Empty(t, m.spans)
assert.False(t, m.normalized)
}
func TestFindEOLMatches_CRLFHayLFNeedle(t *testing.T) {
hay := "alpha\r\nbeta\r\ngamma\r\n"
m := findEOLMatches(hay, "beta\ngamma")
require.Equal(t, 1, m.count)
assert.True(t, m.normalized)
require.Len(t, m.spans, 1)
assert.Equal(t, "beta\r\ngamma", hay[m.spans[0].start:m.spans[0].end],
"span must cover the CRLF bytes of the matched region")
}
func TestFindEOLMatches_CRLFHayLFNeedle_Multiple(t *testing.T) {
hay := "x\r\ny\r\nQ\r\nx\r\ny\r\n"
m := findEOLMatches(hay, "x\ny\n")
require.Equal(t, 2, m.count)
assert.True(t, m.normalized)
for _, sp := range m.spans {
assert.Equal(t, "x\r\ny\r\n", hay[sp.start:sp.end])
}
}
func TestFindEOLMatches_LFHayCRLFNeedle(t *testing.T) {
hay := "alpha\nbeta\ngamma\n"
m := findEOLMatches(hay, "beta\r\ngamma")
require.Equal(t, 1, m.count)
assert.True(t, m.normalized)
assert.Equal(t, "beta\ngamma", hay[m.spans[0].start:m.spans[0].end])
}
func TestFindEOLMatches_NeedleStartingWithNewlineExactWins(t *testing.T) {
// "\nb" is a byte-exact substring of "a\r\nb" — the exact pass wins
// and the span covers only the bytes the caller named.
hay := "a\r\nb"
m := findEOLMatches(hay, "\nb")
require.Equal(t, 1, m.count)
assert.False(t, m.normalized)
assert.Equal(t, "\nb", hay[m.spans[0].start:m.spans[0].end])
}
func TestFindEOLMatches_NeedleStartingWithNewlineSwallowsCR(t *testing.T) {
// Multi-terminator needle that cannot exact-match: the normalized
// match starting at a LF must swallow its CR so replacing the span
// never strands a bare CR.
hay := "a\r\nb\r\nc"
m := findEOLMatches(hay, "\nb\nc")
require.Equal(t, 1, m.count)
require.True(t, m.normalized)
assert.Equal(t, "\r\nb\r\nc", hay[m.spans[0].start:m.spans[0].end],
"a normalized match starting at the LF must swallow the CR")
}
func TestFindEOLMatches_NeedleEndingBeforeNewlineLeavesCR(t *testing.T) {
hay := "ab\r\nc"
m := findEOLMatches(hay, "ab")
require.Equal(t, 1, m.count)
assert.False(t, m.normalized, "no terminator in the needle: exact match")
assert.Equal(t, "ab", hay[m.spans[0].start:m.spans[0].end])
}
func TestFindEOLMatches_LoneCRIsNotATerminator(t *testing.T) {
m := findEOLMatches("foo\rbar", "foo\nbar")
assert.Equal(t, 0, m.count, "a lone CR must not be treated as CRLF")
}
func TestFindEOLMatches_ExactPreferredOverNormalized(t *testing.T) {
// Mixed file: the LF section matches byte-exactly; the CRLF section
// would only match normalized. Exact must win and report one match.
hay := "a\nb\nQ\r\na\r\nb\r\n"
m := findEOLMatches(hay, "a\nb\n")
assert.Equal(t, 1, m.count)
assert.False(t, m.normalized)
assert.Equal(t, 0, m.spans[0].start)
}
func TestFindEOLMatches_WholeFile(t *testing.T) {
hay := "one\r\ntwo\r\n"
m := findEOLMatches(hay, "one\ntwo\n")
require.Equal(t, 1, m.count)
assert.Equal(t, eolSpan{0, len(hay)}, m.spans[0])
}
func TestFindEOLMatches_ConsecutiveBlankCRLFLines(t *testing.T) {
hay := "a\r\n\r\nb\r\n"
m := findEOLMatches(hay, "a\n\nb\n")
require.Equal(t, 1, m.count)
assert.Equal(t, eolSpan{0, len(hay)}, m.spans[0])
}
func TestSpliceSpansEOL_SingleSpan(t *testing.T) {
hay := "alpha\r\nbeta\r\ngamma\r\n"
m := findEOLMatches(hay, "beta\n")
require.Equal(t, 1, m.count)
got := spliceSpansEOL(hay, m.spans, "delta\nepsilon\n", 1)
assert.Equal(t, "alpha\r\ndelta\r\nepsilon\r\ngamma\r\n", got,
"replacement must be written with the span's CRLF terminators")
}
func TestSpliceSpansEOL_AllSpans(t *testing.T) {
hay := "x\r\nQ\r\nx\r\n"
m := findEOLMatches(hay, "x\n")
require.Equal(t, 2, m.count)
got := spliceSpansEOL(hay, m.spans, "y\n", -1)
assert.Equal(t, "y\r\nQ\r\ny\r\n", got)
}
func TestSpliceSpansEOL_LimitOne(t *testing.T) {
hay := "x\r\nQ\r\nx\r\n"
m := findEOLMatches(hay, "x\n")
require.Equal(t, 2, m.count)
got := spliceSpansEOL(hay, m.spans, "y\n", 1)
assert.Equal(t, "y\r\nQ\r\nx\r\n", got, "only the first span is replaced")
}
func TestSpliceSpansEOL_MixedFilePerSpanAdaptation(t *testing.T) {
// One LF region and one CRLF region match the same normalized needle.
// The needle's endings are mixed so NEITHER region matches exactly.
// Each replacement must adopt its own region's terminator style.
hay := "x\ny\nQ\r\nx\r\ny\r\n"
m := findEOLMatches(hay, "x\r\ny\n")
require.Equal(t, 2, m.count)
require.True(t, m.normalized)
got := spliceSpansEOL(hay, m.spans, "z\nw\n", -1)
assert.Equal(t, "z\nw\nQ\r\nz\r\nw\r\n", got)
}
func TestSpliceSpansEOL_LFFileStaysLF(t *testing.T) {
hay := "alpha\nbeta\n"
m := findEOLMatches(hay, "beta\r\n")
require.Equal(t, 1, m.count)
got := spliceSpansEOL(hay, m.spans, "gamma\r\ndelta\r\n", 1)
assert.Equal(t, "alpha\ngamma\ndelta\n", got,
"CRLF replacement into an LF region is rewritten to LF")
}
func TestDominantEOL(t *testing.T) {
tests := []struct {
name string
in string
want string
}{
{"empty", "", "\n"},
{"no newlines", "abc", "\n"},
{"pure LF", "a\nb\n", "\n"},
{"pure CRLF", "a\r\nb\r\n", "\r\n"},
{"CRLF majority", "a\r\nb\r\nc\n", "\r\n"},
{"LF majority", "a\nb\nc\r\n", "\n"},
{"tie goes LF", "a\nb\r\n", "\n"},
{"lone CR ignored", "a\rb\n", "\n"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, dominantEOL(tt.in))
})
}
}
func TestAdaptToDominantEOL(t *testing.T) {
tests := []struct {
name string
replacement string
context string
want string
}{
{"LF into CRLF context", "a\nb\n", "x\r\ny\r\n", "a\r\nb\r\n"},
{"CRLF into LF context", "a\r\nb\r\n", "x\ny\n", "a\nb\n"},
{"mixed replacement unified to CRLF", "a\nb\r\nc", "x\r\n", "a\r\nb\r\nc"},
{"mixed replacement unified to LF", "a\nb\r\nc", "x\n", "a\nb\nc"},
{"no terminators untouched", "abc", "x\r\n", "abc"},
{"lone CR passes through", "a\rb", "x\r\n", "a\rb"},
{"already matching CRLF", "a\r\n", "x\r\n", "a\r\n"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, adaptToDominantEOL(tt.replacement, tt.context))
})
}
}
func TestMatchSpansHint(t *testing.T) {
file := "a\nb\nc\nb\nb\n"
m := findEOLMatches(file, "b\n")
require.Equal(t, 3, m.count)
hint := matchSpansHint(file, m.spans)
assert.Equal(t, " (first match lines 2, 4, 5)", hint)
assert.Empty(t, matchSpansHint(file, nil))
}
func TestMatchSpansHint_CapsAtThreeWithSuffix(t *testing.T) {
file := strings.Repeat("b\n", 5)
m := findEOLMatches(file, "b\n")
require.Equal(t, 5, m.count)
hint := matchSpansHint(file, m.spans)
assert.Equal(t, " (first match lines 1, 2, 3, ...)", hint)
}
func TestMatchSpansHint_CRLFLineNumbers(t *testing.T) {
file := "one\r\ntwo\r\nthree\r\ntwo\r\n"
m := findEOLMatches(file, "two\n")
require.Equal(t, 2, m.count)
require.True(t, m.normalized)
hint := matchSpansHint(file, m.spans)
assert.Equal(t, " (first match lines 2, 4)", hint)
}
func TestMatchLocationsHint_ExactBehaviorPreserved(t *testing.T) {
file := "\nTODO\nTODO\nTODO\n"
hint := matchLocationsHint(file, "TODO")
assert.Equal(t, " (first match lines 2, 3, 4)", hint)
assert.Empty(t, matchLocationsHint(file, ""))
assert.Empty(t, matchLocationsHint(file, "absent"))
}
func TestMatchLocationsHint_EOLTolerant(t *testing.T) {
file := "one\r\nTODO x\r\nTODO x\r\n"
hint := matchLocationsHint(file, "TODO x\n")
assert.Equal(t, " (first match lines 2, 3)", hint,
"hint must report normalized matches too")
}
func TestEOLRoundTrip_NoMixedEndingsAfterSplice(t *testing.T) {
hay := "func a() {\r\n\tx := 1\r\n\t_ = x\r\n}\r\n"
m := findEOLMatches(hay, "\tx := 1\n\t_ = x")
require.Equal(t, 1, m.count)
require.True(t, m.normalized)
got := spliceSpansEOL(hay, m.spans, "\ty := 2\n\t_ = y", 1)
assert.Equal(t, "func a() {\r\n\ty := 2\r\n\t_ = y\r\n}\r\n", got)
assert.NotContains(t, strings.ReplaceAll(got, "\r\n", ""), "\n",
"every LF in the result must be part of a CRLF pair")
}