1
2
3
4
5
6
7 package jsontext
8
9 import (
10 "bytes"
11 "errors"
12 "fmt"
13 "io"
14 "net"
15 "path"
16 "reflect"
17 "slices"
18 "strings"
19 "testing"
20 "testing/iotest"
21
22 "encoding/json/internal/jsonflags"
23 "encoding/json/internal/jsontest"
24 "encoding/json/internal/jsonwire"
25 )
26
27
28 func equalTokens(xs, ys []Token) bool {
29 if len(xs) != len(ys) {
30 return false
31 }
32 for i := range xs {
33 if !(reflect.DeepEqual(xs[i], ys[i]) || xs[i].String() == ys[i].String()) {
34 return false
35 }
36 }
37 return true
38 }
39
40
41 func TestDecoder(t *testing.T) {
42 for _, td := range coderTestdata {
43 for _, typeName := range []string{"Token", "Value", "TokenDelims"} {
44 t.Run(path.Join(td.name.Name, typeName), func(t *testing.T) {
45 testDecoder(t, td.name.Where, typeName, td)
46 })
47 }
48 }
49 }
50 func testDecoder(t *testing.T, where jsontest.CasePos, typeName string, td coderTestdataEntry) {
51 dec := NewDecoder(bytes.NewBufferString(td.in))
52 switch typeName {
53 case "Token":
54 var tokens []Token
55 var pointers []Pointer
56 for {
57 tok, err := dec.ReadToken()
58 if err != nil {
59 if err == io.EOF {
60 break
61 }
62 t.Fatalf("%s: Decoder.ReadToken error: %v", where, err)
63 }
64 tokens = append(tokens, tok.Clone())
65 if td.pointers != nil {
66 pointers = append(pointers, dec.StackPointer())
67 }
68 }
69 if !equalTokens(tokens, td.tokens) {
70 t.Fatalf("%s: tokens mismatch:\ngot %v\nwant %v", where, tokens, td.tokens)
71 }
72 if !slices.Equal(pointers, td.pointers) {
73 t.Fatalf("%s: pointers mismatch:\ngot %q\nwant %q", where, pointers, td.pointers)
74 }
75 case "Value":
76 val, err := dec.ReadValue()
77 if err != nil {
78 t.Fatalf("%s: Decoder.ReadValue error: %v", where, err)
79 }
80 got := string(val)
81 want := strings.TrimSpace(td.in)
82 if got != want {
83 t.Fatalf("%s: Decoder.ReadValue = %s, want %s", where, got, want)
84 }
85 case "TokenDelims":
86
87 var tokens []Token
88 loop:
89 for {
90 switch dec.PeekKind() {
91 case '{', '}', '[', ']':
92 tok, err := dec.ReadToken()
93 if err != nil {
94 if err == io.EOF {
95 break loop
96 }
97 t.Fatalf("%s: Decoder.ReadToken error: %v", where, err)
98 }
99 tokens = append(tokens, tok.Clone())
100 default:
101 val, err := dec.ReadValue()
102 if err != nil {
103 if err == io.EOF {
104 break loop
105 }
106 t.Fatalf("%s: Decoder.ReadValue error: %v", where, err)
107 }
108 tokens = append(tokens, rawToken(string(val)))
109 }
110 }
111 if !equalTokens(tokens, td.tokens) {
112 t.Fatalf("%s: tokens mismatch:\ngot %v\nwant %v", where, tokens, td.tokens)
113 }
114 }
115 }
116
117
118 func TestFaultyDecoder(t *testing.T) {
119 for _, td := range coderTestdata {
120 for _, typeName := range []string{"Token", "Value"} {
121 t.Run(path.Join(td.name.Name, typeName), func(t *testing.T) {
122 testFaultyDecoder(t, td.name.Where, typeName, td)
123 })
124 }
125 }
126 }
127 func testFaultyDecoder(t *testing.T, where jsontest.CasePos, typeName string, td coderTestdataEntry) {
128 b := &FaultyBuffer{
129 B: []byte(td.in),
130 MaxBytes: 1,
131 MayError: io.ErrNoProgress,
132 }
133
134
135
136
137
138 dec := NewDecoder(b)
139 switch typeName {
140 case "Token":
141 var tokens []Token
142 for {
143 tok, err := dec.ReadToken()
144 if err != nil {
145 if err == io.EOF {
146 break
147 }
148 if !errors.Is(err, io.ErrNoProgress) {
149 t.Fatalf("%s: %d: Decoder.ReadToken error: %v", where, len(tokens), err)
150 }
151 continue
152 }
153 tokens = append(tokens, tok.Clone())
154 }
155 if !equalTokens(tokens, td.tokens) {
156 t.Fatalf("%s: tokens mismatch:\ngot %s\nwant %s", where, tokens, td.tokens)
157 }
158 case "Value":
159 for {
160 val, err := dec.ReadValue()
161 if err != nil {
162 if err == io.EOF {
163 break
164 }
165 if !errors.Is(err, io.ErrNoProgress) {
166 t.Fatalf("%s: Decoder.ReadValue error: %v", where, err)
167 }
168 continue
169 }
170 got := string(val)
171 want := strings.TrimSpace(td.in)
172 if got != want {
173 t.Fatalf("%s: Decoder.ReadValue = %s, want %s", where, got, want)
174 }
175 }
176 }
177 }
178
179 type decoderMethodCall struct {
180 wantKind Kind
181 wantOut tokOrVal
182 wantErr error
183 wantPointer Pointer
184 }
185
186 var decoderErrorTestdata = []struct {
187 name jsontest.CaseName
188 opts []Options
189 in string
190 calls []decoderMethodCall
191 wantOffset int
192 }{{
193 name: jsontest.Name("InvalidStart"),
194 in: ` #`,
195 calls: []decoderMethodCall{
196 {'#', zeroToken, newInvalidCharacterError("#", "at start of value").withPos(" ", ""), ""},
197 {'#', zeroValue, newInvalidCharacterError("#", "at start of value").withPos(" ", ""), ""},
198 },
199 }, {
200 name: jsontest.Name("StreamN0"),
201 in: ` `,
202 calls: []decoderMethodCall{
203 {0, zeroToken, io.EOF, ""},
204 {0, zeroValue, io.EOF, ""},
205 },
206 }, {
207 name: jsontest.Name("StreamN1"),
208 in: ` null `,
209 calls: []decoderMethodCall{
210 {'n', Null, nil, ""},
211 {0, zeroToken, io.EOF, ""},
212 {0, zeroValue, io.EOF, ""},
213 },
214 wantOffset: len(` null`),
215 }, {
216 name: jsontest.Name("StreamN2"),
217 in: ` nullnull `,
218 calls: []decoderMethodCall{
219 {'n', Null, nil, ""},
220 {'n', Null, nil, ""},
221 {0, zeroToken, io.EOF, ""},
222 {0, zeroValue, io.EOF, ""},
223 },
224 wantOffset: len(` nullnull`),
225 }, {
226 name: jsontest.Name("StreamN2/ExtraComma"),
227 in: ` null , null `,
228 calls: []decoderMethodCall{
229 {'n', Null, nil, ""},
230 {0, zeroToken, newInvalidCharacterError(",", `at start of value`).withPos(` null `, ""), ""},
231 {0, zeroValue, newInvalidCharacterError(",", `at start of value`).withPos(` null `, ""), ""},
232 },
233 wantOffset: len(` null`),
234 }, {
235 name: jsontest.Name("TruncatedNull"),
236 in: `nul`,
237 calls: []decoderMethodCall{
238 {'n', zeroToken, E(io.ErrUnexpectedEOF).withPos(`nul`, ""), ""},
239 {'n', zeroValue, E(io.ErrUnexpectedEOF).withPos(`nul`, ""), ""},
240 },
241 }, {
242 name: jsontest.Name("InvalidNull"),
243 in: `nulL`,
244 calls: []decoderMethodCall{
245 {'n', zeroToken, newInvalidCharacterError("L", `in literal null (expecting 'l')`).withPos(`nul`, ""), ""},
246 {'n', zeroValue, newInvalidCharacterError("L", `in literal null (expecting 'l')`).withPos(`nul`, ""), ""},
247 },
248 }, {
249 name: jsontest.Name("TruncatedFalse"),
250 in: `fals`,
251 calls: []decoderMethodCall{
252 {'f', zeroToken, E(io.ErrUnexpectedEOF).withPos(`fals`, ""), ""},
253 {'f', zeroValue, E(io.ErrUnexpectedEOF).withPos(`fals`, ""), ""},
254 },
255 }, {
256 name: jsontest.Name("InvalidFalse"),
257 in: `falsE`,
258 calls: []decoderMethodCall{
259 {'f', zeroToken, newInvalidCharacterError("E", `in literal false (expecting 'e')`).withPos(`fals`, ""), ""},
260 {'f', zeroValue, newInvalidCharacterError("E", `in literal false (expecting 'e')`).withPos(`fals`, ""), ""},
261 },
262 }, {
263 name: jsontest.Name("TruncatedTrue"),
264 in: `tru`,
265 calls: []decoderMethodCall{
266 {'t', zeroToken, E(io.ErrUnexpectedEOF).withPos(`tru`, ""), ""},
267 {'t', zeroValue, E(io.ErrUnexpectedEOF).withPos(`tru`, ""), ""},
268 },
269 }, {
270 name: jsontest.Name("InvalidTrue"),
271 in: `truE`,
272 calls: []decoderMethodCall{
273 {'t', zeroToken, newInvalidCharacterError("E", `in literal true (expecting 'e')`).withPos(`tru`, ""), ""},
274 {'t', zeroValue, newInvalidCharacterError("E", `in literal true (expecting 'e')`).withPos(`tru`, ""), ""},
275 },
276 }, {
277 name: jsontest.Name("TruncatedString"),
278 in: `"start`,
279 calls: []decoderMethodCall{
280 {'"', zeroToken, E(io.ErrUnexpectedEOF).withPos(`"start`, ""), ""},
281 {'"', zeroValue, E(io.ErrUnexpectedEOF).withPos(`"start`, ""), ""},
282 },
283 }, {
284 name: jsontest.Name("InvalidString"),
285 in: `"ok` + "\x00",
286 calls: []decoderMethodCall{
287 {'"', zeroToken, newInvalidCharacterError("\x00", `in string (expecting non-control character)`).withPos(`"ok`, ""), ""},
288 {'"', zeroValue, newInvalidCharacterError("\x00", `in string (expecting non-control character)`).withPos(`"ok`, ""), ""},
289 },
290 }, {
291 name: jsontest.Name("ValidString/AllowInvalidUTF8/Token"),
292 opts: []Options{AllowInvalidUTF8(true)},
293 in: "\"living\xde\xad\xbe\xef\"",
294 calls: []decoderMethodCall{
295 {'"', rawToken("\"living\xde\xad\xbe\xef\""), nil, ""},
296 },
297 wantOffset: len("\"living\xde\xad\xbe\xef\""),
298 }, {
299 name: jsontest.Name("ValidString/AllowInvalidUTF8/Value"),
300 opts: []Options{AllowInvalidUTF8(true)},
301 in: "\"living\xde\xad\xbe\xef\"",
302 calls: []decoderMethodCall{
303 {'"', Value("\"living\xde\xad\xbe\xef\""), nil, ""},
304 },
305 wantOffset: len("\"living\xde\xad\xbe\xef\""),
306 }, {
307 name: jsontest.Name("InvalidString/RejectInvalidUTF8"),
308 opts: []Options{AllowInvalidUTF8(false)},
309 in: "\"living\xde\xad\xbe\xef\"",
310 calls: []decoderMethodCall{
311 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos("\"living\xde\xad", ""), ""},
312 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos("\"living\xde\xad", ""), ""},
313 },
314 }, {
315 name: jsontest.Name("TruncatedNumber"),
316 in: `0.`,
317 calls: []decoderMethodCall{
318 {'0', zeroToken, E(io.ErrUnexpectedEOF), ""},
319 {'0', zeroValue, E(io.ErrUnexpectedEOF), ""},
320 },
321 }, {
322 name: jsontest.Name("InvalidNumber"),
323 in: `0.e`,
324 calls: []decoderMethodCall{
325 {'0', zeroToken, newInvalidCharacterError("e", "in number (expecting digit)").withPos(`0.`, ""), ""},
326 {'0', zeroValue, newInvalidCharacterError("e", "in number (expecting digit)").withPos(`0.`, ""), ""},
327 },
328 }, {
329 name: jsontest.Name("TruncatedObject/AfterStart"),
330 in: `{`,
331 calls: []decoderMethodCall{
332 {'{', zeroValue, E(io.ErrUnexpectedEOF).withPos("{", ""), ""},
333 {'{', BeginObject, nil, ""},
334 {0, zeroToken, E(io.ErrUnexpectedEOF).withPos("{", ""), ""},
335 {0, zeroValue, E(io.ErrUnexpectedEOF).withPos("{", ""), ""},
336 },
337 wantOffset: len(`{`),
338 }, {
339 name: jsontest.Name("TruncatedObject/AfterName"),
340 in: `{"0"`,
341 calls: []decoderMethodCall{
342 {'{', zeroValue, E(io.ErrUnexpectedEOF).withPos(`{"0"`, "/0"), ""},
343 {'{', BeginObject, nil, ""},
344 {'"', String("0"), nil, ""},
345 {0, zeroToken, E(io.ErrUnexpectedEOF).withPos(`{"0"`, "/0"), ""},
346 {0, zeroValue, E(io.ErrUnexpectedEOF).withPos(`{"0"`, "/0"), ""},
347 },
348 wantOffset: len(`{"0"`),
349 }, {
350 name: jsontest.Name("TruncatedObject/AfterColon"),
351 in: `{"0":`,
352 calls: []decoderMethodCall{
353 {'{', zeroValue, E(io.ErrUnexpectedEOF).withPos(`{"0":`, "/0"), ""},
354 {'{', BeginObject, nil, ""},
355 {'"', String("0"), nil, ""},
356 {0, zeroToken, E(io.ErrUnexpectedEOF).withPos(`{"0":`, "/0"), ""},
357 {0, zeroValue, E(io.ErrUnexpectedEOF).withPos(`{"0":`, "/0"), ""},
358 },
359 wantOffset: len(`{"0"`),
360 }, {
361 name: jsontest.Name("TruncatedObject/AfterValue"),
362 in: `{"0":0`,
363 calls: []decoderMethodCall{
364 {'{', zeroValue, E(io.ErrUnexpectedEOF).withPos(`{"0":0`, ""), ""},
365 {'{', BeginObject, nil, ""},
366 {'"', String("0"), nil, ""},
367 {'0', Uint(0), nil, ""},
368 {0, zeroToken, E(io.ErrUnexpectedEOF).withPos(`{"0":0`, ""), ""},
369 {0, zeroValue, E(io.ErrUnexpectedEOF).withPos(`{"0":0`, ""), ""},
370 },
371 wantOffset: len(`{"0":0`),
372 }, {
373 name: jsontest.Name("TruncatedObject/AfterComma"),
374 in: `{"0":0,`,
375 calls: []decoderMethodCall{
376 {'{', zeroValue, E(io.ErrUnexpectedEOF).withPos(`{"0":0,`, ""), ""},
377 {'{', BeginObject, nil, ""},
378 {'"', String("0"), nil, ""},
379 {'0', Uint(0), nil, ""},
380 {0, zeroToken, E(io.ErrUnexpectedEOF).withPos(`{"0":0,`, ""), ""},
381 {0, zeroValue, E(io.ErrUnexpectedEOF).withPos(`{"0":0,`, ""), ""},
382 },
383 wantOffset: len(`{"0":0`),
384 }, {
385 name: jsontest.Name("InvalidObject/MissingColon"),
386 in: ` { "fizz" "buzz" } `,
387 calls: []decoderMethodCall{
388 {'{', zeroValue, newInvalidCharacterError("\"", "after object name (expecting ':')").withPos(` { "fizz" `, "/fizz"), ""},
389 {'{', BeginObject, nil, ""},
390 {'"', String("fizz"), nil, ""},
391 {0, zeroToken, newInvalidCharacterError("\"", "after object name (expecting ':')").withPos(` { "fizz" `, "/fizz"), ""},
392 {0, zeroValue, newInvalidCharacterError("\"", "after object name (expecting ':')").withPos(` { "fizz" `, "/fizz"), ""},
393 },
394 wantOffset: len(` { "fizz"`),
395 }, {
396 name: jsontest.Name("InvalidObject/MissingColon/GotComma"),
397 in: ` { "fizz" , "buzz" } `,
398 calls: []decoderMethodCall{
399 {'{', zeroValue, newInvalidCharacterError(",", "after object name (expecting ':')").withPos(` { "fizz" `, "/fizz"), ""},
400 {'{', BeginObject, nil, ""},
401 {'"', String("fizz"), nil, ""},
402 {0, zeroToken, newInvalidCharacterError(",", "after object name (expecting ':')").withPos(` { "fizz" `, "/fizz"), ""},
403 {0, zeroValue, newInvalidCharacterError(",", "after object name (expecting ':')").withPos(` { "fizz" `, "/fizz"), ""},
404 },
405 wantOffset: len(` { "fizz"`),
406 }, {
407 name: jsontest.Name("InvalidObject/MissingColon/GotHash"),
408 in: ` { "fizz" # "buzz" } `,
409 calls: []decoderMethodCall{
410 {'{', zeroValue, newInvalidCharacterError("#", "after object name (expecting ':')").withPos(` { "fizz" `, "/fizz"), ""},
411 {'{', BeginObject, nil, ""},
412 {'"', String("fizz"), nil, ""},
413 {0, zeroToken, newInvalidCharacterError("#", "after object name (expecting ':')").withPos(` { "fizz" `, "/fizz"), ""},
414 {0, zeroValue, newInvalidCharacterError("#", "after object name (expecting ':')").withPos(` { "fizz" `, "/fizz"), ""},
415 },
416 wantOffset: len(` { "fizz"`),
417 }, {
418 name: jsontest.Name("InvalidObject/MissingComma"),
419 in: ` { "fizz" : "buzz" "gazz" } `,
420 calls: []decoderMethodCall{
421 {'{', zeroValue, newInvalidCharacterError("\"", "after object value (expecting ',' or '}')").withPos(` { "fizz" : "buzz" `, ""), ""},
422 {'{', BeginObject, nil, ""},
423 {'"', String("fizz"), nil, ""},
424 {'"', String("buzz"), nil, ""},
425 {0, zeroToken, newInvalidCharacterError("\"", "after object value (expecting ',' or '}')").withPos(` { "fizz" : "buzz" `, ""), ""},
426 {0, zeroValue, newInvalidCharacterError("\"", "after object value (expecting ',' or '}')").withPos(` { "fizz" : "buzz" `, ""), ""},
427 },
428 wantOffset: len(` { "fizz" : "buzz"`),
429 }, {
430 name: jsontest.Name("InvalidObject/MissingComma/GotColon"),
431 in: ` { "fizz" : "buzz" : "gazz" } `,
432 calls: []decoderMethodCall{
433 {'{', zeroValue, newInvalidCharacterError(":", "after object value (expecting ',' or '}')").withPos(` { "fizz" : "buzz" `, ""), ""},
434 {'{', BeginObject, nil, ""},
435 {'"', String("fizz"), nil, ""},
436 {'"', String("buzz"), nil, ""},
437 {0, zeroToken, newInvalidCharacterError(":", "after object value (expecting ',' or '}')").withPos(` { "fizz" : "buzz" `, ""), ""},
438 {0, zeroValue, newInvalidCharacterError(":", "after object value (expecting ',' or '}')").withPos(` { "fizz" : "buzz" `, ""), ""},
439 },
440 wantOffset: len(` { "fizz" : "buzz"`),
441 }, {
442 name: jsontest.Name("InvalidObject/MissingComma/GotHash"),
443 in: ` { "fizz" : "buzz" # "gazz" } `,
444 calls: []decoderMethodCall{
445 {'{', zeroValue, newInvalidCharacterError("#", "after object value (expecting ',' or '}')").withPos(` { "fizz" : "buzz" `, ""), ""},
446 {'{', BeginObject, nil, ""},
447 {'"', String("fizz"), nil, ""},
448 {'"', String("buzz"), nil, ""},
449 {0, zeroToken, newInvalidCharacterError("#", "after object value (expecting ',' or '}')").withPos(` { "fizz" : "buzz" `, ""), ""},
450 {0, zeroValue, newInvalidCharacterError("#", "after object value (expecting ',' or '}')").withPos(` { "fizz" : "buzz" `, ""), ""},
451 },
452 wantOffset: len(` { "fizz" : "buzz"`),
453 }, {
454 name: jsontest.Name("InvalidObject/ExtraComma/AfterStart"),
455 in: ` { , } `,
456 calls: []decoderMethodCall{
457 {'{', zeroValue, newInvalidCharacterError(",", `at start of string (expecting '"')`).withPos(` { `, ""), ""},
458 {'{', BeginObject, nil, ""},
459 {0, zeroToken, newInvalidCharacterError(",", `at start of value`).withPos(` { `, ""), ""},
460 {0, zeroValue, newInvalidCharacterError(",", `at start of value`).withPos(` { `, ""), ""},
461 },
462 wantOffset: len(` {`),
463 }, {
464 name: jsontest.Name("InvalidObject/ExtraComma/AfterValue"),
465 in: ` { "fizz" : "buzz" , } `,
466 calls: []decoderMethodCall{
467 {'{', zeroValue, newInvalidCharacterError("}", `at start of string (expecting '"')`).withPos(` { "fizz" : "buzz" , `, ""), ""},
468 {'{', BeginObject, nil, ""},
469 {'"', String("fizz"), nil, ""},
470 {'"', String("buzz"), nil, ""},
471 {0, zeroToken, newInvalidCharacterError(",", `at start of value`).withPos(` { "fizz" : "buzz" `, ""), ""},
472 {0, zeroValue, newInvalidCharacterError(",", `at start of value`).withPos(` { "fizz" : "buzz" `, ""), ""},
473 },
474 wantOffset: len(` { "fizz" : "buzz"`),
475 }, {
476 name: jsontest.Name("InvalidObject/InvalidName/GotNull"),
477 in: ` { null : null } `,
478 calls: []decoderMethodCall{
479 {'{', zeroValue, newInvalidCharacterError("n", "at start of string (expecting '\"')").withPos(` { `, ""), ""},
480 {'{', BeginObject, nil, ""},
481 {'n', zeroToken, E(ErrNonStringName).withPos(` { `, ""), ""},
482 {'n', zeroValue, E(ErrNonStringName).withPos(` { `, ""), ""},
483 },
484 wantOffset: len(` {`),
485 }, {
486 name: jsontest.Name("InvalidObject/InvalidName/GotFalse"),
487 in: ` { false : false } `,
488 calls: []decoderMethodCall{
489 {'{', zeroValue, newInvalidCharacterError("f", "at start of string (expecting '\"')").withPos(` { `, ""), ""},
490 {'{', BeginObject, nil, ""},
491 {'f', zeroToken, E(ErrNonStringName).withPos(` { `, ""), ""},
492 {'f', zeroValue, E(ErrNonStringName).withPos(` { `, ""), ""},
493 },
494 wantOffset: len(` {`),
495 }, {
496 name: jsontest.Name("InvalidObject/InvalidName/GotTrue"),
497 in: ` { true : true } `,
498 calls: []decoderMethodCall{
499 {'{', zeroValue, newInvalidCharacterError("t", "at start of string (expecting '\"')").withPos(` { `, ""), ""},
500 {'{', BeginObject, nil, ""},
501 {'t', zeroToken, E(ErrNonStringName).withPos(` { `, ""), ""},
502 {'t', zeroValue, E(ErrNonStringName).withPos(` { `, ""), ""},
503 },
504 wantOffset: len(` {`),
505 }, {
506 name: jsontest.Name("InvalidObject/InvalidName/GotNumber"),
507 in: ` { 0 : 0 } `,
508 calls: []decoderMethodCall{
509 {'{', zeroValue, newInvalidCharacterError("0", "at start of string (expecting '\"')").withPos(` { `, ""), ""},
510 {'{', BeginObject, nil, ""},
511 {'0', zeroToken, E(ErrNonStringName).withPos(` { `, ""), ""},
512 {'0', zeroValue, E(ErrNonStringName).withPos(` { `, ""), ""},
513 },
514 wantOffset: len(` {`),
515 }, {
516 name: jsontest.Name("InvalidObject/InvalidName/GotObject"),
517 in: ` { {} : {} } `,
518 calls: []decoderMethodCall{
519 {'{', zeroValue, newInvalidCharacterError("{", "at start of string (expecting '\"')").withPos(` { `, ""), ""},
520 {'{', BeginObject, nil, ""},
521 {'{', zeroToken, E(ErrNonStringName).withPos(` { `, ""), ""},
522 {'{', zeroValue, E(ErrNonStringName).withPos(` { `, ""), ""},
523 },
524 wantOffset: len(` {`),
525 }, {
526 name: jsontest.Name("InvalidObject/InvalidName/GotArray"),
527 in: ` { [] : [] } `,
528 calls: []decoderMethodCall{
529 {'{', zeroValue, newInvalidCharacterError("[", "at start of string (expecting '\"')").withPos(` { `, ""), ""},
530 {'{', BeginObject, nil, ""},
531 {'[', zeroToken, E(ErrNonStringName).withPos(` { `, ""), ""},
532 {'[', zeroValue, E(ErrNonStringName).withPos(` { `, ""), ""},
533 },
534 wantOffset: len(` {`),
535 }, {
536 name: jsontest.Name("InvalidObject/MismatchingDelim"),
537 in: ` { ] `,
538 calls: []decoderMethodCall{
539 {'{', zeroValue, newInvalidCharacterError("]", "at start of string (expecting '\"')").withPos(` { `, ""), ""},
540 {'{', BeginObject, nil, ""},
541 {']', zeroToken, newInvalidCharacterError("]", "at start of value").withPos(` { `, ""), ""},
542 {']', zeroValue, newInvalidCharacterError("]", "at start of value").withPos(` { `, ""), ""},
543 },
544 wantOffset: len(` {`),
545 }, {
546 name: jsontest.Name("ValidObject/InvalidValue"),
547 in: ` { } `,
548 calls: []decoderMethodCall{
549 {'{', BeginObject, nil, ""},
550 {'}', zeroValue, newInvalidCharacterError("}", "at start of value").withPos(" { ", ""), ""},
551 },
552 wantOffset: len(` {`),
553 }, {
554 name: jsontest.Name("ValidObject/UniqueNames"),
555 in: `{"0":0,"1":1} `,
556 calls: []decoderMethodCall{
557 {'{', BeginObject, nil, ""},
558 {'"', String("0"), nil, ""},
559 {'0', Uint(0), nil, ""},
560 {'"', String("1"), nil, ""},
561 {'0', Uint(1), nil, ""},
562 {'}', EndObject, nil, ""},
563 },
564 wantOffset: len(`{"0":0,"1":1}`),
565 }, {
566 name: jsontest.Name("ValidObject/DuplicateNames"),
567 opts: []Options{AllowDuplicateNames(true)},
568 in: `{"0":0,"0":0} `,
569 calls: []decoderMethodCall{
570 {'{', BeginObject, nil, ""},
571 {'"', String("0"), nil, ""},
572 {'0', Uint(0), nil, ""},
573 {'"', String("0"), nil, ""},
574 {'0', Uint(0), nil, ""},
575 {'}', EndObject, nil, ""},
576 },
577 wantOffset: len(`{"0":0,"0":0}`),
578 }, {
579 name: jsontest.Name("InvalidObject/DuplicateNames"),
580 in: `{"X":{},"Y":{},"X":{}} `,
581 calls: []decoderMethodCall{
582 {'{', zeroValue, E(ErrDuplicateName).withPos(`{"X":{},"Y":{},`, "/X"), ""},
583 {'{', BeginObject, nil, ""},
584 {'"', String("X"), nil, ""},
585 {'{', BeginObject, nil, ""},
586 {'}', EndObject, nil, ""},
587 {'"', String("Y"), nil, ""},
588 {'{', BeginObject, nil, ""},
589 {'}', EndObject, nil, ""},
590 {'"', zeroToken, E(ErrDuplicateName).withPos(`{"X":{},"Y":{},`, "/X"), "/Y"},
591 {'"', zeroValue, E(ErrDuplicateName).withPos(`{"0":{},"Y":{},`, "/X"), "/Y"},
592 },
593 wantOffset: len(`{"0":{},"1":{}`),
594 }, {
595 name: jsontest.Name("TruncatedArray/AfterStart"),
596 in: `[`,
597 calls: []decoderMethodCall{
598 {'[', zeroValue, E(io.ErrUnexpectedEOF).withPos("[", ""), ""},
599 {'[', BeginArray, nil, ""},
600 {0, zeroToken, E(io.ErrUnexpectedEOF).withPos("[", ""), ""},
601 {0, zeroValue, E(io.ErrUnexpectedEOF).withPos("[", ""), ""},
602 },
603 wantOffset: len(`[`),
604 }, {
605 name: jsontest.Name("TruncatedArray/AfterValue"),
606 in: `[0`,
607 calls: []decoderMethodCall{
608 {'[', zeroValue, E(io.ErrUnexpectedEOF).withPos("[0", ""), ""},
609 {'[', BeginArray, nil, ""},
610 {'0', Uint(0), nil, ""},
611 {0, zeroToken, E(io.ErrUnexpectedEOF).withPos("[0", ""), ""},
612 {0, zeroValue, E(io.ErrUnexpectedEOF).withPos("[0", ""), ""},
613 },
614 wantOffset: len(`[0`),
615 }, {
616 name: jsontest.Name("TruncatedArray/AfterComma"),
617 in: `[0,`,
618 calls: []decoderMethodCall{
619 {'[', zeroValue, E(io.ErrUnexpectedEOF).withPos("[0,", ""), ""},
620 {'[', BeginArray, nil, ""},
621 {'0', Uint(0), nil, ""},
622 {0, zeroToken, E(io.ErrUnexpectedEOF).withPos("[0,", ""), ""},
623 {0, zeroValue, E(io.ErrUnexpectedEOF).withPos("[0,", ""), ""},
624 },
625 wantOffset: len(`[0`),
626 }, {
627 name: jsontest.Name("InvalidArray/MissingComma"),
628 in: ` [ "fizz" "buzz" ] `,
629 calls: []decoderMethodCall{
630 {'[', zeroValue, newInvalidCharacterError("\"", "after array element (expecting ',' or ']')").withPos(` [ "fizz" `, ""), ""},
631 {'[', BeginArray, nil, ""},
632 {'"', String("fizz"), nil, ""},
633 {0, zeroToken, newInvalidCharacterError("\"", "after array element (expecting ',' or ']')").withPos(` [ "fizz" `, ""), ""},
634 {0, zeroValue, newInvalidCharacterError("\"", "after array element (expecting ',' or ']')").withPos(` [ "fizz" `, ""), ""},
635 },
636 wantOffset: len(` [ "fizz"`),
637 }, {
638 name: jsontest.Name("InvalidArray/MismatchingDelim"),
639 in: ` [ } `,
640 calls: []decoderMethodCall{
641 {'[', zeroValue, newInvalidCharacterError("}", "at start of value").withPos(` [ `, "/0"), ""},
642 {'[', BeginArray, nil, ""},
643 {'}', zeroToken, newInvalidCharacterError("}", "at start of value").withPos(` [ `, "/0"), ""},
644 {'}', zeroValue, newInvalidCharacterError("}", "at start of value").withPos(` [ `, "/0"), ""},
645 },
646 wantOffset: len(` [`),
647 }, {
648 name: jsontest.Name("ValidArray/InvalidValue"),
649 in: ` [ ] `,
650 calls: []decoderMethodCall{
651 {'[', BeginArray, nil, ""},
652 {']', zeroValue, newInvalidCharacterError("]", "at start of value").withPos(" [ ", "/0"), ""},
653 },
654 wantOffset: len(` [`),
655 }, {
656 name: jsontest.Name("InvalidDelim/AfterTopLevel"),
657 in: `"",`,
658 calls: []decoderMethodCall{
659 {'"', String(""), nil, ""},
660 {0, zeroToken, newInvalidCharacterError(",", "at start of value").withPos(`""`, ""), ""},
661 {0, zeroValue, newInvalidCharacterError(",", "at start of value").withPos(`""`, ""), ""},
662 },
663 wantOffset: len(`""`),
664 }, {
665 name: jsontest.Name("InvalidDelim/AfterBeginObject"),
666 in: `{:`,
667 calls: []decoderMethodCall{
668 {'{', zeroValue, newInvalidCharacterError(":", `at start of string (expecting '"')`).withPos(`{`, ""), ""},
669 {'{', BeginObject, nil, ""},
670 {0, zeroToken, newInvalidCharacterError(":", "at start of value").withPos(`{`, ""), ""},
671 {0, zeroValue, newInvalidCharacterError(":", "at start of value").withPos(`{`, ""), ""},
672 },
673 wantOffset: len(`{`),
674 }, {
675 name: jsontest.Name("InvalidDelim/AfterObjectName"),
676 in: `{"",`,
677 calls: []decoderMethodCall{
678 {'{', zeroValue, newInvalidCharacterError(",", "after object name (expecting ':')").withPos(`{""`, "/"), ""},
679 {'{', BeginObject, nil, ""},
680 {'"', String(""), nil, ""},
681 {0, zeroToken, newInvalidCharacterError(",", "after object name (expecting ':')").withPos(`{""`, "/"), ""},
682 {0, zeroValue, newInvalidCharacterError(",", "after object name (expecting ':')").withPos(`{""`, "/"), ""},
683 },
684 wantOffset: len(`{""`),
685 }, {
686 name: jsontest.Name("ValidDelim/AfterObjectName"),
687 in: `{"":`,
688 calls: []decoderMethodCall{
689 {'{', zeroValue, E(io.ErrUnexpectedEOF).withPos(`{"":`, "/"), ""},
690 {'{', BeginObject, nil, ""},
691 {'"', String(""), nil, ""},
692 {0, zeroToken, E(io.ErrUnexpectedEOF).withPos(`{"":`, "/"), ""},
693 {0, zeroValue, E(io.ErrUnexpectedEOF).withPos(`{"":`, "/"), ""},
694 },
695 wantOffset: len(`{""`),
696 }, {
697 name: jsontest.Name("InvalidDelim/AfterObjectValue"),
698 in: `{"":"":`,
699 calls: []decoderMethodCall{
700 {'{', zeroValue, newInvalidCharacterError(":", "after object value (expecting ',' or '}')").withPos(`{"":""`, ""), ""},
701 {'{', BeginObject, nil, ""},
702 {'"', String(""), nil, ""},
703 {'"', String(""), nil, ""},
704 {0, zeroToken, newInvalidCharacterError(":", "after object value (expecting ',' or '}')").withPos(`{"":""`, ""), ""},
705 {0, zeroValue, newInvalidCharacterError(":", "after object value (expecting ',' or '}')").withPos(`{"":""`, ""), ""},
706 },
707 wantOffset: len(`{"":""`),
708 }, {
709 name: jsontest.Name("ValidDelim/AfterObjectValue"),
710 in: `{"":"",`,
711 calls: []decoderMethodCall{
712 {'{', zeroValue, E(io.ErrUnexpectedEOF).withPos(`{"":"",`, ""), ""},
713 {'{', BeginObject, nil, ""},
714 {'"', String(""), nil, ""},
715 {'"', String(""), nil, ""},
716 {0, zeroToken, E(io.ErrUnexpectedEOF).withPos(`{"":"",`, ""), ""},
717 {0, zeroValue, E(io.ErrUnexpectedEOF).withPos(`{"":"",`, ""), ""},
718 },
719 wantOffset: len(`{"":""`),
720 }, {
721 name: jsontest.Name("InvalidDelim/AfterBeginArray"),
722 in: `[,`,
723 calls: []decoderMethodCall{
724 {'[', zeroValue, newInvalidCharacterError(",", "at start of value").withPos(`[`, "/0"), ""},
725 {'[', BeginArray, nil, ""},
726 {0, zeroToken, newInvalidCharacterError(",", "at start of value").withPos(`[`, ""), ""},
727 {0, zeroValue, newInvalidCharacterError(",", "at start of value").withPos(`[`, ""), ""},
728 },
729 wantOffset: len(`[`),
730 }, {
731 name: jsontest.Name("InvalidDelim/AfterArrayValue"),
732 in: `["":`,
733 calls: []decoderMethodCall{
734 {'[', zeroValue, newInvalidCharacterError(":", "after array element (expecting ',' or ']')").withPos(`[""`, ""), ""},
735 {'[', BeginArray, nil, ""},
736 {'"', String(""), nil, ""},
737 {0, zeroToken, newInvalidCharacterError(":", "after array element (expecting ',' or ']')").withPos(`[""`, ""), ""},
738 {0, zeroValue, newInvalidCharacterError(":", "after array element (expecting ',' or ']')").withPos(`[""`, ""), ""},
739 },
740 wantOffset: len(`[""`),
741 }, {
742 name: jsontest.Name("ValidDelim/AfterArrayValue"),
743 in: `["",`,
744 calls: []decoderMethodCall{
745 {'[', zeroValue, E(io.ErrUnexpectedEOF).withPos(`["",`, ""), ""},
746 {'[', BeginArray, nil, ""},
747 {'"', String(""), nil, ""},
748 {0, zeroToken, E(io.ErrUnexpectedEOF).withPos(`["",`, ""), ""},
749 {0, zeroValue, E(io.ErrUnexpectedEOF).withPos(`["",`, ""), ""},
750 },
751 wantOffset: len(`[""`),
752 }, {
753 name: jsontest.Name("ErrorPosition"),
754 in: ` "a` + "\xff" + `0" `,
755 calls: []decoderMethodCall{
756 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` "a`, ""), ""},
757 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` "a`, ""), ""},
758 },
759 }, {
760 name: jsontest.Name("ErrorPosition/0"),
761 in: ` [ "a` + "\xff" + `1" ] `,
762 calls: []decoderMethodCall{
763 {'[', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a`, "/0"), ""},
764 {'[', BeginArray, nil, ""},
765 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a`, "/0"), ""},
766 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a`, "/0"), ""},
767 },
768 wantOffset: len(` [`),
769 }, {
770 name: jsontest.Name("ErrorPosition/1"),
771 in: ` [ "a1" , "b` + "\xff" + `1" ] `,
772 calls: []decoderMethodCall{
773 {'[', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a1" , "b`, "/1"), ""},
774 {'[', BeginArray, nil, ""},
775 {'"', String("a1"), nil, ""},
776 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a1" , "b`, "/1"), ""},
777 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a1" , "b`, "/1"), ""},
778 },
779 wantOffset: len(` [ "a1"`),
780 }, {
781 name: jsontest.Name("ErrorPosition/0/0"),
782 in: ` [ [ "a` + "\xff" + `2" ] ] `,
783 calls: []decoderMethodCall{
784 {'[', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ [ "a`, "/0/0"), ""},
785 {'[', BeginArray, nil, ""},
786 {'[', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ [ "a`, "/0/0"), ""},
787 {'[', BeginArray, nil, "/0"},
788 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ [ "a`, "/0/0"), ""},
789 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` [ [ "a`, "/0/0"), ""},
790 },
791 wantOffset: len(` [ [`),
792 }, {
793 name: jsontest.Name("ErrorPosition/1/0"),
794 in: ` [ "a1" , [ "a` + "\xff" + `2" ] ] `,
795 calls: []decoderMethodCall{
796 {'[', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a1" , [ "a`, "/1/0"), ""},
797 {'[', BeginArray, nil, ""},
798 {'"', String("a1"), nil, "/0"},
799 {'[', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a1" , [ "a`, "/1/0"), "/0"},
800 {'[', BeginArray, nil, "/1"},
801 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a1" , [ "a`, "/1/0"), "/1"},
802 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a1" , [ "a`, "/1/0"), "/1"},
803 },
804 wantOffset: len(` [ "a1" , [`),
805 }, {
806 name: jsontest.Name("ErrorPosition/0/1"),
807 in: ` [ [ "a2" , "b` + "\xff" + `2" ] ] `,
808 calls: []decoderMethodCall{
809 {'[', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ [ "a2" , "b`, "/0/1"), ""},
810 {'[', BeginArray, nil, ""},
811 {'[', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ [ "a2" , "b`, "/0/1"), ""},
812 {'[', BeginArray, nil, "/0"},
813 {'"', String("a2"), nil, "/0/0"},
814 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ [ "a2" , "b`, "/0/1"), "/0/0"},
815 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` [ [ "a2" , "b`, "/0/1"), "/0/0"},
816 },
817 wantOffset: len(` [ [ "a2"`),
818 }, {
819 name: jsontest.Name("ErrorPosition/1/1"),
820 in: ` [ "a1" , [ "a2" , "b` + "\xff" + `2" ] ] `,
821 calls: []decoderMethodCall{
822 {'[', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a1" , [ "a2" , "b`, "/1/1"), ""},
823 {'[', BeginArray, nil, ""},
824 {'"', String("a1"), nil, "/0"},
825 {'[', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a1" , [ "a2" , "b`, "/1/1"), ""},
826 {'[', BeginArray, nil, "/1"},
827 {'"', String("a2"), nil, "/1/0"},
828 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a1" , [ "a2" , "b`, "/1/1"), "/1/0"},
829 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a1" , [ "a2" , "b`, "/1/1"), "/1/0"},
830 },
831 wantOffset: len(` [ "a1" , [ "a2"`),
832 }, {
833 name: jsontest.Name("ErrorPosition/a1-"),
834 in: ` { "a` + "\xff" + `1" : "b1" } `,
835 calls: []decoderMethodCall{
836 {'{', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a`, ""), ""},
837 {'{', BeginObject, nil, ""},
838 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a`, ""), ""},
839 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` { "a`, ""), ""},
840 },
841 wantOffset: len(` {`),
842 }, {
843 name: jsontest.Name("ErrorPosition/a1"),
844 in: ` { "a1" : "b` + "\xff" + `1" } `,
845 calls: []decoderMethodCall{
846 {'{', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : "b`, "/a1"), ""},
847 {'{', BeginObject, nil, ""},
848 {'"', String("a1"), nil, "/a1"},
849 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : "b`, "/a1"), ""},
850 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : "b`, "/a1"), ""},
851 },
852 wantOffset: len(` { "a1"`),
853 }, {
854 name: jsontest.Name("ErrorPosition/c1-"),
855 in: ` { "a1" : "b1" , "c` + "\xff" + `1" : "d1" } `,
856 calls: []decoderMethodCall{
857 {'{', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : "b1" , "c`, ""), ""},
858 {'{', BeginObject, nil, ""},
859 {'"', String("a1"), nil, "/a1"},
860 {'"', String("b1"), nil, "/a1"},
861 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : "b1" : "c`, ""), "/a1"},
862 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : "b1" : "c`, ""), "/a1"},
863 },
864 wantOffset: len(` { "a1" : "b1"`),
865 }, {
866 name: jsontest.Name("ErrorPosition/c1"),
867 in: ` { "a1" : "b1" , "c1" : "d` + "\xff" + `1" } `,
868 calls: []decoderMethodCall{
869 {'{', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : "b1" , "c1" : "d`, "/c1"), ""},
870 {'{', BeginObject, nil, ""},
871 {'"', String("a1"), nil, "/a1"},
872 {'"', String("b1"), nil, "/a1"},
873 {'"', String("c1"), nil, "/c1"},
874 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : "b1" : "c1" : "d`, "/c1"), "/c1"},
875 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : "b1" : "c1" : "d`, "/c1"), "/c1"},
876 },
877 wantOffset: len(` { "a1" : "b1" , "c1"`),
878 }, {
879 name: jsontest.Name("ErrorPosition/a1/a2-"),
880 in: ` { "a1" : { "a` + "\xff" + `2" : "b2" } } `,
881 calls: []decoderMethodCall{
882 {'{', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : { "a`, "/a1"), ""},
883 {'{', BeginObject, nil, ""},
884 {'"', String("a1"), nil, "/a1"},
885 {'{', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : { "a`, "/a1"), ""},
886 {'{', BeginObject, nil, "/a1"},
887 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : { "a`, "/a1"), "/a1"},
888 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : { "a`, "/a1"), "/a1"},
889 },
890 wantOffset: len(` { "a1" : {`),
891 }, {
892 name: jsontest.Name("ErrorPosition/a1/a2"),
893 in: ` { "a1" : { "a2" : "b` + "\xff" + `2" } } `,
894 calls: []decoderMethodCall{
895 {'{', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : { "a2" : "b`, "/a1/a2"), ""},
896 {'{', BeginObject, nil, ""},
897 {'"', String("a1"), nil, "/a1"},
898 {'{', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : { "a2" : "b`, "/a1/a2"), ""},
899 {'{', BeginObject, nil, "/a1"},
900 {'"', String("a2"), nil, "/a1/a2"},
901 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : { "a2" : "b`, "/a1/a2"), "/a1/a2"},
902 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : { "a2" : "b`, "/a1/a2"), "/a1/a2"},
903 },
904 wantOffset: len(` { "a1" : { "a2"`),
905 }, {
906 name: jsontest.Name("ErrorPosition/a1/c2-"),
907 in: ` { "a1" : { "a2" : "b2" , "c` + "\xff" + `2" : "d2" } } `,
908 calls: []decoderMethodCall{
909 {'{', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : { "a2" : "b2" , "c`, "/a1"), ""},
910 {'{', BeginObject, nil, ""},
911 {'"', String("a1"), nil, "/a1"},
912 {'{', BeginObject, nil, "/a1"},
913 {'"', String("a2"), nil, "/a1/a2"},
914 {'"', String("b2"), nil, "/a1/a2"},
915 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : { "a2" : "b2" , "c`, "/a1"), "/a1/a2"},
916 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : { "a2" : "b2" , "c`, "/a1"), "/a1/a2"},
917 },
918 wantOffset: len(` { "a1" : { "a2" : "b2"`),
919 }, {
920 name: jsontest.Name("ErrorPosition/a1/c2"),
921 in: ` { "a1" : { "a2" : "b2" , "c2" : "d` + "\xff" + `2" } } `,
922 calls: []decoderMethodCall{
923 {'{', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : { "a2" : "b2" , "c2" : "d`, "/a1/c2"), ""},
924 {'{', BeginObject, nil, ""},
925 {'"', String("a1"), nil, "/a1"},
926 {'{', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : { "a2" : "b2" , "c2" : "d`, "/a1/c2"), ""},
927 {'{', BeginObject, nil, ""},
928 {'"', String("a2"), nil, "/a1/a2"},
929 {'"', String("b2"), nil, "/a1/a2"},
930 {'"', String("c2"), nil, "/a1/c2"},
931 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : { "a2" : "b2" , "c2" : "d`, "/a1/c2"), "/a1/c2"},
932 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : { "a2" : "b2" , "c2" : "d`, "/a1/c2"), "/a1/c2"},
933 },
934 wantOffset: len(` { "a1" : { "a2" : "b2" , "c2"`),
935 }, {
936 name: jsontest.Name("ErrorPosition/1/a2"),
937 in: ` [ "a1" , { "a2" : "b` + "\xff" + `2" } ] `,
938 calls: []decoderMethodCall{
939 {'[', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a1" , { "a2" : "b`, "/1/a2"), ""},
940 {'[', BeginArray, nil, ""},
941 {'"', String("a1"), nil, "/0"},
942 {'{', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a1" , { "a2" : "b`, "/1/a2"), ""},
943 {'{', BeginObject, nil, "/1"},
944 {'"', String("a2"), nil, "/1/a2"},
945 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a1" , { "a2" : "b`, "/1/a2"), "/1/a2"},
946 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` [ "a1" , { "a2" : "b`, "/1/a2"), "/1/a2"},
947 },
948 wantOffset: len(` [ "a1" , { "a2"`),
949 }, {
950 name: jsontest.Name("ErrorPosition/c1/1"),
951 in: ` { "a1" : "b1" , "c1" : [ "a2" , "b` + "\xff" + `2" ] } `,
952 calls: []decoderMethodCall{
953 {'{', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : "b1" , "c1" : [ "a2" , "b`, "/c1/1"), ""},
954 {'{', BeginObject, nil, ""},
955 {'"', String("a1"), nil, "/a1"},
956 {'"', String("b1"), nil, "/a1"},
957 {'"', String("c1"), nil, "/c1"},
958 {'[', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : "b1" , "c1" : [ "a2" , "b`, "/c1/1"), ""},
959 {'[', BeginArray, nil, "/c1"},
960 {'"', String("a2"), nil, "/c1/0"},
961 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : "b1" , "c1" : [ "a2" , "b`, "/c1/1"), "/c1/0"},
962 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` { "a1" : "b1" , "c1" : [ "a2" , "b`, "/c1/1"), "/c1/0"},
963 },
964 wantOffset: len(` { "a1" : "b1" , "c1" : [ "a2"`),
965 }, {
966 name: jsontest.Name("ErrorPosition/0/a1/1/c3/1"),
967 in: ` [ { "a1" : [ "a2" , { "a3" : "b3" , "c3" : [ "a4" , "b` + "\xff" + `4" ] } ] } ] `,
968 calls: []decoderMethodCall{
969 {'[', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ { "a1" : [ "a2" , { "a3" : "b3" , "c3" : [ "a4" , "b`, "/0/a1/1/c3/1"), ""},
970 {'[', BeginArray, nil, ""},
971 {'{', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ { "a1" : [ "a2" , { "a3" : "b3" , "c3" : [ "a4" , "b`, "/0/a1/1/c3/1"), ""},
972 {'{', BeginObject, nil, "/0"},
973 {'"', String("a1"), nil, "/0/a1"},
974 {'[', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ { "a1" : [ "a2" , { "a3" : "b3" , "c3" : [ "a4" , "b`, "/0/a1/1/c3/1"), ""},
975 {'[', BeginArray, nil, ""},
976 {'"', String("a2"), nil, "/0/a1/0"},
977 {'{', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ { "a1" : [ "a2" , { "a3" : "b3" , "c3" : [ "a4" , "b`, "/0/a1/1/c3/1"), ""},
978 {'{', BeginObject, nil, "/0/a1/1"},
979 {'"', String("a3"), nil, "/0/a1/1/a3"},
980 {'"', String("b3"), nil, "/0/a1/1/a3"},
981 {'"', String("c3"), nil, "/0/a1/1/c3"},
982 {'[', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ { "a1" : [ "a2" , { "a3" : "b3" , "c3" : [ "a4" , "b`, "/0/a1/1/c3/1"), ""},
983 {'[', BeginArray, nil, "/0/a1/1/c3"},
984 {'"', String("a4"), nil, "/0/a1/1/c3/0"},
985 {'"', zeroValue, E(jsonwire.ErrInvalidUTF8).withPos(` [ { "a1" : [ "a2" , { "a3" : "b3" , "c3" : [ "a4" , "b`, "/0/a1/1/c3/1"), "/0/a1/1/c3/0"},
986 {'"', zeroToken, E(jsonwire.ErrInvalidUTF8).withPos(` [ { "a1" : [ "a2" , { "a3" : "b3" , "c3" : [ "a4" , "b`, "/0/a1/1/c3/1"), "/0/a1/1/c3/0"},
987 },
988 wantOffset: len(` [ { "a1" : [ "a2" , { "a3" : "b3" , "c3" : [ "a4"`),
989 }}
990
991
992
993 func TestDecoderErrors(t *testing.T) {
994 for _, td := range decoderErrorTestdata {
995 t.Run(path.Join(td.name.Name), func(t *testing.T) {
996 testDecoderErrors(t, td.name.Where, td.opts, td.in, td.calls, td.wantOffset)
997 })
998 }
999 }
1000 func testDecoderErrors(t *testing.T, where jsontest.CasePos, opts []Options, in string, calls []decoderMethodCall, wantOffset int) {
1001 src := bytes.NewBufferString(in)
1002 dec := NewDecoder(src, opts...)
1003 for i, call := range calls {
1004 gotKind := dec.PeekKind()
1005 if gotKind != call.wantKind {
1006 t.Fatalf("%s: %d: Decoder.PeekKind = %v, want %v", where, i, gotKind, call.wantKind)
1007 }
1008
1009 var gotErr error
1010 switch wantOut := call.wantOut.(type) {
1011 case Token:
1012 var gotOut Token
1013 gotOut, gotErr = dec.ReadToken()
1014 if gotOut.String() != wantOut.String() {
1015 t.Fatalf("%s: %d: Decoder.ReadToken = %v, want %v", where, i, gotOut, wantOut)
1016 }
1017 case Value:
1018 var gotOut Value
1019 gotOut, gotErr = dec.ReadValue()
1020 if string(gotOut) != string(wantOut) {
1021 t.Fatalf("%s: %d: Decoder.ReadValue = %s, want %s", where, i, gotOut, wantOut)
1022 }
1023 }
1024 if !equalError(gotErr, call.wantErr) {
1025 t.Fatalf("%s: %d: error mismatch:\ngot %v\nwant %v", where, i, gotErr, call.wantErr)
1026 }
1027 if call.wantPointer != "" {
1028 gotPointer := dec.StackPointer()
1029 if gotPointer != call.wantPointer {
1030 t.Fatalf("%s: %d: Decoder.StackPointer = %s, want %s", where, i, gotPointer, call.wantPointer)
1031 }
1032 }
1033 }
1034 gotOffset := int(dec.InputOffset())
1035 if gotOffset != wantOffset {
1036 t.Fatalf("%s: Decoder.InputOffset = %v, want %v", where, gotOffset, wantOffset)
1037 }
1038 gotUnread := string(dec.s.unreadBuffer())
1039 wantUnread := in[wantOffset:]
1040 if !strings.HasPrefix(wantUnread, gotUnread) {
1041 t.Fatalf("%s: Decoder.UnreadBuffer = %v, want %v", where, gotUnread, wantUnread)
1042 }
1043 }
1044
1045
1046 func TestBufferDecoder(t *testing.T) {
1047 bb := bytes.NewBufferString("[null, false, true]")
1048 dec := NewDecoder(bb)
1049 var err error
1050 for {
1051 if _, err = dec.ReadToken(); err != nil {
1052 break
1053 }
1054 bb.WriteByte(' ')
1055 }
1056 want := &ioError{action: "read", err: errBufferWriteAfterNext}
1057 if !equalError(err, want) {
1058 t.Fatalf("error mismatch: got %v, want %v", err, want)
1059 }
1060 }
1061
1062 var resumableDecoderTestdata = []string{
1063 `0`,
1064 `123456789`,
1065 `0.0`,
1066 `0.123456789`,
1067 `0e0`,
1068 `0e+0`,
1069 `0e123456789`,
1070 `0e+123456789`,
1071 `123456789.123456789e+123456789`,
1072 `-0`,
1073 `-123456789`,
1074 `-0.0`,
1075 `-0.123456789`,
1076 `-0e0`,
1077 `-0e-0`,
1078 `-0e123456789`,
1079 `-0e-123456789`,
1080 `-123456789.123456789e-123456789`,
1081
1082 `""`,
1083 `"a"`,
1084 `"ab"`,
1085 `"abc"`,
1086 `"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"`,
1087 `"\"\\\/\b\f\n\r\t"`,
1088 `"\u0022\u005c\u002f\u0008\u000c\u000a\u000d\u0009"`,
1089 `"\ud800\udead"`,
1090 "\"\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\U0001f602\"",
1091 `"\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\ud83d\ude02"`,
1092 }
1093
1094
1095
1096 func TestResumableDecoder(t *testing.T) {
1097 for _, want := range resumableDecoderTestdata {
1098 t.Run("", func(t *testing.T) {
1099 dec := NewDecoder(iotest.OneByteReader(strings.NewReader(want)))
1100 got, err := dec.ReadValue()
1101 if err != nil {
1102 t.Fatalf("Decoder.ReadValue error: %v", err)
1103 }
1104 if string(got) != want {
1105 t.Fatalf("Decoder.ReadValue = %s, want %s", got, want)
1106 }
1107 })
1108 }
1109 }
1110
1111
1112
1113
1114
1115 func TestBlockingDecoder(t *testing.T) {
1116 values := []string{"null", "false", "true", `""`, `{}`, `[]`}
1117
1118 r, w := net.Pipe()
1119 defer r.Close()
1120 defer w.Close()
1121
1122 enc := NewEncoder(w, jsonflags.OmitTopLevelNewline|1)
1123 dec := NewDecoder(r)
1124
1125 errCh := make(chan error)
1126
1127
1128 for _, want := range values {
1129 go func() {
1130 errCh <- enc.WriteValue(Value(want))
1131 }()
1132
1133 tok, err := dec.ReadToken()
1134 if err != nil {
1135 t.Fatalf("Decoder.ReadToken error: %v", err)
1136 }
1137 got := tok.String()
1138 switch tok.Kind() {
1139 case '"':
1140 got = `"` + got + `"`
1141 case '{', '[':
1142 tok, err := dec.ReadToken()
1143 if err != nil {
1144 t.Fatalf("Decoder.ReadToken error: %v", err)
1145 }
1146 got += tok.String()
1147 }
1148 if got != want {
1149 t.Fatalf("ReadTokens = %s, want %s", got, want)
1150 }
1151
1152 if err := <-errCh; err != nil {
1153 t.Fatalf("Encoder.WriteValue error: %v", err)
1154 }
1155 }
1156
1157
1158 for _, want := range values {
1159 go func() {
1160 errCh <- enc.WriteValue(Value(want))
1161 }()
1162
1163 got, err := dec.ReadValue()
1164 if err != nil {
1165 t.Fatalf("Decoder.ReadValue error: %v", err)
1166 }
1167 if string(got) != want {
1168 t.Fatalf("ReadValue = %s, want %s", got, want)
1169 }
1170
1171 if err := <-errCh; err != nil {
1172 t.Fatalf("Encoder.WriteValue error: %v", err)
1173 }
1174 }
1175 }
1176
1177 func TestPeekableDecoder(t *testing.T) {
1178 type operation any
1179 type PeekKind struct {
1180 want Kind
1181 }
1182 type ReadToken struct {
1183 wantKind Kind
1184 wantErr error
1185 }
1186 type ReadValue struct {
1187 wantKind Kind
1188 wantErr error
1189 }
1190 type WriteString struct {
1191 in string
1192 }
1193 ops := []operation{
1194 PeekKind{0},
1195 WriteString{"[ "},
1196 ReadToken{0, io.EOF},
1197 ReadToken{'[', nil},
1198
1199 PeekKind{0},
1200 WriteString{"] "},
1201 ReadValue{0, E(io.ErrUnexpectedEOF).withPos("[ ", "")},
1202 ReadValue{0, newInvalidCharacterError("]", "at start of value").withPos("[ ", "/0")},
1203 ReadToken{']', nil},
1204
1205 WriteString{"[ "},
1206 ReadToken{'[', nil},
1207
1208 WriteString{" null "},
1209 PeekKind{'n'},
1210 PeekKind{'n'},
1211 ReadToken{'n', nil},
1212
1213 WriteString{", "},
1214 PeekKind{0},
1215 WriteString{"fal"},
1216 PeekKind{'f'},
1217 ReadValue{0, E(io.ErrUnexpectedEOF).withPos("[ ] [ null , fal", "/1")},
1218 WriteString{"se "},
1219 ReadValue{'f', nil},
1220
1221 PeekKind{0},
1222 WriteString{" , "},
1223 PeekKind{0},
1224 WriteString{` "" `},
1225 ReadValue{0, E(io.ErrUnexpectedEOF).withPos("[ ] [ null , false , ", "")},
1226 ReadValue{'"', nil},
1227
1228 WriteString{" , 0"},
1229 PeekKind{'0'},
1230 ReadToken{'0', nil},
1231
1232 WriteString{" , {} , []"},
1233 PeekKind{'{'},
1234 ReadValue{'{', nil},
1235 ReadValue{'[', nil},
1236
1237 WriteString{"]"},
1238 ReadToken{']', nil},
1239 }
1240
1241 bb := struct{ *bytes.Buffer }{new(bytes.Buffer)}
1242 d := NewDecoder(bb)
1243 for i, op := range ops {
1244 switch op := op.(type) {
1245 case PeekKind:
1246 if got := d.PeekKind(); got != op.want {
1247 t.Fatalf("%d: Decoder.PeekKind() = %v, want %v", i, got, op.want)
1248 }
1249 case ReadToken:
1250 gotTok, gotErr := d.ReadToken()
1251 gotKind := gotTok.Kind()
1252 if gotKind != op.wantKind || !equalError(gotErr, op.wantErr) {
1253 t.Fatalf("%d: Decoder.ReadToken() = (%v, %v), want (%v, %v)", i, gotKind, gotErr, op.wantKind, op.wantErr)
1254 }
1255 case ReadValue:
1256 gotVal, gotErr := d.ReadValue()
1257 gotKind := gotVal.Kind()
1258 if gotKind != op.wantKind || !equalError(gotErr, op.wantErr) {
1259 t.Fatalf("%d: Decoder.ReadValue() = (%v, %v), want (%v, %v)", i, gotKind, gotErr, op.wantKind, op.wantErr)
1260 }
1261 case WriteString:
1262 bb.WriteString(op.in)
1263 default:
1264 panic(fmt.Sprintf("unknown operation: %T", op))
1265 }
1266 }
1267 }
1268
View as plain text