size: 5 KiB

1-- run tests
2package.path = "./?.lua;" .. package.path
3local djot = require("djot")
4
5local testcases = {
6 "attributes.test",
7 "blockquote.test",
8 "code_blocks.test",
9 "definition_lists.test",
10 "symbol.test",
11 "emphasis.test",
12 "escapes.test",
13 "fenced_divs.test",
14 "filters.test",
15 "footnotes.test",
16 "headings.test",
17 "insert_delete_mark.test",
18 "links_and_images.test",
19 "lists.test",
20 "math.test",
21 "para.test",
22 "raw.test",
23 "regression.test",
24 "smart.test",
25 "spans.test",
26 "sourcepos.test",
27 "super_subscript.test",
28 "tables.test",
29 "task_lists.test",
30 "thematic_breaks.test",
31 "verbatim.test"
32}
33
34local opts = {}
35local i=1
36while i <= #arg do
37 local thisarg = arg[i]
38 if string.find(thisarg, "^%-") then
39 if thisarg == "-v" then
40 opts.verbose = true
41 elseif thisarg == "-p" then
42 opts.pattern = true
43 elseif thisarg == "--accept" then
44 opts.accept = true
45 end
46 elseif opts.pattern == true then
47 opts.pattern = thisarg
48 end
49 i = i + 1
50end
51
52local Tests = {}
53
54function Tests:new()
55 local contents = {
56 passed = 0,
57 failed = 0,
58 errors = 0,
59 accept = opts.accept,
60 verbose = opts.verbose
61 }
62 setmetatable(contents, Tests)
63 Tests.__index = Tests
64 return contents
65end
66
67function Tests:do_test(test)
68 if self.verbose then
69 io.write(string.format("Testing %s at linen %d\n", test.file, test.linenum))
70 end
71 local sourcepos = false
72 if test.options:match("p") then
73 sourcepos = true
74 end
75 local actual = ""
76 if test.options:match("m") then
77 actual = actual .. djot.parse_and_render_events(test.input)
78 else
79 local doc = djot.parse(test.input, sourcepos)
80 for _,filt in ipairs(test.filters) do
81 local f, err = djot.filter.load_filter(filt)
82 if not f then
83 error(err)
84 end
85 djot.filter.apply_filter(doc, f)
86 end
87 if test.options:match("a") then
88 actual = actual .. djot.render_ast_pretty(doc)
89 else -- match 'h' or empty
90 actual = actual .. djot.render_html(doc)
91 end
92 end
93 if self.accept then
94 test.output = actual
95 end
96 if actual == test.output then
97 self.passed = self.passed + 1
98 return true
99 else
100 io.write(string.format("FAILED at %s line %d\n", test.file, test.linenum))
101 io.write(string.format("--- INPUT -------------------------------------\n%s--- EXPECTED ----------------------------------\n%s--- GOT ---------------------------------------\n%s-----------------------------------------------\n\n", test.input, test.output, actual))
102 self.failed = self.failed + 1
103 return false
104 end
105end
106
107local function read_tests(file)
108 local f = io.open("test/" .. file,"r")
109 assert(f ~= nil, "File " .. file .. " cannot be read")
110 local line
111 local linenum = 0
112 return function()
113 while true do
114 local inp = ""
115 local out = ""
116 line = f:read()
117 local pretext = {}
118 linenum = linenum + 1
119 while line and not line:match("^```") do
120 pretext[#pretext + 1] = line
121 line = f:read()
122 linenum = linenum + 1
123 end
124 local testlinenum = linenum
125 if not line then
126 break
127 end
128 local ticks, options = line:match("^(`+)%s*(.*)")
129
130 -- parse input
131 line = f:read()
132 linenum = linenum + 1
133 while not line:match("^[%.%!]$") do
134 inp = inp .. line .. "\n"
135 line = f:read()
136 linenum = linenum + 1
137 end
138
139 local filters = {}
140 while line == "!" do -- parse filter
141 line = f:read()
142 linenum = linenum + 1
143 local filt = ""
144 while not line:match("^[%.%!]$") do
145 filt = filt .. line .. "\n"
146 line = f:read()
147 linenum = linenum + 1
148 end
149 table.insert(filters, filt)
150 end
151
152 -- parse output
153 line = f:read()
154 linenum = linenum + 1
155 while not line:match("^" .. ticks) do
156 out = out .. line .. "\n"
157 line = f:read()
158 linenum = linenum + 1
159 end
160
161 return { file = file,
162 linenum = testlinenum,
163 pretext = table.concat(pretext, "\n"),
164 options = options,
165 filters = filters,
166 input = inp,
167 output = out }
168 end
169 end
170end
171
172function Tests:do_tests(file)
173 local tests = {}
174 for test in read_tests(file) do
175 tests[#tests + 1] = test
176 local ok, err = pcall(function()
177 self:do_test(test)
178 end)
179 if not ok then
180 io.stderr:write(string.format("Error running test %s line %d:\n%s\n",
181 test.file, test.linenum, err))
182 self.errors = self.errors + 1
183 end
184 end
185 if self.accept then -- rewrite file
186 local fh = io.open("test/" .. file, "w")
187 for idx,test in ipairs(tests) do
188 local numticks = 3
189 string.gsub(test.input .. test.output, "(````*)",
190 function(x)
191 if #x >= numticks then
192 numticks = #x + 1
193 end
194 end)
195 local ticks = string.rep("`", numticks)
196 local pretext = test.pretext
197 if #pretext > 0 or idx > 1 then
198 pretext = pretext .. "\n"
199 end
200
201 fh:write(string.format("%s%s%s\n%s",
202 pretext,
203 ticks,
204 (test.options == "" and "") or " " .. test.options,
205 test.input))
206 for _,f in ipairs(test.filters) do
207 fh:write(string.format("!\n%s", f))
208 end
209 fh:write(string.format(".\n%s%s\n", test.output, ticks))
210 end
211 fh:close()
212 end
213end
214
215local tests = Tests:new()
216local starttime = os.clock()
217for _,case in ipairs(testcases) do
218 if not opts.pattern or string.find(case, opts.pattern) then
219 tests:do_tests(case)
220 end
221end
222local endtime = os.clock()
223
224io.write(string.format("%d tests completed in %0.3f s\n",
225 tests.passed + tests.failed + tests.errors, endtime - starttime))
226io.write(string.format("PASSED: %4d\n", tests.passed))
227io.write(string.format("FAILED: %4d\n", tests.failed))
228io.write(string.format("ERRORS: %4d\n", tests.errors))
229os.exit(tests.failed + tests.errors)
230