// UTF-8 fuzzer for strip() — library.md §7 item 3 asks for this by name:
//
// "Fuzz UTF-8 specifically. strip §8 names it: byte-vs-character offsets is 'the single most
// likely defect here and produces facets that land on the wrong characters only for non-ASCII
// authors.' Thirty-six hand-written vectors may never catch it; a fuzzer will."
//
// The oracle is not "does it look right" — it is EXACT: for a generated `[LABEL](url)`, slicing the
// output text by the facet's BYTE range must decode to exactly LABEL. A character-offset
// implementation passes every ASCII case and fails the moment one multi-byte character precedes a
// facet, which is why the hand-written vectors cannot be trusted alone here.
//
// Deterministic by seed. A fuzzer whose failures cannot be reproduced is a rumour, not a test, so
// the seed is printed and any failure reports the exact source that produced it.
import test from 'brittle'
import { strip } from '../lib/strip.js'
// xorshift32 — tiny, deterministic, dependency-free. Reproducibility is the point.
function rng (seed) {
let s = seed >>> 0 || 1
return () => {
s ^= s << 13; s >>>= 0
s ^= s >> 17
s ^= s << 5; s >>>= 0
return s / 0x100000000
}
}
// Alphabet chosen to cover every UTF-8 width, plus the cases that break naive implementations.
const ALPHABET = [
'a', 'Z', '7', ' ', '-', // 1 byte
'é', 'ü', 'ß', 'ñ', // 2 bytes
'日', '本', 'א', 'ه', // 3 bytes
'🎉', '👩', '🌍', '🧀', // 4 bytes (surrogate pair in JS)
'é', // combining acute — 1 grapheme, 3 bytes, 2 code units
'👩💻', // ZWJ sequence — 1 grapheme, 11 bytes
' ' // NBSP — whitespace that is NOT ASCII space
]
const pick = (r, xs) => xs[Math.floor(r() * xs.length) % xs.length]
function randomText (r, n) {
let s = ''
for (let i = 0; i < n; i++) s += pick(r, ALPHABET)
return s
}
// A label that cannot contain markdown-significant characters, so the expected facet span is exact.
function randomLabel (r) {
let s = randomText(r, 1 + Math.floor(r() * 6))
s = s.replace(/[[\]()*_~`#|\\<>\n]/g, 'x').trim()
return s.length ? s : 'x'
}
const byteLen = (s) => Buffer.byteLength(s, 'utf8')
// Does this byte index fall on a UTF-8 character boundary? A continuation byte is 0b10xxxxxx.
function onBoundary (buf, i) {
if (i <= 0 || i >= buf.length) return true
return (buf[i] & 0xc0) !== 0x80
}
test('fuzz: facet byte ranges decode to exactly the label they cover', (t) => {
const SEED = 0x5eed1234
const r = rng(SEED)
t.comment('seed ' + SEED.toString(16) + ' — change it to explore, keep it to reproduce')
for (let i = 0; i < 600; i++) {
// A run of arbitrary UTF-8 BEFORE the facet is what shifts a char-offset implementation.
const prefix = randomText(r, Math.floor(r() * 8))
const label = randomLabel(r)
const suffix = randomText(r, Math.floor(r() * 5))
const url = 'https://example.com/' + (i % 97)
const src = prefix + '[' + label + '](' + url + ')' + suffix
const { text, facets } = strip(src)
const buf = Buffer.from(text, 'utf8')
if (facets.length !== 1) {
t.fail('expected exactly one facet for ' + JSON.stringify(src) + ' — got ' + facets.length)
continue
}
const { byteStart, byteEnd } = facets[0]
// ★ THE ORACLE. Slice by BYTES and decode: it must be the label, exactly.
const covered = buf.subarray(byteStart, byteEnd).toString('utf8')
if (covered !== label) {
t.fail('facet covers ' + JSON.stringify(covered) + ', expected ' + JSON.stringify(label) +
'\n source: ' + JSON.stringify(src) + '\n text: ' + JSON.stringify(text))
continue
}
t.ok(onBoundary(buf, byteStart) && onBoundary(buf, byteEnd),
'offsets land on UTF-8 character boundaries')
}
})
test('fuzz: hashtag facets cover "#tag" including the hash (§3.7)', (t) => {
const r = rng(0xbeef01)
for (let i = 0; i < 300; i++) {
const prefix = randomText(r, Math.floor(r() * 8))
const tag = 'tag' + i
const src = prefix + ' #' + tag + ' rest'
const { text, facets } = strip(src)
const buf = Buffer.from(text, 'utf8')
const tagFacets = facets.filter((f) => f.type === 'tag')
if (tagFacets.length !== 1) { t.fail('expected one tag facet for ' + JSON.stringify(src)); continue }
const { byteStart, byteEnd } = tagFacets[0]
t.is(buf.subarray(byteStart, byteEnd).toString('utf8'), '#' + tag,
'the facet spans #tag; the VALUE drops the hash')
}
})
test('fuzz: invariants hold on arbitrary markdown-ish input (§6, §2)', (t) => {
const r = rng(0xc0ffee)
const NOISE = ['**', '*', '~~', '`', '# ', '> ', '- ', '1. ', '|', '[[', ']]', ':::', '', '[^1]', '\\\n', ' ', '---\n', '<b>', '$$']
for (let i = 0; i < 800; i++) {
let src = ''
const parts = 1 + Math.floor(r() * 10)
for (let p = 0; p < parts; p++) src += (r() < 0.5 ? randomText(r, 1 + Math.floor(r() * 5)) : pick(r, NOISE))
let out
try {
out = strip(src)
} catch (err) {
t.fail('threw on ' + JSON.stringify(src) + ': ' + err.message)
continue
}
const buf = Buffer.from(out.text, 'utf8')
let prevEnd = -1
let ok = true
for (const f of out.facets) {
const { byteStart, byteEnd } = f
if (!(byteStart >= 0 && byteEnd <= buf.length)) { ok = false; t.fail('out of bounds: ' + JSON.stringify(src)); break }
if (!(byteEnd > byteStart)) { ok = false; t.fail('empty facet not dropped (§6.3): ' + JSON.stringify(src)); break }
if (byteStart < prevEnd) { ok = false; t.fail('overlapping facets (§6.2): ' + JSON.stringify(src)); break }
if (!onBoundary(buf, byteStart) || !onBoundary(buf, byteEnd)) { ok = false; t.fail('offset mid-character: ' + JSON.stringify(src)); break }
if (typeof f.type !== 'string' || !('value' in f)) { ok = false; t.fail('not a native facet (§6.5): ' + JSON.stringify(src)); break }
prevEnd = byteEnd
}
t.ok(ok, 'invariants hold')
}
})
test('fuzz: §5 normalisation is idempotent on its own output (§7 property law)', (t) => {
const r = rng(0xd0d0)
for (let i = 0; i < 300; i++) {
const src = randomText(r, 1 + Math.floor(r() * 20)) + pick(r, ['\n\n\n', ' \n', '\n ', ' '])
const once = strip(src).text
// Plain text is valid markdown, so stripping the output again must be a fixed point:
// trailing whitespace is gone, newline runs are collapsed, the ends are trimmed.
t.is(strip(once).text, once, 'strip(strip(x).text).text === strip(x).text')
}
})