Commitf01eef5aRecorded20 Jul 2026Repositorysigil-markdown

test: add differential fuzz harness for the markdown parser

Message

Deterministically generates ~16k markup-dense documents and prints the serialized SXML for each. Running it against the pre-optimization parser and the optimized parser yields byte-identical output, corroborating the golden corpus with far wider input coverage than the fixed fixtures.

Changed
 bench/fuzz.sgl | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)
Diff
bench/fuzz.sgladded
@@ -0,0 +1,51 @@
+1
;;; Differential fuzz corpus for (sigil markdown).
+2
;;;
+3
;;; Usage: sigil bench/fuzz.sgl > out.txt
+4
;;;
+5
;;; Deterministically generates many small documents drawn from a
+6
;;; markup-dense alphabet and prints `~s` of (markdown->sxml doc) for each,
+7
;;; one record per line. Run this against the ORIGINAL parser and the
+8
;;; optimized parser and diff the two outputs: any divergence is a
+9
;;; correctness regression the fixed corpus missed. Deterministic (LCG with
+10
;;; a fixed seed), so the two runs are directly comparable.
+11
+12
(import (sigil markdown)
+13
(sigil io)
+14
(sigil string))
+15
+16
;; Alphabet heavy in inline/block markers plus a little prose.
+17
(define alphabet
+18
(list #\a #\b #\space #\* #\_ #\` #\[ #\] #\( #\) #\! #\\ #\#
+19
#\- #\+ #\| #\: #\~ #\. #\1 #\newline #\space #\a #\space))
+20
+21
(define alen (length alphabet))
+22
+23
;; Simple LCG (Numerical Recipes constants); pure, seed threaded explicitly.
+24
(define (lcg-next state)
+25
(modulo (+ (* state 1664525) 1013904223) 4294967296))
+26
+27
(define (nth-char idx)
+28
(list-ref alphabet (modulo idx alen)))
+29
+30
;; Build one document of LEN chars starting from SEED; returns (doc . state).
+31
(define (make-doc seed len)
+32
(let loop ((k 0) (state seed) (chars '()))
+33
(if (>= k len)
+34
(cons (list->string (reverse chars)) state)
+35
(let ((s2 (lcg-next state)))
+36
(loop (+ k 1) s2 (cons (nth-char s2) chars))))))
+37
+38
(define (run seed count max-len)
+39
(let loop ((i 0) (state seed))
+40
(when (< i count)
+41
(let* ((len (+ 1 (modulo state max-len)))
+42
(r (make-doc state len))
+43
(doc (car r))
+44
(state2 (cdr r)))
+45
(println "~s" (markdown->sxml doc))
+46
(loop (+ i 1) (lcg-next state2))))))
+47
+48
;; Several regimes: short markup-dense docs and longer multi-line docs.
+49
(run 12345 5000 40)
+50
(run 987654321 4000 120)
+51
(run 55555 2000 300)