checkParseStringGate (Gate 8: PARSESTRING) extracts a String-typed value via Get and calls ParseString on the raw escaped content. Closes the API- coverage blind spot: without this gate, the structure-aware fuzzer NEVER reaches ParseString on grammar-generated escape sequences (\uXXXX, \uD800\uDC00
(t *testing.T, data []byte, path []string)
| 1157 | // surrogate pairs, \u0000, long escape runs). It also cross-checks the |
| 1158 | // unescaped result against encoding/json on the same token. |
| 1159 | func checkParseStringGate(t *testing.T, data []byte, path []string) { |
| 1160 | t.Helper() |
| 1161 | if len(data) > fuzzGateSizeCap { |
| 1162 | return |
| 1163 | } |
| 1164 | val, dt, _, err := Get(data, path...) |
| 1165 | if err != nil || dt != String || len(val) == 0 { |
| 1166 | return |
| 1167 | } |
| 1168 | out, perr := ParseString(val) |
| 1169 | if perr != nil { |
| 1170 | // ParseString rejects malformed escapes; that is a clean failure. |
| 1171 | return |
| 1172 | } |
| 1173 | // NOTE: jsonparser is documented as lenient on raw invalid UTF-8 bytes |
| 1174 | // inside strings — it passes them through unchanged (consistent with |
| 1175 | // Get's no-validate contract on these seeds). We therefore do NOT assert |
| 1176 | // utf8.ValidString(out); that would assert a contract the parser does |
| 1177 | // not claim to uphold. The differential check below is the honest gate: |
| 1178 | // for any token encoding/json accepts, ParseString MUST produce the same |
| 1179 | // output. Disagreement there is a genuine unescape bug. |
| 1180 | // |
| 1181 | // Cross-check against encoding/json's reference unescaper. Wrap val back |
| 1182 | // into a JSON string literal so json.Unmarshal sees the same token. |
| 1183 | // Restricted to valid-UTF-8 inputs because the two implementations |
| 1184 | // DOCUMENTEDLY disagree on invalid-UTF-8 handling (jsonparser passes |
| 1185 | // raw bytes through; encoding/json substitutes U+FFFD) — that is a |
| 1186 | // design choice, not an unescape bug. |
| 1187 | quoted := make([]byte, 0, len(val)+2) |
| 1188 | quoted = append(quoted, '"') |
| 1189 | quoted = append(quoted, val...) |
| 1190 | quoted = append(quoted, '"') |
| 1191 | var ref string |
| 1192 | if jerr := json.Unmarshal(quoted, &ref); jerr == nil && utf8.Valid(val) { |
| 1193 | // Both succeeded — they must agree byte-for-byte. |
| 1194 | if out != ref { |
| 1195 | t.Errorf("ParseString disagrees with encoding/json "+ |
| 1196 | "(PARSESTRING differential): ParseString(%q)=%q json.Unmarshal=%q data=%q path=%v", |
| 1197 | val, out, ref, data, path) |
| 1198 | } |
| 1199 | } |
| 1200 | // Sanity: result is bounded (catches runaway allocation in Unescape). |
| 1201 | if len(out) > len(val)*4+16 { |
| 1202 | t.Errorf("ParseString returned suspiciously large output (PARSESTRING sanity): "+ |
| 1203 | "in=%d out=%d data=%q path=%v", len(val), len(out), data, path) |
| 1204 | } |
| 1205 | } |
| 1206 | |
| 1207 | // checkParseBooleanGate (Gate 9: PARSEBOOLEAN) cross-checks ParseBoolean |
| 1208 | // against strconv.ParseBool on Boolean-typed values. Closes the API-coverage |
no test coverage detected