genString emits a JSON string value. Includes empty "", ASCII, strings with escape sequences, unicode escapes, and long strings.
(r *rand.Rand, buf *[]byte)
| 297 | // genString emits a JSON string value. Includes empty "", ASCII, strings |
| 298 | // with escape sequences, unicode escapes, and long strings. |
| 299 | func genString(r *rand.Rand, buf *[]byte) { |
| 300 | *buf = append(*buf, '"') |
| 301 | switch r.Intn(22) { |
| 302 | case 0: // empty string |
| 303 | case 1: // ASCII short |
| 304 | for i := 0; i < 1+r.Intn(8); i++ { |
| 305 | *buf = append(*buf, byte('a'+r.Intn(26))) |
| 306 | } |
| 307 | case 2: // escape sequences (all 8 JSON escapes incl. \b and \f) |
| 308 | escapes := [][]byte{[]byte(`\n`), []byte(`\t`), []byte(`\"`), []byte(`\\`), []byte(`\/`), []byte(`\r`), []byte(`\b`), []byte(`\f`)} |
| 309 | for i := 0; i < 1+r.Intn(4); i++ { |
| 310 | *buf = append(*buf, escapes[r.Intn(len(escapes))]...) |
| 311 | } |
| 312 | case 3: // unicode escape (BMP non-surrogate, hiragana range) |
| 313 | *buf = append(*buf, '\\', 'u', '3', '0') |
| 314 | *buf = append(*buf, hexDigit(r), hexDigit(r)) |
| 315 | case 4: // long string (stress allocation) |
| 316 | for i := 0; i < 50+r.Intn(50); i++ { |
| 317 | *buf = append(*buf, byte('a'+r.Intn(26))) |
| 318 | } |
| 319 | case 5: // mixed content with escapes |
| 320 | *buf = append(*buf, []byte(`hello\nworld\u2603`)...) |
| 321 | case 6: // numeric-looking string (tests type coercion in callers) |
| 322 | *buf = append(*buf, '1', '2', '3', '4', '5') |
| 323 | case 7: // whitespace inside string (properly escaped — raw control |
| 324 | // bytes like 0x09 are invalid inside JSON strings per RFC 8259, |
| 325 | // so we emit the \t escape sequence instead of a literal tab). |
| 326 | *buf = append(*buf, ' ', '\\', 't') |
| 327 | // --- raw multibyte UTF-8 (parser indexes BYTES not runes) --- |
| 328 | case 8: // 2-byte UTF-8 raw (U+0080–U+07FF: accented Latin, Greek, Cyrillic) |
| 329 | var u [4]byte |
| 330 | n := utf8.EncodeRune(u[:], rune(0x80+r.Intn(0x780))) |
| 331 | *buf = append(*buf, u[:n]...) |
| 332 | case 9: // 3-byte UTF-8 raw (U+0800–U+FFFF: CJK, Arabic, Hindi) |
| 333 | var u [4]byte |
| 334 | n := utf8.EncodeRune(u[:], rune(0x800+r.Intn(0xF800))) |
| 335 | *buf = append(*buf, u[:n]...) |
| 336 | case 10: // 4-byte UTF-8 raw (U+10000+: emoji, math symbols, CJK ext.) |
| 337 | var u [4]byte |
| 338 | cp := 0x10000 + r.Intn(0x10FFFF-0x10000+1) |
| 339 | n := utf8.EncodeRune(u[:], rune(cp)) |
| 340 | *buf = append(*buf, u[:n]...) |
| 341 | // --- surrogate-pair escapes (the escape decoder must combine these) --- |
| 342 | case 11: // valid surrogate pair (\uXXXX\uXXXX → U+10000..U+10FFFF) |
| 343 | cp := 0x10000 + r.Intn(0x10FFFF-0x10000+1) |
| 344 | cp -= 0x10000 |
| 345 | appendUnicodeEscape(buf, 0xD800+(cp>>10)) |
| 346 | appendUnicodeEscape(buf, 0xDC00+(cp&0x3FF)) |
| 347 | case 12: // lone high surrogate (malformed — parser must reject) |
| 348 | appendUnicodeEscape(buf, 0xD800+r.Intn(0x400)) |
| 349 | case 13: // lone low surrogate (malformed — parser must reject) |
| 350 | appendUnicodeEscape(buf, 0xDC00+r.Intn(0x400)) |
| 351 | case 14: // two high surrogates back-to-back (malformed) |
| 352 | appendUnicodeEscape(buf, 0xD800+r.Intn(0x400)) |
| 353 | appendUnicodeEscape(buf, 0xD800+r.Intn(0x400)) |
| 354 | // --- control characters (escaped form, valid JSON) --- |
| 355 | case 15: // escaped null and unit separator |
| 356 | appendUnicodeEscape(buf, 0x00) // \u0000 |
no test coverage detected