type SyntaxError struct {
Msg string
Line int
+ Byte int64 // byte offset from start of stream
}
func (e *SyntaxError) Error() string {
ns map[string]string
err error
line int
+ offset int64
unmarshalDepth int
}
if b == '\n' {
d.line++
}
+ d.offset++
return b, true
}
+// InputOffset returns the input stream byte offset of the current decoder position.
+// The offset gives the location of the end of the most recently returned token
+// and the beginning of the next token.
+func (d *Decoder) InputOffset() int64 {
+ return d.offset
+}
+
// Return saved offset.
// If we did ungetc (nextByte >= 0), have to back up one.
func (d *Decoder) savedOffset() int {
d.line--
}
d.nextByte = int(b)
+ d.offset--
}
var entity = map[string]int{
func TestRawToken(t *testing.T) {
d := NewDecoder(strings.NewReader(testInput))
d.Entity = testEntity
- testRawToken(t, d, rawTokens)
+ testRawToken(t, d, testInput, rawTokens)
}
const nonStrictInput = `
func TestNonStrictRawToken(t *testing.T) {
d := NewDecoder(strings.NewReader(nonStrictInput))
d.Strict = false
- testRawToken(t, d, nonStrictTokens)
+ testRawToken(t, d, nonStrictInput, nonStrictTokens)
}
type downCaser struct {
}
return &downCaser{t, input.(io.ByteReader)}, nil
}
- testRawToken(t, d, rawTokensAltEncoding)
+ testRawToken(t, d, testInputAltEncoding, rawTokensAltEncoding)
}
func TestRawTokenAltEncodingNoConverter(t *testing.T) {
}
}
-func testRawToken(t *testing.T, d *Decoder, rawTokens []Token) {
+func testRawToken(t *testing.T, d *Decoder, raw string, rawTokens []Token) {
+ lastEnd := int64(0)
for i, want := range rawTokens {
+ start := d.InputOffset()
have, err := d.RawToken()
+ end := d.InputOffset()
if err != nil {
t.Fatalf("token %d: unexpected error: %s", i, err)
}
}
t.Errorf("token %d = %s, want %s", i, shave, swant)
}
+
+ // Check that InputOffset returned actual token.
+ switch {
+ case start < lastEnd:
+ t.Errorf("token %d: position [%d,%d) for %T is before previous token", i, start, end, have)
+ case start >= end:
+ // Special case: EndElement can be synthesized.
+ if start == end && end == lastEnd {
+ break
+ }
+ t.Errorf("token %d: position [%d,%d) for %T is empty", i, start, end, have)
+ case end > int64(len(raw)):
+ t.Errorf("token %d: position [%d,%d) for %T extends beyond input", i, start, end, have)
+ default:
+ text := raw[start:end]
+ if strings.ContainsAny(text, "<>") && (!strings.HasPrefix(text, "<") || !strings.HasSuffix(text, ">")) {
+ t.Errorf("token %d: misaligned raw token %#q for %T", i, text, have)
+ }
+ }
+ lastEnd = end
}
}