MCPcopy Create free account
hub / github.com/buger/jsonparser / FuzzPathMutation

Function FuzzPathMutation

path_fuzz_test.go:165–275  ·  view source on GitHub ↗

FuzzPathMutation mutates BOTH the JSON bytes and the key-path bytes, then exercises the full parser surface. This is the harness that would have caught the 8th empty-key panic site (parser.go:981's predecessor hazards in searchKeys/EachKey/createInsertComponent/calcAllocateSpace, now fixed) and whic

(f *testing.F)

Source from the content-addressed store, hash-verified

163// Verifies: SYS-REQ-035 [no-panic on malformed input]
164// reqproof:proptest Get, Set, Delete, GetString, GetInt, GetFloat, GetBoolean, ArrayEach, ObjectEach, EachKey
165func FuzzPathMutation(f *testing.F) {
166 // Seed corpus: a mix of valid JSON + non-empty paths, AND adversarial
167 // path shapes (empty, trailing-slash, array-index-then-empty). The
168 // mutation engine will explore combinations of these.
169 f.Add([]byte(`{"a":1}`), []byte("a"))
170 f.Add([]byte(`[1,2,3]`), []byte(""))
171 f.Add([]byte(`{"a":{"b":1}}`), []byte("a"))
172 f.Add([]byte(`{"a":[{"x":1}]}`), []byte("a")) // 8th-site repro shape
173 f.Add([]byte(`{"a":1}`), []byte("[0]")) // array-index path on object
174 f.Add([]byte(`{"a":1}`), []byte("[99]")) // out-of-range index
175 f.Add([]byte(`{"":1}`), []byte("")) // object with empty key
176 f.Add([]byte(`{"a":[1,2,3]}`), []byte("a/")) // trailing empty
177 f.Add([]byte(`{"a":[{"b":1}]}`), []byte("a/[0]")) // nested array index
178 f.Add([]byte(`{"a":[{"b":1}]}`), []byte("a/[0]/")) // D9 repro: arr-of-obj + empty trailing
179 f.Add([]byte(`null`), []byte("a"))
180 f.Add([]byte(``), []byte("a"))
181 f.Add([]byte(`{`), []byte("a"))
182 f.Add([]byte(`[}`), []byte("[0]"))
183
184 f.Fuzz(func(t *testing.T, data []byte, path []byte) {
185 components := splitPathComponents(path)
186 inputValid := json.Valid(data)
187 pathShapeMatches := pathShapeMatchesRoot(data, components)
188
189 // --- Get family ---
190 runPathOp("Get", data, path, func() {
191 _, _, _, _ = Get(data, components...)
192 })
193 runPathOp("GetString", data, path, func() {
194 _, _ = GetString(data, components...)
195 })
196 runPathOp("GetInt", data, path, func() {
197 _, _ = GetInt(data, components...)
198 })
199 runPathOp("GetFloat", data, path, func() {
200 _, _ = GetFloat(data, components...)
201 })
202 runPathOp("GetBoolean", data, path, func() {
203 _, _ = GetBoolean(data, components...)
204 })
205
206 // --- ArrayEach / ObjectEach ---
207 runPathOp("ArrayEach", data, path, func() {
208 _, _ = ArrayEach(data, func(value []byte, dataType ValueType, offset int, err error) {
209 // callback error is informational; do not propagate.
210 }, components...)
211 })
212 runPathOp("ObjectEach", data, path, func() {
213 _ = ObjectEach(data, func(key, value []byte, dataType ValueType, offset int) error {
214 return nil
215 }, components...)
216 })
217
218 // --- EachKey with the same components as a single path ---
219 if len(components) > 0 {
220 runPathOp("EachKey", data, path, func() {
221 EachKey(data, func(idx int, value []byte, vt ValueType, err error) {
222 // informational callback

Callers

nothing calls this directly

Calls 13

splitPathComponentsFunction · 0.85
pathShapeMatchesRootFunction · 0.85
runPathOpFunction · 0.85
GetFunction · 0.85
GetStringFunction · 0.85
GetIntFunction · 0.85
GetFloatFunction · 0.85
GetBooleanFunction · 0.85
ArrayEachFunction · 0.85
ObjectEachFunction · 0.85
EachKeyFunction · 0.85
SetFunction · 0.85

Tested by

no test coverage detected