============================================================================= Gate E: Streaming Decoder vs one-shot Unmarshal consistency ============================================================================= runStreamingConsistencyGate asserts that json.NewDecoder.Decode and json.Unmarshal a
(t *testing.T, data []byte)
| 346 | // historically; this gate surfaces any divergence not explained by the |
| 347 | // trailing-data semantic. |
| 348 | func runStreamingConsistencyGate(t *testing.T, data []byte) { |
| 349 | t.Helper() |
| 350 | |
| 351 | var decV interface{} |
| 352 | var decErr error |
| 353 | encodingJSONNoPanic(t, "Streaming/Decode", data, func() { |
| 354 | dec := json.NewDecoder(bytes.NewReader(data)) |
| 355 | decErr = dec.Decode(&decV) |
| 356 | }) |
| 357 | |
| 358 | var unV interface{} |
| 359 | var unErr error |
| 360 | encodingJSONNoPanic(t, "Streaming/Unmarshal", data, func() { |
| 361 | unErr = json.Unmarshal(data, &unV) |
| 362 | }) |
| 363 | |
| 364 | valid := json.Valid(data) |
| 365 | |
| 366 | if decErr == nil && unErr == nil { |
| 367 | // Both succeeded: values must match. |
| 368 | if !reflect.DeepEqual(decV, unV) { |
| 369 | t.Errorf("Gate E: Decoder and Unmarshal both succeeded but values differ:\n"+ |
| 370 | " decoder=%#v\n unmarshal=%#v\n data=%s", |
| 371 | decV, unV, truncateForMsg(data)) |
| 372 | } |
| 373 | return |
| 374 | } |
| 375 | if decErr != nil && unErr != nil { |
| 376 | // Both failed: they agree. For valid JSON this is the documented |
| 377 | // float64-range limitation (e.g. 1e999 overflows float64 identically |
| 378 | // under both the streaming and one-shot paths); for invalid JSON it |
| 379 | // is expected. Either way, Decoder and Unmarshal agree. |
| 380 | return |
| 381 | } |
| 382 | // Exactly one succeeded while the other failed. |
| 383 | if valid { |
| 384 | // For VALID JSON there is no trailing-data semantic to explain the |
| 385 | // divergence — this is a genuine streaming-vs-one-shot inconsistency. |
| 386 | t.Errorf("Gate E: on valid JSON, Decoder and Unmarshal disagree on success "+ |
| 387 | "(decErr=%v, unErr=%v): data=%s", |
| 388 | decErr, unErr, truncateForMsg(data)) |
| 389 | return |
| 390 | } |
| 391 | // For INVALID JSON: the only documented reason for exactly one of the two |
| 392 | // to succeed is the streaming Decoder's trailing-data semantic — it reads |
| 393 | // ONE top-level value and ignores the rest, while Unmarshal rejects |
| 394 | // trailing bytes (so "{}{}" decodes the first "{}" but fails to unmarshal). |
| 395 | // This is the KNOWN, legitimate divergence and is NOT flagged. |
| 396 | } |
| 397 | |
| 398 | // ============================================================================= |
| 399 | // Gate F: Compact / Indent / HTMLEscape must never panic |
no test coverage detected