size: 2 KiB
| 1 | local djot = require("djot") |
| 2 | local to_html = function(s) |
| 3 | local doc = djot.parse(s) |
| 4 | return djot.render_html(doc) |
| 5 | end |
| 6 | local signal = require("posix.signal") |
| 7 | local resource = require("posix.sys.resource") |
| 8 | local times = require 'posix.sys.times'.times |
| 9 | |
| 10 | -- if you want to be able to interrupt stuck fuzz tests. |
| 11 | |
| 12 | math.randomseed(os.time()) |
| 13 | |
| 14 | local MAXLINES = 5 |
| 15 | local MAXLENGTH = 5 |
| 16 | local NUMTESTS = arg[1] or 200000 |
| 17 | |
| 18 | local activechars = { |
| 19 | '\t', ' ', '[', ']', '1', '2', 'a', 'b', |
| 20 | 'A', 'B', 'I', 'V', 'i', 'v', '.', ')', '(', |
| 21 | '{', '}', '=', '+', '_', '-', '*', '!', '>', |
| 22 | '<', '`', '~' |
| 23 | } |
| 24 | |
| 25 | local function randomstring() |
| 26 | local numlines = math.random(1,MAXLINES) |
| 27 | local buffer = {} |
| 28 | for j=1,numlines do |
| 29 | -- -1 to privilege blank lines |
| 30 | local res = "" |
| 31 | local len = math.random(-1,MAXLENGTH) |
| 32 | if len < 0 then len = 0 end |
| 33 | for i=1,len do |
| 34 | local charclass = math.random(1, 4) |
| 35 | if charclass < 4 then |
| 36 | res = res .. activechars[math.random(1, #activechars)] |
| 37 | elseif utf8 then |
| 38 | res = res .. utf8.char(math.random(1, 200)) |
| 39 | else |
| 40 | res = res .. string.char(math.random(1, 127)) |
| 41 | end |
| 42 | end |
| 43 | buffer[#buffer + 1] = res |
| 44 | end |
| 45 | local res = table.concat(buffer, "\n") |
| 46 | return res |
| 47 | end |
| 48 | |
| 49 | local failures = 0 |
| 50 | |
| 51 | io.stderr:write("Running fuzz tests: ") |
| 52 | for i=1,NUMTESTS do |
| 53 | local s = randomstring() |
| 54 | if i % 1000 == 0 then |
| 55 | io.stderr:write("."); |
| 56 | end |
| 57 | local ok, err = pcall(function () |
| 58 | signal.signal(signal.SIGINT, function(signum) |
| 59 | io.stderr:write(string.format("\nInterrupted processing on input %q\n", s)) |
| 60 | io.stderr:flush() |
| 61 | os.exit(128 + signum) |
| 62 | end) |
| 63 | return to_html(s) |
| 64 | end) |
| 65 | if not ok then |
| 66 | -- try to minimize case |
| 67 | local minimal = false |
| 68 | local trim_from_front = true |
| 69 | while not minimal do |
| 70 | local s2 |
| 71 | if trim_from_front then |
| 72 | s2 = string.sub(s, 2, -1) |
| 73 | else |
| 74 | s2 = string.sub(s, 1, -2) |
| 75 | end |
| 76 | local ok2, _ = pcall(function () return to_html(s2) end) |
| 77 | if ok2 then |
| 78 | if trim_from_front then |
| 79 | trim_from_front = false |
| 80 | else |
| 81 | minimal = true |
| 82 | end |
| 83 | else |
| 84 | s = s2 |
| 85 | end |
| 86 | end |
| 87 | failures = failures + 1 |
| 88 | io.stderr:write(string.format("\nFAILURE on\n%q\n", s)) |
| 89 | io.stderr:write(err .. "\n") |
| 90 | end |
| 91 | end |
| 92 | |
| 93 | io.stderr:write("\n") |
| 94 | os.exit(failures) |
| 95 |