TestFuzzPathMutationSeedsClean is a regression gate that runs every seed corpus entry through FuzzPathMutation's body once. It catches seed-shape regressions (a seed that newly panics after a code change) without requiring a `-fuzz` run. Uses the same recover-and-record pattern as the fuzz body so p
(t *testing.T)
| 276 | // |
| 277 | // Verifies: SYS-REQ-035 [seed cleanliness] |
| 278 | func TestFuzzPathMutationSeedsClean(t *testing.T) { |
| 279 | pathCrashCounter = 0 |
| 280 | // Re-run the seed corpus through a manual loop (we can't invoke the |
| 281 | // testing.F body directly, so we replicate the body). Any seed that |
| 282 | // records a crash fails this test. |
| 283 | seeds := []struct { |
| 284 | data []byte |
| 285 | path []byte |
| 286 | }{ |
| 287 | {[]byte(`{"a":1}`), []byte("a")}, |
| 288 | {[]byte(`[1,2,3]`), []byte("")}, |
| 289 | {[]byte(`{"a":{"b":1}}`), []byte("a")}, |
| 290 | {[]byte(`{"a":[{"x":1}]}`), []byte("a")}, |
| 291 | {[]byte(`{"a":1}`), []byte("[0]")}, |
| 292 | {[]byte(`{"a":1}`), []byte("[99]")}, |
| 293 | {[]byte(`{"":1}`), []byte("")}, |
| 294 | {[]byte(`{"a":[1,2,3]}`), []byte("a/")}, |
| 295 | {[]byte(`{"a":[{"b":1}]}`), []byte("a/[0]")}, |
| 296 | {[]byte(`{"a":[{"b":1}]}`), []byte("a/[0]/")}, |
| 297 | {[]byte(`null`), []byte("a")}, |
| 298 | {[]byte(``), []byte("a")}, |
| 299 | {[]byte(`{`), []byte("a")}, |
| 300 | {[]byte(`[}`), []byte("[0]")}, |
| 301 | } |
| 302 | setVal := []byte(`"v"`) |
| 303 | for i, tc := range seeds { |
| 304 | components := splitPathComponents(tc.path) |
| 305 | |
| 306 | // json.Valid is only a meaningful post-condition when the input is |
| 307 | // itself valid JSON AND the path semantics apply to the input's |
| 308 | // container type. For malformed input or shape-mismatched paths |
| 309 | // (D6: array-index on object root), the parser's behavior is |
| 310 | // undefined; we only assert no-panic there. The D6 corruption is |
| 311 | // documented in reference_oracle_test.go's file header. |
| 312 | inputValid := json.Valid(tc.data) |
| 313 | pathShapeMatches := pathShapeMatchesRoot(tc.data, components) |
| 314 | |
| 315 | // We do NOT soft-skip the D9 panic here: the seeds exercise shapes |
| 316 | // known to be safe post-fix, plus the D9 repro shape which IS |
| 317 | // expected to record a crash. If a previously-safe seed starts |
| 318 | // panicking, that's a regression. |
| 319 | ops := []struct { |
| 320 | name string |
| 321 | fn func() |
| 322 | }{ |
| 323 | {"Get", func() { _, _, _, _ = Get(tc.data, components...) }}, |
| 324 | {"GetString", func() { _, _ = GetString(tc.data, components...) }}, |
| 325 | {"GetInt", func() { _, _ = GetInt(tc.data, components...) }}, |
| 326 | {"GetFloat", func() { _, _ = GetFloat(tc.data, components...) }}, |
| 327 | {"GetBoolean", func() { _, _ = GetBoolean(tc.data, components...) }}, |
| 328 | {"ArrayEach", func() { |
| 329 | _, _ = ArrayEach(tc.data, func([]byte, ValueType, int, error) {}, components...) |
| 330 | }}, |
| 331 | {"ObjectEach", func() { |
| 332 | _ = ObjectEach(tc.data, func([]byte, []byte, ValueType, int) error { return nil }, components...) |
| 333 | }}, |
| 334 | {"EachKey", func() { |
| 335 | if len(components) > 0 { |
nothing calls this directly
no test coverage detected