k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/internal/third_party/go-json-experiment/json/decode_test.go (about) 1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package json 6 7 import ( 8 "bytes" 9 "errors" 10 "fmt" 11 "io" 12 "math" 13 "net" 14 "path" 15 "reflect" 16 "strings" 17 "testing" 18 "testing/iotest" 19 ) 20 21 // equalTokens reports whether to sequences of tokens formats the same way. 22 func equalTokens(xs, ys []Token) bool { 23 if len(xs) != len(ys) { 24 return false 25 } 26 for i := range xs { 27 if !(reflect.DeepEqual(xs[i], ys[i]) || xs[i].String() == ys[i].String()) { 28 return false 29 } 30 } 31 return true 32 } 33 34 // TestDecoder tests whether we can parse JSON with either tokens or raw values. 35 func TestDecoder(t *testing.T) { 36 for _, td := range coderTestdata { 37 for _, typeName := range []string{"Token", "Value", "TokenDelims"} { 38 t.Run(path.Join(td.name.name, typeName), func(t *testing.T) { 39 testDecoder(t, td.name.where, typeName, td) 40 }) 41 } 42 } 43 } 44 func testDecoder(t *testing.T, where pc, typeName string, td coderTestdataEntry) { 45 dec := NewDecoder(bytes.NewBufferString(td.in)) 46 switch typeName { 47 case "Token": 48 var tokens []Token 49 var pointers []string 50 for { 51 tok, err := dec.ReadToken() 52 if err != nil { 53 if err == io.EOF { 54 break 55 } 56 t.Fatalf("%s: Decoder.ReadToken error: %v", where, err) 57 } 58 tokens = append(tokens, tok.Clone()) 59 if td.pointers != nil { 60 pointers = append(pointers, dec.StackPointer()) 61 } 62 } 63 if !equalTokens(tokens, td.tokens) { 64 t.Fatalf("%s: tokens mismatch:\ngot %v\nwant %v", where, tokens, td.tokens) 65 } 66 if !reflect.DeepEqual(pointers, td.pointers) { 67 t.Fatalf("%s: pointers mismatch:\ngot %q\nwant %q", where, pointers, td.pointers) 68 } 69 case "Value": 70 val, err := dec.ReadValue() 71 if err != nil { 72 t.Fatalf("%s: Decoder.ReadValue error: %v", where, err) 73 } 74 got := string(val) 75 want := strings.TrimSpace(td.in) 76 if got != want { 77 t.Fatalf("%s: Decoder.ReadValue = %s, want %s", where, got, want) 78 } 79 case "TokenDelims": 80 // Use ReadToken for object/array delimiters, ReadValue otherwise. 81 var tokens []Token 82 loop: 83 for { 84 switch dec.PeekKind() { 85 case '{', '}', '[', ']': 86 tok, err := dec.ReadToken() 87 if err != nil { 88 if err == io.EOF { 89 break loop 90 } 91 t.Fatalf("%s: Decoder.ReadToken error: %v", where, err) 92 } 93 tokens = append(tokens, tok.Clone()) 94 default: 95 val, err := dec.ReadValue() 96 if err != nil { 97 if err == io.EOF { 98 break loop 99 } 100 t.Fatalf("%s: Decoder.ReadValue error: %v", where, err) 101 } 102 tokens = append(tokens, rawToken(string(val))) 103 } 104 } 105 if !equalTokens(tokens, td.tokens) { 106 t.Fatalf("%s: tokens mismatch:\ngot %v\nwant %v", where, tokens, td.tokens) 107 } 108 } 109 } 110 111 // TestFaultyDecoder tests that temporary I/O errors are not fatal. 112 func TestFaultyDecoder(t *testing.T) { 113 for _, td := range coderTestdata { 114 for _, typeName := range []string{"Token", "Value"} { 115 t.Run(path.Join(td.name.name, typeName), func(t *testing.T) { 116 testFaultyDecoder(t, td.name.where, typeName, td) 117 }) 118 } 119 } 120 } 121 func testFaultyDecoder(t *testing.T, where pc, typeName string, td coderTestdataEntry) { 122 b := &FaultyBuffer{ 123 B: []byte(td.in), 124 MaxBytes: 1, 125 MayError: io.ErrNoProgress, 126 } 127 128 // Read all the tokens. 129 // If the underlying io.Reader is faulty, then Read may return 130 // an error without changing the internal state machine. 131 // In other words, I/O errors occur before syntactic errors. 132 dec := NewDecoder(b) 133 switch typeName { 134 case "Token": 135 var tokens []Token 136 for { 137 tok, err := dec.ReadToken() 138 if err != nil { 139 if err == io.EOF { 140 break 141 } 142 if !errors.Is(err, io.ErrNoProgress) { 143 t.Fatalf("%s: %d: Decoder.ReadToken error: %v", where, len(tokens), err) 144 } 145 continue 146 } 147 tokens = append(tokens, tok.Clone()) 148 } 149 if !equalTokens(tokens, td.tokens) { 150 t.Fatalf("%s: tokens mismatch:\ngot %s\nwant %s", where, tokens, td.tokens) 151 } 152 case "Value": 153 for { 154 val, err := dec.ReadValue() 155 if err != nil { 156 if err == io.EOF { 157 break 158 } 159 if !errors.Is(err, io.ErrNoProgress) { 160 t.Fatalf("%s: Decoder.ReadValue error: %v", where, err) 161 } 162 continue 163 } 164 got := string(val) 165 want := strings.TrimSpace(td.in) 166 if got != want { 167 t.Fatalf("%s: Decoder.ReadValue = %s, want %s", where, got, want) 168 } 169 } 170 } 171 } 172 173 type decoderMethodCall struct { 174 wantKind Kind 175 wantOut tokOrVal 176 wantErr error 177 wantPointer string 178 } 179 180 var decoderErrorTestdata = []struct { 181 name testName 182 opts DecodeOptions 183 in string 184 calls []decoderMethodCall 185 wantOffset int 186 }{{ 187 name: name("InvalidStart"), 188 in: ` #`, 189 calls: []decoderMethodCall{ 190 {'#', zeroToken, newInvalidCharacterError([]byte("#"), "at start of token").withOffset(int64(len(" "))), ""}, 191 {'#', zeroValue, newInvalidCharacterError([]byte("#"), "at start of value").withOffset(int64(len(" "))), ""}, 192 }, 193 }, { 194 name: name("StreamN0"), 195 in: ` `, 196 calls: []decoderMethodCall{ 197 {0, zeroToken, io.EOF, ""}, 198 {0, zeroValue, io.EOF, ""}, 199 }, 200 }, { 201 name: name("StreamN1"), 202 in: ` null `, 203 calls: []decoderMethodCall{ 204 {'n', Null, nil, ""}, 205 {0, zeroToken, io.EOF, ""}, 206 {0, zeroValue, io.EOF, ""}, 207 }, 208 wantOffset: len(` null`), 209 }, { 210 name: name("StreamN2"), 211 in: ` nullnull `, 212 calls: []decoderMethodCall{ 213 {'n', Null, nil, ""}, 214 {'n', Null, nil, ""}, 215 {0, zeroToken, io.EOF, ""}, 216 {0, zeroValue, io.EOF, ""}, 217 }, 218 wantOffset: len(` nullnull`), 219 }, { 220 name: name("StreamN2/ExtraComma"), // stream is whitespace delimited, not comma delimited 221 in: ` null , null `, 222 calls: []decoderMethodCall{ 223 {'n', Null, nil, ""}, 224 {0, zeroToken, newInvalidCharacterError([]byte(","), `before next token`).withOffset(int64(len(` null `))), ""}, 225 {0, zeroValue, newInvalidCharacterError([]byte(","), `before next token`).withOffset(int64(len(` null `))), ""}, 226 }, 227 wantOffset: len(` null`), 228 }, { 229 name: name("TruncatedNull"), 230 in: `nul`, 231 calls: []decoderMethodCall{ 232 {'n', zeroToken, io.ErrUnexpectedEOF, ""}, 233 {'n', zeroValue, io.ErrUnexpectedEOF, ""}, 234 }, 235 }, { 236 name: name("InvalidNull"), 237 in: `nulL`, 238 calls: []decoderMethodCall{ 239 {'n', zeroToken, newInvalidCharacterError([]byte("L"), `within literal null (expecting 'l')`).withOffset(int64(len(`nul`))), ""}, 240 {'n', zeroValue, newInvalidCharacterError([]byte("L"), `within literal null (expecting 'l')`).withOffset(int64(len(`nul`))), ""}, 241 }, 242 }, { 243 name: name("TruncatedFalse"), 244 in: `fals`, 245 calls: []decoderMethodCall{ 246 {'f', zeroToken, io.ErrUnexpectedEOF, ""}, 247 {'f', zeroValue, io.ErrUnexpectedEOF, ""}, 248 }, 249 }, { 250 name: name("InvalidFalse"), 251 in: `falsE`, 252 calls: []decoderMethodCall{ 253 {'f', zeroToken, newInvalidCharacterError([]byte("E"), `within literal false (expecting 'e')`).withOffset(int64(len(`fals`))), ""}, 254 {'f', zeroValue, newInvalidCharacterError([]byte("E"), `within literal false (expecting 'e')`).withOffset(int64(len(`fals`))), ""}, 255 }, 256 }, { 257 name: name("TruncatedTrue"), 258 in: `tru`, 259 calls: []decoderMethodCall{ 260 {'t', zeroToken, io.ErrUnexpectedEOF, ""}, 261 {'t', zeroValue, io.ErrUnexpectedEOF, ""}, 262 }, 263 }, { 264 name: name("InvalidTrue"), 265 in: `truE`, 266 calls: []decoderMethodCall{ 267 {'t', zeroToken, newInvalidCharacterError([]byte("E"), `within literal true (expecting 'e')`).withOffset(int64(len(`tru`))), ""}, 268 {'t', zeroValue, newInvalidCharacterError([]byte("E"), `within literal true (expecting 'e')`).withOffset(int64(len(`tru`))), ""}, 269 }, 270 }, { 271 name: name("TruncatedString"), 272 in: `"start`, 273 calls: []decoderMethodCall{ 274 {'"', zeroToken, io.ErrUnexpectedEOF, ""}, 275 {'"', zeroValue, io.ErrUnexpectedEOF, ""}, 276 }, 277 }, { 278 name: name("InvalidString"), 279 in: `"ok` + "\x00", 280 calls: []decoderMethodCall{ 281 {'"', zeroToken, newInvalidCharacterError([]byte("\x00"), `within string (expecting non-control character)`).withOffset(int64(len(`"ok`))), ""}, 282 {'"', zeroValue, newInvalidCharacterError([]byte("\x00"), `within string (expecting non-control character)`).withOffset(int64(len(`"ok`))), ""}, 283 }, 284 }, { 285 name: name("ValidString/AllowInvalidUTF8/Token"), 286 opts: DecodeOptions{AllowInvalidUTF8: true}, 287 in: "\"living\xde\xad\xbe\xef\"", 288 calls: []decoderMethodCall{ 289 {'"', rawToken("\"living\xde\xad\xbe\xef\""), nil, ""}, 290 }, 291 wantOffset: len("\"living\xde\xad\xbe\xef\""), 292 }, { 293 name: name("ValidString/AllowInvalidUTF8/Value"), 294 opts: DecodeOptions{AllowInvalidUTF8: true}, 295 in: "\"living\xde\xad\xbe\xef\"", 296 calls: []decoderMethodCall{ 297 {'"', RawValue("\"living\xde\xad\xbe\xef\""), nil, ""}, 298 }, 299 wantOffset: len("\"living\xde\xad\xbe\xef\""), 300 }, { 301 name: name("InvalidString/RejectInvalidUTF8"), 302 opts: DecodeOptions{AllowInvalidUTF8: false}, 303 in: "\"living\xde\xad\xbe\xef\"", 304 calls: []decoderMethodCall{ 305 {'"', zeroToken, (&SyntacticError{str: "invalid UTF-8 within string"}).withOffset(int64(len("\"living\xde\xad"))), ""}, 306 {'"', zeroValue, (&SyntacticError{str: "invalid UTF-8 within string"}).withOffset(int64(len("\"living\xde\xad"))), ""}, 307 }, 308 }, { 309 name: name("TruncatedNumber"), 310 in: `0.`, 311 calls: []decoderMethodCall{ 312 {'0', zeroToken, io.ErrUnexpectedEOF, ""}, 313 {'0', zeroValue, io.ErrUnexpectedEOF, ""}, 314 }, 315 }, { 316 name: name("InvalidNumber"), 317 in: `0.e`, 318 calls: []decoderMethodCall{ 319 {'0', zeroToken, newInvalidCharacterError([]byte("e"), "within number (expecting digit)").withOffset(int64(len(`0.`))), ""}, 320 {'0', zeroValue, newInvalidCharacterError([]byte("e"), "within number (expecting digit)").withOffset(int64(len(`0.`))), ""}, 321 }, 322 }, { 323 name: name("TruncatedObject/AfterStart"), 324 in: `{`, 325 calls: []decoderMethodCall{ 326 {'{', zeroValue, io.ErrUnexpectedEOF, ""}, 327 {'{', ObjectStart, nil, ""}, 328 {0, zeroToken, io.ErrUnexpectedEOF, ""}, 329 {0, zeroValue, io.ErrUnexpectedEOF, ""}, 330 }, 331 wantOffset: len(`{`), 332 }, { 333 name: name("TruncatedObject/AfterName"), 334 in: `{"0"`, 335 calls: []decoderMethodCall{ 336 {'{', zeroValue, io.ErrUnexpectedEOF, ""}, 337 {'{', ObjectStart, nil, ""}, 338 {'"', String("0"), nil, ""}, 339 {0, zeroToken, io.ErrUnexpectedEOF, ""}, 340 {0, zeroValue, io.ErrUnexpectedEOF, ""}, 341 }, 342 wantOffset: len(`{"0"`), 343 }, { 344 name: name("TruncatedObject/AfterColon"), 345 in: `{"0":`, 346 calls: []decoderMethodCall{ 347 {'{', zeroValue, io.ErrUnexpectedEOF, ""}, 348 {'{', ObjectStart, nil, ""}, 349 {'"', String("0"), nil, ""}, 350 {0, zeroToken, io.ErrUnexpectedEOF, ""}, 351 {0, zeroValue, io.ErrUnexpectedEOF, ""}, 352 }, 353 wantOffset: len(`{"0"`), 354 }, { 355 name: name("TruncatedObject/AfterValue"), 356 in: `{"0":0`, 357 calls: []decoderMethodCall{ 358 {'{', zeroValue, io.ErrUnexpectedEOF, ""}, 359 {'{', ObjectStart, nil, ""}, 360 {'"', String("0"), nil, ""}, 361 {'0', Uint(0), nil, ""}, 362 {0, zeroToken, io.ErrUnexpectedEOF, ""}, 363 {0, zeroValue, io.ErrUnexpectedEOF, ""}, 364 }, 365 wantOffset: len(`{"0":0`), 366 }, { 367 name: name("TruncatedObject/AfterComma"), 368 in: `{"0":0,`, 369 calls: []decoderMethodCall{ 370 {'{', zeroValue, io.ErrUnexpectedEOF, ""}, 371 {'{', ObjectStart, nil, ""}, 372 {'"', String("0"), nil, ""}, 373 {'0', Uint(0), nil, ""}, 374 {0, zeroToken, io.ErrUnexpectedEOF, ""}, 375 {0, zeroValue, io.ErrUnexpectedEOF, ""}, 376 }, 377 wantOffset: len(`{"0":0`), 378 }, { 379 name: name("InvalidObject/MissingColon"), 380 in: ` { "fizz" "buzz" } `, 381 calls: []decoderMethodCall{ 382 {'{', zeroValue, newInvalidCharacterError([]byte("\""), "after object name (expecting ':')").withOffset(int64(len(` { "fizz" `))), ""}, 383 {'{', ObjectStart, nil, ""}, 384 {'"', String("fizz"), nil, ""}, 385 {0, zeroToken, errMissingColon.withOffset(int64(len(` { "fizz" `))), ""}, 386 {0, zeroValue, errMissingColon.withOffset(int64(len(` { "fizz" `))), ""}, 387 }, 388 wantOffset: len(` { "fizz"`), 389 }, { 390 name: name("InvalidObject/MissingColon/GotComma"), 391 in: ` { "fizz" , "buzz" } `, 392 calls: []decoderMethodCall{ 393 {'{', zeroValue, newInvalidCharacterError([]byte(","), "after object name (expecting ':')").withOffset(int64(len(` { "fizz" `))), ""}, 394 {'{', ObjectStart, nil, ""}, 395 {'"', String("fizz"), nil, ""}, 396 {0, zeroToken, errMissingColon.withOffset(int64(len(` { "fizz" `))), ""}, 397 {0, zeroValue, errMissingColon.withOffset(int64(len(` { "fizz" `))), ""}, 398 }, 399 wantOffset: len(` { "fizz"`), 400 }, { 401 name: name("InvalidObject/MissingColon/GotHash"), 402 in: ` { "fizz" # "buzz" } `, 403 calls: []decoderMethodCall{ 404 {'{', zeroValue, newInvalidCharacterError([]byte("#"), "after object name (expecting ':')").withOffset(int64(len(` { "fizz" `))), ""}, 405 {'{', ObjectStart, nil, ""}, 406 {'"', String("fizz"), nil, ""}, 407 {0, zeroToken, errMissingColon.withOffset(int64(len(` { "fizz" `))), ""}, 408 {0, zeroValue, errMissingColon.withOffset(int64(len(` { "fizz" `))), ""}, 409 }, 410 wantOffset: len(` { "fizz"`), 411 }, { 412 name: name("InvalidObject/MissingComma"), 413 in: ` { "fizz" : "buzz" "gazz" } `, 414 calls: []decoderMethodCall{ 415 {'{', zeroValue, newInvalidCharacterError([]byte("\""), "after object value (expecting ',' or '}')").withOffset(int64(len(` { "fizz" : "buzz" `))), ""}, 416 {'{', ObjectStart, nil, ""}, 417 {'"', String("fizz"), nil, ""}, 418 {'"', String("buzz"), nil, ""}, 419 {0, zeroToken, errMissingComma.withOffset(int64(len(` { "fizz" : "buzz" `))), ""}, 420 {0, zeroValue, errMissingComma.withOffset(int64(len(` { "fizz" : "buzz" `))), ""}, 421 }, 422 wantOffset: len(` { "fizz" : "buzz"`), 423 }, { 424 name: name("InvalidObject/MissingComma/GotColon"), 425 in: ` { "fizz" : "buzz" : "gazz" } `, 426 calls: []decoderMethodCall{ 427 {'{', zeroValue, newInvalidCharacterError([]byte(":"), "after object value (expecting ',' or '}')").withOffset(int64(len(` { "fizz" : "buzz" `))), ""}, 428 {'{', ObjectStart, nil, ""}, 429 {'"', String("fizz"), nil, ""}, 430 {'"', String("buzz"), nil, ""}, 431 {0, zeroToken, errMissingComma.withOffset(int64(len(` { "fizz" : "buzz" `))), ""}, 432 {0, zeroValue, errMissingComma.withOffset(int64(len(` { "fizz" : "buzz" `))), ""}, 433 }, 434 wantOffset: len(` { "fizz" : "buzz"`), 435 }, { 436 name: name("InvalidObject/MissingComma/GotHash"), 437 in: ` { "fizz" : "buzz" # "gazz" } `, 438 calls: []decoderMethodCall{ 439 {'{', zeroValue, newInvalidCharacterError([]byte("#"), "after object value (expecting ',' or '}')").withOffset(int64(len(` { "fizz" : "buzz" `))), ""}, 440 {'{', ObjectStart, nil, ""}, 441 {'"', String("fizz"), nil, ""}, 442 {'"', String("buzz"), nil, ""}, 443 {0, zeroToken, errMissingComma.withOffset(int64(len(` { "fizz" : "buzz" `))), ""}, 444 {0, zeroValue, errMissingComma.withOffset(int64(len(` { "fizz" : "buzz" `))), ""}, 445 }, 446 wantOffset: len(` { "fizz" : "buzz"`), 447 }, { 448 name: name("InvalidObject/ExtraComma/AfterStart"), 449 in: ` { , } `, 450 calls: []decoderMethodCall{ 451 {'{', zeroValue, newInvalidCharacterError([]byte(","), `at start of string (expecting '"')`).withOffset(int64(len(` { `))), ""}, 452 {'{', ObjectStart, nil, ""}, 453 {0, zeroToken, newInvalidCharacterError([]byte(","), `before next token`).withOffset(int64(len(` { `))), ""}, 454 {0, zeroValue, newInvalidCharacterError([]byte(","), `before next token`).withOffset(int64(len(` { `))), ""}, 455 }, 456 wantOffset: len(` {`), 457 }, { 458 name: name("InvalidObject/ExtraComma/AfterValue"), 459 in: ` { "fizz" : "buzz" , } `, 460 calls: []decoderMethodCall{ 461 {'{', zeroValue, newInvalidCharacterError([]byte("}"), `at start of string (expecting '"')`).withOffset(int64(len(` { "fizz" : "buzz" , `))), ""}, 462 {'{', ObjectStart, nil, ""}, 463 {'"', String("fizz"), nil, ""}, 464 {'"', String("buzz"), nil, ""}, 465 {0, zeroToken, newInvalidCharacterError([]byte(","), `before next token`).withOffset(int64(len(` { "fizz" : "buzz" `))), ""}, 466 {0, zeroValue, newInvalidCharacterError([]byte(","), `before next token`).withOffset(int64(len(` { "fizz" : "buzz" `))), ""}, 467 }, 468 wantOffset: len(` { "fizz" : "buzz"`), 469 }, { 470 name: name("InvalidObject/InvalidName/GotNull"), 471 in: ` { null : null } `, 472 calls: []decoderMethodCall{ 473 {'{', zeroValue, newInvalidCharacterError([]byte("n"), "at start of string (expecting '\"')").withOffset(int64(len(` { `))), ""}, 474 {'{', ObjectStart, nil, ""}, 475 {'n', zeroToken, errMissingName.withOffset(int64(len(` { `))), ""}, 476 {'n', zeroValue, errMissingName.withOffset(int64(len(` { `))), ""}, 477 }, 478 wantOffset: len(` {`), 479 }, { 480 name: name("InvalidObject/InvalidName/GotFalse"), 481 in: ` { false : false } `, 482 calls: []decoderMethodCall{ 483 {'{', zeroValue, newInvalidCharacterError([]byte("f"), "at start of string (expecting '\"')").withOffset(int64(len(` { `))), ""}, 484 {'{', ObjectStart, nil, ""}, 485 {'f', zeroToken, errMissingName.withOffset(int64(len(` { `))), ""}, 486 {'f', zeroValue, errMissingName.withOffset(int64(len(` { `))), ""}, 487 }, 488 wantOffset: len(` {`), 489 }, { 490 name: name("InvalidObject/InvalidName/GotTrue"), 491 in: ` { true : true } `, 492 calls: []decoderMethodCall{ 493 {'{', zeroValue, newInvalidCharacterError([]byte("t"), "at start of string (expecting '\"')").withOffset(int64(len(` { `))), ""}, 494 {'{', ObjectStart, nil, ""}, 495 {'t', zeroToken, errMissingName.withOffset(int64(len(` { `))), ""}, 496 {'t', zeroValue, errMissingName.withOffset(int64(len(` { `))), ""}, 497 }, 498 wantOffset: len(` {`), 499 }, { 500 name: name("InvalidObject/InvalidName/GotNumber"), 501 in: ` { 0 : 0 } `, 502 calls: []decoderMethodCall{ 503 {'{', zeroValue, newInvalidCharacterError([]byte("0"), "at start of string (expecting '\"')").withOffset(int64(len(` { `))), ""}, 504 {'{', ObjectStart, nil, ""}, 505 {'0', zeroToken, errMissingName.withOffset(int64(len(` { `))), ""}, 506 {'0', zeroValue, errMissingName.withOffset(int64(len(` { `))), ""}, 507 }, 508 wantOffset: len(` {`), 509 }, { 510 name: name("InvalidObject/InvalidName/GotObject"), 511 in: ` { {} : {} } `, 512 calls: []decoderMethodCall{ 513 {'{', zeroValue, newInvalidCharacterError([]byte("{"), "at start of string (expecting '\"')").withOffset(int64(len(` { `))), ""}, 514 {'{', ObjectStart, nil, ""}, 515 {'{', zeroToken, errMissingName.withOffset(int64(len(` { `))), ""}, 516 {'{', zeroValue, errMissingName.withOffset(int64(len(` { `))), ""}, 517 }, 518 wantOffset: len(` {`), 519 }, { 520 name: name("InvalidObject/InvalidName/GotArray"), 521 in: ` { [] : [] } `, 522 calls: []decoderMethodCall{ 523 {'{', zeroValue, newInvalidCharacterError([]byte("["), "at start of string (expecting '\"')").withOffset(int64(len(` { `))), ""}, 524 {'{', ObjectStart, nil, ""}, 525 {'[', zeroToken, errMissingName.withOffset(int64(len(` { `))), ""}, 526 {'[', zeroValue, errMissingName.withOffset(int64(len(` { `))), ""}, 527 }, 528 wantOffset: len(` {`), 529 }, { 530 name: name("InvalidObject/MismatchingDelim"), 531 in: ` { ] `, 532 calls: []decoderMethodCall{ 533 {'{', zeroValue, newInvalidCharacterError([]byte("]"), "at start of string (expecting '\"')").withOffset(int64(len(` { `))), ""}, 534 {'{', ObjectStart, nil, ""}, 535 {']', zeroToken, errMismatchDelim.withOffset(int64(len(` { `))), ""}, 536 {']', zeroValue, newInvalidCharacterError([]byte("]"), "at start of value").withOffset(int64(len(` { `))), ""}, 537 }, 538 wantOffset: len(` {`), 539 }, { 540 name: name("ValidObject/InvalidValue"), 541 in: ` { } `, 542 calls: []decoderMethodCall{ 543 {'{', ObjectStart, nil, ""}, 544 {'}', zeroValue, newInvalidCharacterError([]byte("}"), "at start of value").withOffset(int64(len(" { "))), ""}, 545 }, 546 wantOffset: len(` {`), 547 }, { 548 name: name("ValidObject/UniqueNames"), 549 in: `{"0":0,"1":1} `, 550 calls: []decoderMethodCall{ 551 {'{', ObjectStart, nil, ""}, 552 {'"', String("0"), nil, ""}, 553 {'0', Uint(0), nil, ""}, 554 {'"', String("1"), nil, ""}, 555 {'0', Uint(1), nil, ""}, 556 {'}', ObjectEnd, nil, ""}, 557 }, 558 wantOffset: len(`{"0":0,"1":1}`), 559 }, { 560 name: name("ValidObject/DuplicateNames"), 561 opts: DecodeOptions{AllowDuplicateNames: true}, 562 in: `{"0":0,"0":0} `, 563 calls: []decoderMethodCall{ 564 {'{', ObjectStart, nil, ""}, 565 {'"', String("0"), nil, ""}, 566 {'0', Uint(0), nil, ""}, 567 {'"', String("0"), nil, ""}, 568 {'0', Uint(0), nil, ""}, 569 {'}', ObjectEnd, nil, ""}, 570 }, 571 wantOffset: len(`{"0":0,"0":0}`), 572 }, { 573 name: name("InvalidObject/DuplicateNames"), 574 in: `{"0":{},"1":{},"0":{}} `, 575 calls: []decoderMethodCall{ 576 {'{', zeroValue, (&SyntacticError{str: `duplicate name "0" in object`}).withOffset(int64(len(`{"0":{},"1":{},`))), ""}, 577 {'{', ObjectStart, nil, ""}, 578 {'"', String("0"), nil, ""}, 579 {'{', ObjectStart, nil, ""}, 580 {'}', ObjectEnd, nil, ""}, 581 {'"', String("1"), nil, ""}, 582 {'{', ObjectStart, nil, ""}, 583 {'}', ObjectEnd, nil, ""}, 584 {'"', zeroToken, (&SyntacticError{str: `duplicate name "0" in object`}).withOffset(int64(len(`{"0":{},"1":{},`))), "/1"}, 585 {'"', zeroValue, (&SyntacticError{str: `duplicate name "0" in object`}).withOffset(int64(len(`{"0":{},"1":{},`))), "/1"}, 586 }, 587 wantOffset: len(`{"0":{},"1":{}`), 588 }, { 589 name: name("TruncatedArray/AfterStart"), 590 in: `[`, 591 calls: []decoderMethodCall{ 592 {'[', zeroValue, io.ErrUnexpectedEOF, ""}, 593 {'[', ArrayStart, nil, ""}, 594 {0, zeroToken, io.ErrUnexpectedEOF, ""}, 595 {0, zeroValue, io.ErrUnexpectedEOF, ""}, 596 }, 597 wantOffset: len(`[`), 598 }, { 599 name: name("TruncatedArray/AfterValue"), 600 in: `[0`, 601 calls: []decoderMethodCall{ 602 {'[', zeroValue, io.ErrUnexpectedEOF, ""}, 603 {'[', ArrayStart, nil, ""}, 604 {'0', Uint(0), nil, ""}, 605 {0, zeroToken, io.ErrUnexpectedEOF, ""}, 606 {0, zeroValue, io.ErrUnexpectedEOF, ""}, 607 }, 608 wantOffset: len(`[0`), 609 }, { 610 name: name("TruncatedArray/AfterComma"), 611 in: `[0,`, 612 calls: []decoderMethodCall{ 613 {'[', zeroValue, io.ErrUnexpectedEOF, ""}, 614 {'[', ArrayStart, nil, ""}, 615 {'0', Uint(0), nil, ""}, 616 {0, zeroToken, io.ErrUnexpectedEOF, ""}, 617 {0, zeroValue, io.ErrUnexpectedEOF, ""}, 618 }, 619 wantOffset: len(`[0`), 620 }, { 621 name: name("InvalidArray/MissingComma"), 622 in: ` [ "fizz" "buzz" ] `, 623 calls: []decoderMethodCall{ 624 {'[', zeroValue, newInvalidCharacterError([]byte("\""), "after array value (expecting ',' or ']')").withOffset(int64(len(` [ "fizz" `))), ""}, 625 {'[', ArrayStart, nil, ""}, 626 {'"', String("fizz"), nil, ""}, 627 {0, zeroToken, errMissingComma.withOffset(int64(len(` [ "fizz" `))), ""}, 628 {0, zeroValue, errMissingComma.withOffset(int64(len(` [ "fizz" `))), ""}, 629 }, 630 wantOffset: len(` [ "fizz"`), 631 }, { 632 name: name("InvalidArray/MismatchingDelim"), 633 in: ` [ } `, 634 calls: []decoderMethodCall{ 635 {'[', zeroValue, newInvalidCharacterError([]byte("}"), "at start of value").withOffset(int64(len(` [ `))), ""}, 636 {'[', ArrayStart, nil, ""}, 637 {'}', zeroToken, errMismatchDelim.withOffset(int64(len(` { `))), ""}, 638 {'}', zeroValue, newInvalidCharacterError([]byte("}"), "at start of value").withOffset(int64(len(` [ `))), ""}, 639 }, 640 wantOffset: len(` [`), 641 }, { 642 name: name("ValidArray/InvalidValue"), 643 in: ` [ ] `, 644 calls: []decoderMethodCall{ 645 {'[', ArrayStart, nil, ""}, 646 {']', zeroValue, newInvalidCharacterError([]byte("]"), "at start of value").withOffset(int64(len(" [ "))), ""}, 647 }, 648 wantOffset: len(` [`), 649 }} 650 651 // TestDecoderErrors test that Decoder errors occur when we expect and 652 // leaves the Decoder in a consistent state. 653 func TestDecoderErrors(t *testing.T) { 654 for _, td := range decoderErrorTestdata { 655 t.Run(path.Join(td.name.name), func(t *testing.T) { 656 testDecoderErrors(t, td.name.where, td.opts, td.in, td.calls, td.wantOffset) 657 }) 658 } 659 } 660 func testDecoderErrors(t *testing.T, where pc, opts DecodeOptions, in string, calls []decoderMethodCall, wantOffset int) { 661 src := bytes.NewBufferString(in) 662 dec := opts.NewDecoder(src) 663 for i, call := range calls { 664 gotKind := dec.PeekKind() 665 if gotKind != call.wantKind { 666 t.Fatalf("%s: %d: Decoder.PeekKind = %v, want %v", where, i, gotKind, call.wantKind) 667 } 668 669 var gotErr error 670 switch wantOut := call.wantOut.(type) { 671 case Token: 672 var gotOut Token 673 gotOut, gotErr = dec.ReadToken() 674 if gotOut.String() != wantOut.String() { 675 t.Fatalf("%s: %d: Decoder.ReadToken = %v, want %v", where, i, gotOut, wantOut) 676 } 677 case RawValue: 678 var gotOut RawValue 679 gotOut, gotErr = dec.ReadValue() 680 if string(gotOut) != string(wantOut) { 681 t.Fatalf("%s: %d: Decoder.ReadValue = %s, want %s", where, i, gotOut, wantOut) 682 } 683 } 684 if !reflect.DeepEqual(gotErr, call.wantErr) { 685 t.Fatalf("%s: %d: error mismatch: got %#v, want %#v", where, i, gotErr, call.wantErr) 686 } 687 if call.wantPointer != "" { 688 gotPointer := dec.StackPointer() 689 if gotPointer != call.wantPointer { 690 t.Fatalf("%s: %d: Decoder.StackPointer = %s, want %s", where, i, gotPointer, call.wantPointer) 691 } 692 } 693 } 694 gotOffset := int(dec.InputOffset()) 695 if gotOffset != wantOffset { 696 t.Fatalf("%s: Decoder.InputOffset = %v, want %v", where, gotOffset, wantOffset) 697 } 698 gotUnread := string(dec.unreadBuffer()) // should be a prefix of wantUnread 699 wantUnread := in[wantOffset:] 700 if !strings.HasPrefix(wantUnread, gotUnread) { 701 t.Fatalf("%s: Decoder.UnreadBuffer = %v, want %v", where, gotUnread, wantUnread) 702 } 703 } 704 705 var resumableDecoderTestdata = []string{ 706 `0`, 707 `123456789`, 708 `0.0`, 709 `0.123456789`, 710 `0e0`, 711 `0e+0`, 712 `0e123456789`, 713 `0e+123456789`, 714 `123456789.123456789e+123456789`, 715 `-0`, 716 `-123456789`, 717 `-0.0`, 718 `-0.123456789`, 719 `-0e0`, 720 `-0e-0`, 721 `-0e123456789`, 722 `-0e-123456789`, 723 `-123456789.123456789e-123456789`, 724 725 `""`, 726 `"a"`, 727 `"ab"`, 728 `"abc"`, 729 `"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"`, 730 `"\"\\\/\b\f\n\r\t"`, 731 `"\u0022\u005c\u002f\u0008\u000c\u000a\u000d\u0009"`, 732 `"\ud800\udead"`, 733 "\"\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\U0001f602\"", 734 `"\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\ud83d\ude02"`, 735 } 736 737 // TestBufferDecoder tests that we detect misuses of bytes.Buffer with Decoder. 738 func TestBufferDecoder(t *testing.T) { 739 bb := bytes.NewBufferString("[null, false, true]") 740 dec := NewDecoder(bb) 741 var err error 742 for { 743 if _, err = dec.ReadToken(); err != nil { 744 break 745 } 746 bb.WriteByte(' ') // not allowed to write to the buffer while reading 747 } 748 want := &ioError{action: "read", err: errBufferWriteAfterNext} 749 if !reflect.DeepEqual(err, want) { 750 t.Fatalf("error mismatch: got %v, want %v", err, want) 751 } 752 } 753 754 // TestResumableDecoder tests that resume logic for parsing a 755 // JSON string and number properly works across every possible split point. 756 func TestResumableDecoder(t *testing.T) { 757 for _, want := range resumableDecoderTestdata { 758 t.Run("", func(t *testing.T) { 759 dec := NewDecoder(iotest.OneByteReader(strings.NewReader(want))) 760 got, err := dec.ReadValue() 761 if err != nil { 762 t.Fatalf("Decoder.ReadValue error: %v", err) 763 } 764 if string(got) != want { 765 t.Fatalf("Decoder.ReadValue = %s, want %s", got, want) 766 } 767 }) 768 } 769 } 770 771 // TestBlockingDecoder verifies that JSON values except numbers can be 772 // synchronously sent and received on a blocking pipe without a deadlock. 773 // Numbers are the exception since termination cannot be determined until 774 // either the pipe ends or a non-numeric character is encountered. 775 func TestBlockingDecoder(t *testing.T) { 776 values := []string{"null", "false", "true", `""`, `{}`, `[]`} 777 778 r, w := net.Pipe() 779 defer r.Close() 780 defer w.Close() 781 782 enc := NewEncoder(w) 783 enc.options.omitTopLevelNewline = true 784 dec := NewDecoder(r) 785 786 errCh := make(chan error) 787 788 // Test synchronous ReadToken calls. 789 for _, want := range values { 790 go func() { 791 errCh <- enc.WriteValue(RawValue(want)) 792 }() 793 794 tok, err := dec.ReadToken() 795 if err != nil { 796 t.Fatalf("Decoder.ReadToken error: %v", err) 797 } 798 got := tok.String() 799 switch tok.Kind() { 800 case '"': 801 got = `"` + got + `"` 802 case '{', '[': 803 tok, err := dec.ReadToken() 804 if err != nil { 805 t.Fatalf("Decoder.ReadToken error: %v", err) 806 } 807 got += tok.String() 808 } 809 if got != want { 810 t.Fatalf("ReadTokens = %s, want %s", got, want) 811 } 812 813 if err := <-errCh; err != nil { 814 t.Fatalf("Encoder.WriteValue error: %v", err) 815 } 816 } 817 818 // Test synchronous ReadValue calls. 819 for _, want := range values { 820 go func() { 821 errCh <- enc.WriteValue(RawValue(want)) 822 }() 823 824 got, err := dec.ReadValue() 825 if err != nil { 826 t.Fatalf("Decoder.ReadValue error: %v", err) 827 } 828 if string(got) != want { 829 t.Fatalf("ReadValue = %s, want %s", got, want) 830 } 831 832 if err := <-errCh; err != nil { 833 t.Fatalf("Encoder.WriteValue error: %v", err) 834 } 835 } 836 } 837 838 func TestPeekableDecoder(t *testing.T) { 839 type operation any // PeekKind | ReadToken | ReadValue | BufferWrite 840 type PeekKind struct { 841 want Kind 842 } 843 type ReadToken struct { 844 wantKind Kind 845 wantErr error 846 } 847 type ReadValue struct { 848 wantKind Kind 849 wantErr error 850 } 851 type WriteString struct { 852 in string 853 } 854 ops := []operation{ 855 PeekKind{0}, 856 WriteString{"[ "}, 857 ReadToken{0, io.EOF}, // previous error from PeekKind is cached once 858 ReadToken{'[', nil}, 859 860 PeekKind{0}, 861 WriteString{"] "}, 862 ReadValue{0, io.ErrUnexpectedEOF}, // previous error from PeekKind is cached once 863 ReadValue{0, newInvalidCharacterError([]byte("]"), "at start of value").withOffset(2)}, 864 ReadToken{']', nil}, 865 866 WriteString{"[ "}, 867 ReadToken{'[', nil}, 868 869 WriteString{" null "}, 870 PeekKind{'n'}, 871 PeekKind{'n'}, 872 ReadToken{'n', nil}, 873 874 WriteString{", "}, 875 PeekKind{0}, 876 WriteString{"fal"}, 877 PeekKind{'f'}, 878 ReadValue{0, io.ErrUnexpectedEOF}, 879 WriteString{"se "}, 880 ReadValue{'f', nil}, 881 882 PeekKind{0}, 883 WriteString{" , "}, 884 PeekKind{0}, 885 WriteString{` "" `}, 886 ReadValue{0, io.ErrUnexpectedEOF}, // previous error from PeekKind is cached once 887 ReadValue{'"', nil}, 888 889 WriteString{" , 0"}, 890 PeekKind{'0'}, 891 ReadToken{'0', nil}, 892 893 WriteString{" , {} , []"}, 894 PeekKind{'{'}, 895 ReadValue{'{', nil}, 896 ReadValue{'[', nil}, 897 898 WriteString{"]"}, 899 ReadToken{']', nil}, 900 } 901 902 bb := struct{ *bytes.Buffer }{new(bytes.Buffer)} 903 d := NewDecoder(bb) 904 for i, op := range ops { 905 switch op := op.(type) { 906 case PeekKind: 907 if got := d.PeekKind(); got != op.want { 908 t.Fatalf("%d: Decoder.PeekKind() = %v, want %v", i, got, op.want) 909 } 910 case ReadToken: 911 gotTok, gotErr := d.ReadToken() 912 gotKind := gotTok.Kind() 913 if gotKind != op.wantKind || !reflect.DeepEqual(gotErr, op.wantErr) { 914 t.Fatalf("%d: Decoder.ReadToken() = (%v, %v), want (%v, %v)", i, gotKind, gotErr, op.wantKind, op.wantErr) 915 } 916 case ReadValue: 917 gotVal, gotErr := d.ReadValue() 918 gotKind := gotVal.Kind() 919 if gotKind != op.wantKind || !reflect.DeepEqual(gotErr, op.wantErr) { 920 t.Fatalf("%d: Decoder.ReadValue() = (%v, %v), want (%v, %v)", i, gotKind, gotErr, op.wantKind, op.wantErr) 921 } 922 case WriteString: 923 bb.WriteString(op.in) 924 default: 925 panic(fmt.Sprintf("unknown operation: %T", op)) 926 } 927 } 928 } 929 930 func TestConsumeWhitespace(t *testing.T) { 931 tests := []struct { 932 in string 933 want int 934 }{ 935 {"", 0}, 936 {"a", 0}, 937 {" a", 1}, 938 {" a ", 1}, 939 {" \n\r\ta", 4}, 940 {" \n\r\t \n\r\t \n\r\t \n\r\t", 16}, 941 {"\u00a0", 0}, // non-breaking space is not JSON whitespace 942 } 943 944 for _, tt := range tests { 945 t.Run("", func(t *testing.T) { 946 if got := consumeWhitespace([]byte(tt.in)); got != tt.want { 947 t.Errorf("consumeWhitespace(%q) = %v, want %v", tt.in, got, tt.want) 948 } 949 }) 950 } 951 } 952 953 func TestConsumeLiteral(t *testing.T) { 954 tests := []struct { 955 literal string 956 in string 957 want int 958 wantErr error 959 }{ 960 {"null", "", 0, io.ErrUnexpectedEOF}, 961 {"null", "n", 1, io.ErrUnexpectedEOF}, 962 {"null", "nu", 2, io.ErrUnexpectedEOF}, 963 {"null", "nul", 3, io.ErrUnexpectedEOF}, 964 {"null", "null", 4, nil}, 965 {"null", "nullx", 4, nil}, 966 {"null", "x", 0, newInvalidCharacterError([]byte("x"), "within literal null (expecting 'n')")}, 967 {"null", "nuxx", 2, newInvalidCharacterError([]byte("x"), "within literal null (expecting 'l')")}, 968 969 {"false", "", 0, io.ErrUnexpectedEOF}, 970 {"false", "f", 1, io.ErrUnexpectedEOF}, 971 {"false", "fa", 2, io.ErrUnexpectedEOF}, 972 {"false", "fal", 3, io.ErrUnexpectedEOF}, 973 {"false", "fals", 4, io.ErrUnexpectedEOF}, 974 {"false", "false", 5, nil}, 975 {"false", "falsex", 5, nil}, 976 {"false", "x", 0, newInvalidCharacterError([]byte("x"), "within literal false (expecting 'f')")}, 977 {"false", "falsx", 4, newInvalidCharacterError([]byte("x"), "within literal false (expecting 'e')")}, 978 979 {"true", "", 0, io.ErrUnexpectedEOF}, 980 {"true", "t", 1, io.ErrUnexpectedEOF}, 981 {"true", "tr", 2, io.ErrUnexpectedEOF}, 982 {"true", "tru", 3, io.ErrUnexpectedEOF}, 983 {"true", "true", 4, nil}, 984 {"true", "truex", 4, nil}, 985 {"true", "x", 0, newInvalidCharacterError([]byte("x"), "within literal true (expecting 't')")}, 986 {"true", "trux", 3, newInvalidCharacterError([]byte("x"), "within literal true (expecting 'e')")}, 987 } 988 989 for _, tt := range tests { 990 t.Run("", func(t *testing.T) { 991 var got int 992 switch tt.literal { 993 case "null": 994 got = consumeNull([]byte(tt.in)) 995 case "false": 996 got = consumeFalse([]byte(tt.in)) 997 case "true": 998 got = consumeTrue([]byte(tt.in)) 999 default: 1000 t.Errorf("invalid literal: %v", tt.literal) 1001 } 1002 switch { 1003 case tt.wantErr == nil && got != tt.want: 1004 t.Errorf("consume%v(%q) = %v, want %v", strings.Title(tt.literal), tt.in, got, tt.want) 1005 case tt.wantErr != nil && got != 0: 1006 t.Errorf("consume%v(%q) = %v, want %v", strings.Title(tt.literal), tt.in, got, 0) 1007 } 1008 1009 got, gotErr := consumeLiteral([]byte(tt.in), tt.literal) 1010 if got != tt.want || !reflect.DeepEqual(gotErr, tt.wantErr) { 1011 t.Errorf("consumeLiteral(%q, %q) = (%v, %v), want (%v, %v)", tt.in, tt.literal, got, gotErr, tt.want, tt.wantErr) 1012 } 1013 }) 1014 } 1015 } 1016 1017 func TestConsumeString(t *testing.T) { 1018 tests := []struct { 1019 in string 1020 simple bool 1021 want int 1022 wantFlags valueFlags 1023 wantStr string 1024 wantErr error 1025 wantErrUTF8 error // error if validateUTF8 is specified 1026 }{ 1027 {``, false, 0, 0, "", io.ErrUnexpectedEOF, nil}, 1028 {`"`, false, 1, 0, "", io.ErrUnexpectedEOF, nil}, 1029 {`""`, true, 2, 0, "", nil, nil}, 1030 {`""x`, true, 2, 0, "", nil, nil}, 1031 {` ""x`, false, 0, 0, "", newInvalidCharacterError([]byte(" "), "at start of string (expecting '\"')"), nil}, 1032 {`"hello`, false, 6, 0, "hello", io.ErrUnexpectedEOF, nil}, 1033 {`"hello"`, true, 7, 0, "hello", nil, nil}, 1034 {"\"\x00\"", false, 1, stringNonVerbatim | stringNonCanonical, "", newInvalidCharacterError([]byte("\x00"), "within string (expecting non-control character)"), nil}, 1035 {`"\u0000"`, false, 8, stringNonVerbatim, "\x00", nil, nil}, 1036 {"\"\x1f\"", false, 1, stringNonVerbatim | stringNonCanonical, "", newInvalidCharacterError([]byte("\x1f"), "within string (expecting non-control character)"), nil}, 1037 {`"\u001f"`, false, 8, stringNonVerbatim, "\x1f", nil, nil}, 1038 {`"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"`, true, 54, 0, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", nil, nil}, 1039 {"\" !#$%&'()*+,-./0123456789:;<=>?@[]^_`{|}~\x7f\"", true, 44, 0, " !#$%&'()*+,-./0123456789:;<=>?@[]^_`{|}~\x7f", nil, nil}, 1040 {"\"x\x80\"", false, 4, stringNonVerbatim | stringNonCanonical, "x\ufffd", nil, &SyntacticError{str: "invalid UTF-8 within string"}}, 1041 {"\"x\xff\"", false, 4, stringNonVerbatim | stringNonCanonical, "x\ufffd", nil, &SyntacticError{str: "invalid UTF-8 within string"}}, 1042 {"\"x\xc0", false, 3, stringNonVerbatim | stringNonCanonical, "x\ufffd", io.ErrUnexpectedEOF, &SyntacticError{str: "invalid UTF-8 within string"}}, 1043 {"\"x\xc0\x80\"", false, 5, stringNonVerbatim | stringNonCanonical, "x\ufffd\ufffd", nil, &SyntacticError{str: "invalid UTF-8 within string"}}, 1044 {"\"x\xe0", false, 2, 0, "x", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF}, 1045 {"\"x\xe0\x80", false, 4, stringNonVerbatim | stringNonCanonical, "x\ufffd\ufffd", io.ErrUnexpectedEOF, &SyntacticError{str: "invalid UTF-8 within string"}}, 1046 {"\"x\xe0\x80\x80\"", false, 6, stringNonVerbatim | stringNonCanonical, "x\ufffd\ufffd\ufffd", nil, &SyntacticError{str: "invalid UTF-8 within string"}}, 1047 {"\"x\xf0", false, 2, 0, "x", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF}, 1048 {"\"x\xf0\x80", false, 4, stringNonVerbatim | stringNonCanonical, "x\ufffd\ufffd", io.ErrUnexpectedEOF, &SyntacticError{str: "invalid UTF-8 within string"}}, 1049 {"\"x\xf0\x80\x80", false, 5, stringNonVerbatim | stringNonCanonical, "x\ufffd\ufffd\ufffd", io.ErrUnexpectedEOF, &SyntacticError{str: "invalid UTF-8 within string"}}, 1050 {"\"x\xf0\x80\x80\x80\"", false, 7, stringNonVerbatim | stringNonCanonical, "x\ufffd\ufffd\ufffd\ufffd", nil, &SyntacticError{str: "invalid UTF-8 within string"}}, 1051 {"\"x\xed\xba\xad\"", false, 6, stringNonVerbatim | stringNonCanonical, "x\ufffd\ufffd\ufffd", nil, &SyntacticError{str: "invalid UTF-8 within string"}}, 1052 {"\"\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\U0001f602\"", false, 25, 0, "\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\U0001f602", nil, nil}, 1053 {`"¢"`[:2], false, 1, 0, "", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF}, 1054 {`"¢"`[:3], false, 3, 0, "¢", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF}, // missing terminating quote 1055 {`"¢"`[:4], false, 4, 0, "¢", nil, nil}, 1056 {`"€"`[:2], false, 1, 0, "", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF}, 1057 {`"€"`[:3], false, 1, 0, "", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF}, 1058 {`"€"`[:4], false, 4, 0, "€", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF}, // missing terminating quote 1059 {`"€"`[:5], false, 5, 0, "€", nil, nil}, 1060 {`"𐍈"`[:2], false, 1, 0, "", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF}, 1061 {`"𐍈"`[:3], false, 1, 0, "", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF}, 1062 {`"𐍈"`[:4], false, 1, 0, "", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF}, 1063 {`"𐍈"`[:5], false, 5, 0, "𐍈", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF}, // missing terminating quote 1064 {`"𐍈"`[:6], false, 6, 0, "𐍈", nil, nil}, 1065 {`"x\`, false, 2, stringNonVerbatim, "x", io.ErrUnexpectedEOF, nil}, 1066 {`"x\"`, false, 4, stringNonVerbatim, "x\"", io.ErrUnexpectedEOF, nil}, 1067 {`"x\x"`, false, 2, stringNonVerbatim | stringNonCanonical, "x", &SyntacticError{str: `invalid escape sequence "\\x" within string`}, nil}, 1068 {`"\"\\\b\f\n\r\t"`, false, 16, stringNonVerbatim, "\"\\\b\f\n\r\t", nil, nil}, 1069 {`"/"`, true, 3, 0, "/", nil, nil}, 1070 {`"\/"`, false, 4, stringNonVerbatim | stringNonCanonical, "/", nil, nil}, 1071 {`"\u002f"`, false, 8, stringNonVerbatim | stringNonCanonical, "/", nil, nil}, 1072 {`"\u`, false, 1, stringNonVerbatim, "", io.ErrUnexpectedEOF, nil}, 1073 {`"\uf`, false, 1, stringNonVerbatim, "", io.ErrUnexpectedEOF, nil}, 1074 {`"\uff`, false, 1, stringNonVerbatim, "", io.ErrUnexpectedEOF, nil}, 1075 {`"\ufff`, false, 1, stringNonVerbatim, "", io.ErrUnexpectedEOF, nil}, 1076 {`"\ufffd`, false, 7, stringNonVerbatim | stringNonCanonical, "\ufffd", io.ErrUnexpectedEOF, nil}, 1077 {`"\ufffd"`, false, 8, stringNonVerbatim | stringNonCanonical, "\ufffd", nil, nil}, 1078 {`"\uABCD"`, false, 8, stringNonVerbatim | stringNonCanonical, "\uabcd", nil, nil}, 1079 {`"\uefX0"`, false, 1, stringNonVerbatim | stringNonCanonical, "", &SyntacticError{str: `invalid escape sequence "\\uefX0" within string`}, nil}, 1080 {`"\uDEAD`, false, 7, stringNonVerbatim | stringNonCanonical, "\ufffd", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF}, 1081 {`"\uDEAD"`, false, 8, stringNonVerbatim | stringNonCanonical, "\ufffd", nil, &SyntacticError{str: `invalid escape sequence "\"" within string`}}, 1082 {`"\uDEAD______"`, false, 14, stringNonVerbatim | stringNonCanonical, "\ufffd______", nil, &SyntacticError{str: "invalid unpaired surrogate half within string"}}, 1083 {`"\uDEAD\uXXXX"`, false, 7, stringNonVerbatim | stringNonCanonical, "\ufffd", &SyntacticError{str: `invalid escape sequence "\\uXXXX" within string`}, nil}, 1084 {`"\uDEAD\uBEEF"`, false, 14, stringNonVerbatim | stringNonCanonical, "\ufffd\ubeef", nil, &SyntacticError{str: `invalid surrogate pair in string`}}, 1085 {`"\uD800\udead"`, false, 14, stringNonVerbatim | stringNonCanonical, "\U000102ad", nil, nil}, 1086 {`"\u0022\u005c\u002f\u0008\u000c\u000a\u000d\u0009"`, false, 50, stringNonVerbatim | stringNonCanonical, "\"\\/\b\f\n\r\t", nil, nil}, 1087 {`"\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\ud83d\ude02"`, false, 56, stringNonVerbatim | stringNonCanonical, "\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\U0001f602", nil, nil}, 1088 } 1089 1090 for _, tt := range tests { 1091 t.Run("", func(t *testing.T) { 1092 switch got := consumeSimpleString([]byte(tt.in)); { 1093 case tt.simple && got != tt.want: 1094 t.Errorf("consumeSimpleString(%q) = %v, want %v", tt.in, got, tt.want) 1095 case !tt.simple && got != 0: 1096 t.Errorf("consumeSimpleString(%q) = %v, want %v", tt.in, got, 0) 1097 } 1098 1099 var gotFlags valueFlags 1100 got, gotErr := consumeString(&gotFlags, []byte(tt.in), false) 1101 if gotFlags != tt.wantFlags { 1102 t.Errorf("consumeString(%q, false) flags = %v, want %v", tt.in, gotFlags, tt.wantFlags) 1103 } 1104 if got != tt.want || !reflect.DeepEqual(gotErr, tt.wantErr) { 1105 t.Errorf("consumeString(%q, false) = (%v, %v), want (%v, %v)", tt.in, got, gotErr, tt.want, tt.wantErr) 1106 } 1107 switch got, gotErr := consumeString(&gotFlags, []byte(tt.in), true); { 1108 case tt.wantErrUTF8 == nil && (got != tt.want || !reflect.DeepEqual(gotErr, tt.wantErr)): 1109 t.Errorf("consumeString(%q, true) = (%v, %v), want (%v, %v)", tt.in, got, gotErr, tt.want, tt.wantErr) 1110 case tt.wantErrUTF8 != nil && (got > tt.want || !reflect.DeepEqual(gotErr, tt.wantErrUTF8)): 1111 t.Errorf("consumeString(%q, true) = (%v, %v), want (%v, %v)", tt.in, got, gotErr, tt.want, tt.wantErrUTF8) 1112 } 1113 1114 gotStr, gotOk := unescapeString(nil, []byte(tt.in[:got])) 1115 wantOk := tt.wantErr == nil 1116 if string(gotStr) != tt.wantStr || gotOk != wantOk { 1117 t.Errorf("unescapeString(nil, %q) = (%q, %v), want (%q, %v)", tt.in[:got], gotStr, gotOk, tt.wantStr, wantOk) 1118 } 1119 if _, gotOk := unescapeString(nil, []byte(tt.in)); got < len(tt.in) && gotOk { 1120 t.Errorf("unescapeString(nil, %q) = (_, true), want (_, false)", tt.in) 1121 } 1122 }) 1123 } 1124 } 1125 1126 func TestConsumeNumber(t *testing.T) { 1127 tests := []struct { 1128 in string 1129 simple bool 1130 want int 1131 wantErr error 1132 }{ 1133 {"", false, 0, io.ErrUnexpectedEOF}, 1134 {`"NaN"`, false, 0, newInvalidCharacterError([]byte("\""), "within number (expecting digit)")}, 1135 {`"Infinity"`, false, 0, newInvalidCharacterError([]byte("\""), "within number (expecting digit)")}, 1136 {`"-Infinity"`, false, 0, newInvalidCharacterError([]byte("\""), "within number (expecting digit)")}, 1137 {".0", false, 0, newInvalidCharacterError([]byte("."), "within number (expecting digit)")}, 1138 {"0", true, 1, nil}, 1139 {"-0", false, 2, nil}, 1140 {"+0", false, 0, newInvalidCharacterError([]byte("+"), "within number (expecting digit)")}, 1141 {"1", true, 1, nil}, 1142 {"-1", false, 2, nil}, 1143 {"00", true, 1, nil}, 1144 {"-00", false, 2, nil}, 1145 {"01", true, 1, nil}, 1146 {"-01", false, 2, nil}, 1147 {"0i", true, 1, nil}, 1148 {"-0i", false, 2, nil}, 1149 {"0f", true, 1, nil}, 1150 {"-0f", false, 2, nil}, 1151 {"9876543210", true, 10, nil}, 1152 {"-9876543210", false, 11, nil}, 1153 {"9876543210x", true, 10, nil}, 1154 {"-9876543210x", false, 11, nil}, 1155 {" 9876543210", true, 0, newInvalidCharacterError([]byte(" "), "within number (expecting digit)")}, 1156 {"- 9876543210", false, 1, newInvalidCharacterError([]byte(" "), "within number (expecting digit)")}, 1157 {strings.Repeat("9876543210", 1000), true, 10000, nil}, 1158 {"-" + strings.Repeat("9876543210", 1000), false, 1 + 10000, nil}, 1159 {"0.", false, 1, io.ErrUnexpectedEOF}, 1160 {"-0.", false, 2, io.ErrUnexpectedEOF}, 1161 {"0e", false, 1, io.ErrUnexpectedEOF}, 1162 {"-0e", false, 2, io.ErrUnexpectedEOF}, 1163 {"0E", false, 1, io.ErrUnexpectedEOF}, 1164 {"-0E", false, 2, io.ErrUnexpectedEOF}, 1165 {"0.0", false, 3, nil}, 1166 {"-0.0", false, 4, nil}, 1167 {"0e0", false, 3, nil}, 1168 {"-0e0", false, 4, nil}, 1169 {"0E0", false, 3, nil}, 1170 {"-0E0", false, 4, nil}, 1171 {"0.0123456789", false, 12, nil}, 1172 {"-0.0123456789", false, 13, nil}, 1173 {"1.f", false, 2, newInvalidCharacterError([]byte("f"), "within number (expecting digit)")}, 1174 {"-1.f", false, 3, newInvalidCharacterError([]byte("f"), "within number (expecting digit)")}, 1175 {"1.e", false, 2, newInvalidCharacterError([]byte("e"), "within number (expecting digit)")}, 1176 {"-1.e", false, 3, newInvalidCharacterError([]byte("e"), "within number (expecting digit)")}, 1177 {"1e0", false, 3, nil}, 1178 {"-1e0", false, 4, nil}, 1179 {"1E0", false, 3, nil}, 1180 {"-1E0", false, 4, nil}, 1181 {"1Ex", false, 2, newInvalidCharacterError([]byte("x"), "within number (expecting digit)")}, 1182 {"-1Ex", false, 3, newInvalidCharacterError([]byte("x"), "within number (expecting digit)")}, 1183 {"1e-0", false, 4, nil}, 1184 {"-1e-0", false, 5, nil}, 1185 {"1e+0", false, 4, nil}, 1186 {"-1e+0", false, 5, nil}, 1187 {"1E-0", false, 4, nil}, 1188 {"-1E-0", false, 5, nil}, 1189 {"1E+0", false, 4, nil}, 1190 {"-1E+0", false, 5, nil}, 1191 {"1E+00500", false, 8, nil}, 1192 {"-1E+00500", false, 9, nil}, 1193 {"1E+00500x", false, 8, nil}, 1194 {"-1E+00500x", false, 9, nil}, 1195 {"9876543210.0123456789e+01234589x", false, 31, nil}, 1196 {"-9876543210.0123456789e+01234589x", false, 32, nil}, 1197 {"1_000_000", true, 1, nil}, 1198 {"0x12ef", true, 1, nil}, 1199 {"0x1p-2", true, 1, nil}, 1200 } 1201 1202 for _, tt := range tests { 1203 t.Run("", func(t *testing.T) { 1204 switch got := consumeSimpleNumber([]byte(tt.in)); { 1205 case tt.simple && got != tt.want: 1206 t.Errorf("consumeSimpleNumber(%q) = %v, want %v", tt.in, got, tt.want) 1207 case !tt.simple && got != 0: 1208 t.Errorf("consumeSimpleNumber(%q) = %v, want %v", tt.in, got, 0) 1209 } 1210 1211 got, gotErr := consumeNumber([]byte(tt.in)) 1212 if got != tt.want || !reflect.DeepEqual(gotErr, tt.wantErr) { 1213 t.Errorf("consumeNumber(%q) = (%v, %v), want (%v, %v)", tt.in, got, gotErr, tt.want, tt.wantErr) 1214 } 1215 }) 1216 } 1217 } 1218 1219 func TestParseHexUint16(t *testing.T) { 1220 tests := []struct { 1221 in string 1222 want uint16 1223 wantOk bool 1224 }{ 1225 {"", 0, false}, 1226 {"a", 0, false}, 1227 {"ab", 0, false}, 1228 {"abc", 0, false}, 1229 {"abcd", 0xabcd, true}, 1230 {"abcde", 0, false}, 1231 {"9eA1", 0x9ea1, true}, 1232 {"gggg", 0, false}, 1233 {"0000", 0x0000, true}, 1234 {"1234", 0x1234, true}, 1235 } 1236 1237 for _, tt := range tests { 1238 t.Run("", func(t *testing.T) { 1239 got, gotOk := parseHexUint16([]byte(tt.in)) 1240 if got != tt.want || gotOk != tt.wantOk { 1241 t.Errorf("parseHexUint16(%q) = (0x%04x, %v), want (0x%04x, %v)", tt.in, got, gotOk, tt.want, tt.wantOk) 1242 } 1243 }) 1244 } 1245 } 1246 1247 func TestParseDecUint(t *testing.T) { 1248 tests := []struct { 1249 in string 1250 want uint64 1251 wantOk bool 1252 }{ 1253 {"", 0, false}, 1254 {"0", 0, true}, 1255 {"1", 1, true}, 1256 {"-1", 0, false}, 1257 {"1f", 0, false}, 1258 {"00", 0, true}, 1259 {"01", 1, true}, 1260 {"10", 10, true}, 1261 {"10.9", 0, false}, 1262 {" 10", 0, false}, 1263 {"10 ", 0, false}, 1264 {"123456789", 123456789, true}, 1265 {"123456789d", 0, false}, 1266 {"18446744073709551614", math.MaxUint64 - 1, true}, 1267 {"18446744073709551615", math.MaxUint64, true}, 1268 {"99999999999999999999999999999999", math.MaxUint64, false}, 1269 {"99999999999999999999999999999999f", 0, false}, 1270 } 1271 1272 for _, tt := range tests { 1273 t.Run("", func(t *testing.T) { 1274 got, gotOk := parseDecUint([]byte(tt.in)) 1275 if got != tt.want || gotOk != tt.wantOk { 1276 t.Errorf("parseDecUint(%q) = (%v, %v), want (%v, %v)", tt.in, got, gotOk, tt.want, tt.wantOk) 1277 } 1278 }) 1279 } 1280 } 1281 1282 func TestParseFloat(t *testing.T) { 1283 tests := []struct { 1284 in string 1285 want32 float64 1286 want64 float64 1287 wantOk bool 1288 }{ 1289 {"0", 0, 0, true}, 1290 {"-1", -1, -1, true}, 1291 {"1", 1, 1, true}, 1292 1293 {"-16777215", -16777215, -16777215, true}, // -(1<<24 - 1) 1294 {"16777215", 16777215, 16777215, true}, // +(1<<24 - 1) 1295 {"-16777216", -16777216, -16777216, true}, // -(1<<24) 1296 {"16777216", 16777216, 16777216, true}, // +(1<<24) 1297 {"-16777217", -16777216, -16777217, true}, // -(1<<24 + 1) 1298 {"16777217", 16777216, 16777217, true}, // +(1<<24 + 1) 1299 1300 {"-9007199254740991", -9007199254740992, -9007199254740991, true}, // -(1<<53 - 1) 1301 {"9007199254740991", 9007199254740992, 9007199254740991, true}, // +(1<<53 - 1) 1302 {"-9007199254740992", -9007199254740992, -9007199254740992, true}, // -(1<<53) 1303 {"9007199254740992", 9007199254740992, 9007199254740992, true}, // +(1<<53) 1304 {"-9007199254740993", -9007199254740992, -9007199254740992, true}, // -(1<<53 + 1) 1305 {"9007199254740993", 9007199254740992, 9007199254740992, true}, // +(1<<53 + 1) 1306 1307 {"-1e1000", -math.MaxFloat32, -math.MaxFloat64, true}, 1308 {"1e1000", +math.MaxFloat32, +math.MaxFloat64, true}, 1309 } 1310 1311 for _, tt := range tests { 1312 t.Run("", func(t *testing.T) { 1313 got32, gotOk32 := parseFloat([]byte(tt.in), 32) 1314 if got32 != tt.want32 || gotOk32 != tt.wantOk { 1315 t.Errorf("parseFloat(%q, 32) = (%v, %v), want (%v, %v)", tt.in, got32, gotOk32, tt.want32, tt.wantOk) 1316 } 1317 1318 got64, gotOk64 := parseFloat([]byte(tt.in), 64) 1319 if got64 != tt.want64 || gotOk64 != tt.wantOk { 1320 t.Errorf("parseFloat(%q, 64) = (%v, %v), want (%v, %v)", tt.in, got64, gotOk64, tt.want64, tt.wantOk) 1321 } 1322 }) 1323 } 1324 }