Fix incorrect error positions for non-suffix subslices in unstable.Parser.Range (#1047)
The unsafe removal (#1021) replaced danger.SubsliceOffset (pointer arithmetic) with len(p.data)-len(b), which only works for suffix slices. Parser.Range is called with arbitrary interior subslices (e.g. ParserError.Highlight), so the offset was wrong whenever the error occurred after previously scanned content like comments. Fix by using reflect.ValueOf().Pointer() to recover the actual data pointer, matching the approach already used in errors.go. https://claude.ai/code/session_01EXYfFXc3DDGpQ27sWdXTKq
This commit is contained in:
@@ -695,3 +695,81 @@ func ExampleParser() {
|
||||
// Expression: KeyValue
|
||||
// value -> (Integer) 42
|
||||
}
|
||||
|
||||
func TestParserError_RangeOffset(t *testing.T) {
|
||||
// Regression test for https://github.com/pelletier/go-toml/issues/1047
|
||||
// Parser.Range must return the correct byte offset for error highlights,
|
||||
// not just for suffix slices.
|
||||
examples := []struct {
|
||||
desc string
|
||||
input string
|
||||
wantOffset int
|
||||
wantLine int
|
||||
wantColumn int
|
||||
wantMessage string
|
||||
}{
|
||||
{
|
||||
desc: "invalid key start after comment",
|
||||
input: "# comment\n= \"value\"",
|
||||
wantOffset: 10,
|
||||
wantLine: 2,
|
||||
wantColumn: 1,
|
||||
wantMessage: "invalid character at start of key: =",
|
||||
},
|
||||
{
|
||||
desc: "invalid key start after two comments",
|
||||
input: "# one\n# two\n= \"value\"",
|
||||
wantOffset: 12,
|
||||
wantLine: 3,
|
||||
wantColumn: 1,
|
||||
wantMessage: "invalid character at start of key: =",
|
||||
},
|
||||
{
|
||||
desc: "invalid key start after blank line",
|
||||
input: "a = 1\n\n= 2",
|
||||
wantOffset: 7,
|
||||
wantLine: 3,
|
||||
wantColumn: 1,
|
||||
wantMessage: "invalid character at start of key: =",
|
||||
},
|
||||
{
|
||||
desc: "invalid key start after valid key-value",
|
||||
input: "a = 1\n= 2",
|
||||
wantOffset: 6,
|
||||
wantLine: 2,
|
||||
wantColumn: 1,
|
||||
wantMessage: "invalid character at start of key: =",
|
||||
},
|
||||
}
|
||||
|
||||
for _, e := range examples {
|
||||
t.Run(e.desc, func(t *testing.T) {
|
||||
p := Parser{}
|
||||
p.Reset([]byte(e.input))
|
||||
for p.NextExpression() {
|
||||
}
|
||||
err := p.Error()
|
||||
if err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
perr, ok := err.(*ParserError)
|
||||
if !ok {
|
||||
t.Fatalf("expected *ParserError, got %T", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, e.wantMessage, perr.Message)
|
||||
|
||||
r := p.Range(perr.Highlight)
|
||||
if int(r.Offset) != e.wantOffset {
|
||||
t.Errorf("Range offset: got %d, want %d", r.Offset, e.wantOffset)
|
||||
}
|
||||
|
||||
shape := p.Shape(r)
|
||||
if shape.Start.Line != e.wantLine || shape.Start.Column != e.wantColumn {
|
||||
t.Errorf("position: got %d:%d, want %d:%d",
|
||||
shape.Start.Line, shape.Start.Column,
|
||||
e.wantLine, e.wantColumn)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user