diff options
Diffstat (limited to 'spec/util/quick.lua')
| -rw-r--r-- | spec/util/quick.lua | 106 |
1 files changed, 73 insertions, 33 deletions
diff --git a/spec/util/quick.lua b/spec/util/quick.lua index c8bfb61a..1fcf2b36 100644 --- a/spec/util/quick.lua +++ b/spec/util/quick.lua | |||
| @@ -37,7 +37,7 @@ local function is_hr(line) | |||
| 37 | end | 37 | end |
| 38 | 38 | ||
| 39 | local function parse(filename) | 39 | local function parse(filename) |
| 40 | local fd = assert(io.open(filename, "r")) | 40 | local fd = assert(io.open(filename, "rb")) |
| 41 | local input = assert(fd:read("*a")) | 41 | local input = assert(fd:read("*a")) |
| 42 | fd:close() | 42 | fd:close() |
| 43 | 43 | ||
| @@ -67,11 +67,27 @@ local function parse(filename) | |||
| 67 | os.exit(1) | 67 | os.exit(1) |
| 68 | end | 68 | end |
| 69 | 69 | ||
| 70 | local function bool_arg(cmd, cur_block, field, arg) | 70 | local function bool_arg(cmd, cur, field, arg) |
| 71 | if arg ~= "true" and arg ~= "false" then | 71 | if arg ~= "true" and arg ~= "false" then |
| 72 | fail(cmd .. " argument must be 'true' or 'false'") | 72 | fail(cmd .. " argument must be 'true' or 'false'") |
| 73 | end | 73 | end |
| 74 | cur_block[field] = (arg == "true") | 74 | cur[field] = (arg == "true") |
| 75 | end | ||
| 76 | |||
| 77 | local function block_start_arg(cmd, cur, field) | ||
| 78 | if not cur or cur.op ~= "RUN" then | ||
| 79 | fail(cmd .. " must be given in the context of a RUN") | ||
| 80 | end | ||
| 81 | if cur[field] then | ||
| 82 | fail(cmd .. " was already declared") | ||
| 83 | end | ||
| 84 | |||
| 85 | cur[field] = { | ||
| 86 | data = {} | ||
| 87 | } | ||
| 88 | cur_block = cur[field] | ||
| 89 | cur_block_name = cmd | ||
| 90 | table.insert(stack, "block start") | ||
| 75 | end | 91 | end |
| 76 | 92 | ||
| 77 | local test_env = require("spec.util.test_env") | 93 | local test_env = require("spec.util.test_env") |
| @@ -109,7 +125,11 @@ local function parse(filename) | |||
| 109 | end)) | 125 | end)) |
| 110 | end | 126 | end |
| 111 | 127 | ||
| 112 | for line in input:gmatch("[^\n]*") do | 128 | if input:sub(#input, #input) ~= "\n" then |
| 129 | input = input .. "\n" | ||
| 130 | end | ||
| 131 | |||
| 132 | for line in input:gmatch("([^\r\n]*)\r?\n?") do | ||
| 113 | cur_line = cur_line + 1 | 133 | cur_line = cur_line + 1 |
| 114 | 134 | ||
| 115 | local state = stack[#stack] | 135 | local state = stack[#stack] |
| @@ -182,34 +202,20 @@ local function parse(filename) | |||
| 182 | 202 | ||
| 183 | cur_op.exit = code | 203 | cur_op.exit = code |
| 184 | cur_op.exit_line = cur_line | 204 | cur_op.exit_line = cur_line |
| 185 | elseif cmd == "STDERR" then | 205 | elseif cmd == "VERBOSE" then |
| 186 | if not cur_op or cur_op.op ~= "RUN" then | 206 | if not cur_op or cur_op.op ~= "RUN" then |
| 187 | fail("STDERR must be given in the context of a RUN") | 207 | fail("VERBOSE must be given in the context of a RUN") |
| 188 | end | ||
| 189 | if cur_op.stderr then | ||
| 190 | fail("STDERR was already declared") | ||
| 191 | end | 208 | end |
| 192 | 209 | ||
| 193 | cur_op.stderr = { | 210 | bool_arg("VERBOSE", cur_op, "verbose", arg) |
| 194 | data = {} | 211 | elseif cmd == "STDERR" then |
| 195 | } | 212 | block_start_arg("STDERR", cur_op, "stderr") |
| 196 | cur_block = cur_op.stderr | 213 | elseif cmd == "NOT_STDERR" then |
| 197 | cur_block_name = "STDERR" | 214 | block_start_arg("NOT_STDERR", cur_op, "not_stderr") |
| 198 | table.insert(stack, "block start") | ||
| 199 | elseif cmd == "STDOUT" then | 215 | elseif cmd == "STDOUT" then |
| 200 | if not cur_op or cur_op.op ~= "RUN" then | 216 | block_start_arg("STDOUT", cur_op, "stdout") |
| 201 | fail("STDOUT must be given in the context of a RUN") | 217 | elseif cmd == "NOT_STDOUT" then |
| 202 | end | 218 | block_start_arg("NOT_STDOUT", cur_op, "not_stdout") |
| 203 | if cur_op.stdout then | ||
| 204 | fail("STDOUT was already declared") | ||
| 205 | end | ||
| 206 | |||
| 207 | cur_op.stdout = { | ||
| 208 | data = {} | ||
| 209 | } | ||
| 210 | cur_block = cur_op.stdout | ||
| 211 | cur_block_name = "STDOUT" | ||
| 212 | table.insert(stack, "block start") | ||
| 213 | elseif cmd == "TEST" then | 219 | elseif cmd == "TEST" then |
| 214 | table.remove(stack) | 220 | table.remove(stack) |
| 215 | start_test(arg) | 221 | start_test(arg) |
| @@ -298,7 +304,7 @@ function quick.compile(filename, env) | |||
| 298 | write([=[ end ]=]) | 304 | write([=[ end ]=]) |
| 299 | for _, op in ipairs(t.ops) do | 305 | for _, op in ipairs(t.ops) do |
| 300 | if op.op == "FILE" then | 306 | if op.op == "FILE" then |
| 301 | write([=[ test_env.write_file(handle_tmpdir("]=], op.name, [=["), handle_tmpdir([=====[ ]=]) | 307 | write(([=[ test_env.write_file(handle_tmpdir(%q), handle_tmpdir([=====[ ]=]):format(op.name)) |
| 302 | for _, line in ipairs(op.data) do | 308 | for _, line in ipairs(op.data) do |
| 303 | write(line) | 309 | write(line) |
| 304 | end | 310 | end |
| @@ -324,7 +330,7 @@ function quick.compile(filename, env) | |||
| 324 | write(([=[ local ok, _, code = os.execute(%s .. " " .. %q .. %q) ]=]):format(cmd_helper, op.args, redirs)) | 330 | write(([=[ local ok, _, code = os.execute(%s .. " " .. %q .. %q) ]=]):format(cmd_helper, op.args, redirs)) |
| 325 | write([=[ if type(ok) == "number" then code = (ok >= 256 and ok / 256 or ok) end ]=]) | 331 | write([=[ if type(ok) == "number" then code = (ok >= 256 and ok / 256 or ok) end ]=]) |
| 326 | 332 | ||
| 327 | write([=[ local fd_stderr = assert(io.open("stderr.txt", "r")) ]=]) | 333 | write([=[ local fd_stderr = assert(io.open("stderr.txt", "rb")) ]=]) |
| 328 | write([=[ local stderr_data = fd_stderr:read("*a") ]=]) | 334 | write([=[ local stderr_data = fd_stderr:read("*a") ]=]) |
| 329 | write([=[ fd_stderr:close() ]=]) | 335 | write([=[ fd_stderr:close() ]=]) |
| 330 | 336 | ||
| @@ -332,23 +338,46 @@ function quick.compile(filename, env) | |||
| 332 | write(([=[ assert(false, error_message(%d, "RUN crashed: ", stderr_data)) ]=]):format(op.line)) | 338 | write(([=[ assert(false, error_message(%d, "RUN crashed: ", stderr_data)) ]=]):format(op.line)) |
| 333 | write([=[ end ]=]) | 339 | write([=[ end ]=]) |
| 334 | 340 | ||
| 335 | if op.stdout then | 341 | if op.stdout or op.not_stdout or op.verbose then |
| 336 | write([=[ local fd_stdout = assert(io.open("stdout.txt", "r")) ]=]) | 342 | write([=[ local fd_stdout = assert(io.open("stdout.txt", "rb")) ]=]) |
| 337 | write([=[ local stdout_data = fd_stdout:read("*a") ]=]) | 343 | write([=[ local stdout_data = fd_stdout:read("*a") ]=]) |
| 338 | write([=[ fd_stdout:close() ]=]) | 344 | write([=[ fd_stdout:close() ]=]) |
| 345 | end | ||
| 346 | |||
| 347 | if op.verbose then | ||
| 348 | write([=[ print() ]=]) | ||
| 349 | write([=[ print("STDOUT: --" .. ("-"):rep(70)) ]=]) | ||
| 350 | write([=[ print(stdout_data) ]=]) | ||
| 351 | write([=[ print("STDERR: --" .. ("-"):rep(70)) ]=]) | ||
| 352 | write([=[ print(stderr_data) ]=]) | ||
| 353 | write([=[ print(("-"):rep(80)) ]=]) | ||
| 354 | write([=[ print() ]=]) | ||
| 355 | end | ||
| 339 | 356 | ||
| 357 | if op.stdout then | ||
| 340 | write([=[ do ]=]) | 358 | write([=[ do ]=]) |
| 341 | write([=[ local block_at = 1 ]=]) | 359 | write([=[ local block_at = 1 ]=]) |
| 342 | write([=[ local s, e, line ]=]) | 360 | write([=[ local s, e, line ]=]) |
| 343 | for i, line in ipairs(op.stdout.data) do | 361 | for i, line in ipairs(op.stdout.data) do |
| 344 | write(([=[ line = %q ]=]):format(line)) | 362 | write(([=[ line = %q ]=]):format(line)) |
| 345 | write(([=[ s, e = string.find(stdout_data, line, block_at, true) ]=])) | 363 | write(([=[ s, e = string.find(stdout_data, line, 1, true) ]=])) |
| 346 | write(([=[ assert(s, error_message(%d, "STDOUT did not match: " .. line, stdout_data)) ]=]):format(op.stdout.start + i)) | 364 | write(([=[ assert(s, error_message(%d, "STDOUT did not match: " .. line, stdout_data)) ]=]):format(op.stdout.start + i)) |
| 347 | write(([=[ block_at = e + 1 ]=]):format(i)) | 365 | write(([=[ block_at = e + 1 ]=]):format(i)) |
| 348 | end | 366 | end |
| 349 | write([=[ end ]=]) | 367 | write([=[ end ]=]) |
| 350 | end | 368 | end |
| 351 | 369 | ||
| 370 | if op.not_stdout then | ||
| 371 | write([=[ do ]=]) | ||
| 372 | write([=[ local line ]=]) | ||
| 373 | for i, line in ipairs(op.not_stdout.data) do | ||
| 374 | write(([=[ line = %q ]=]):format(line)) | ||
| 375 | write(([=[ s = string.find(stdout_data, line, 1, true) ]=])) | ||
| 376 | write(([=[ assert(not s, error_message(%d, "NOT_STDOUT did match unwanted output: " .. line, stdout_data)) ]=]):format(op.stdout.start + i)) | ||
| 377 | end | ||
| 378 | write([=[ end ]=]) | ||
| 379 | end | ||
| 380 | |||
| 352 | if op.stderr then | 381 | if op.stderr then |
| 353 | write([=[ do ]=]) | 382 | write([=[ do ]=]) |
| 354 | write([=[ local block_at = 1 ]=]) | 383 | write([=[ local block_at = 1 ]=]) |
| @@ -362,6 +391,17 @@ function quick.compile(filename, env) | |||
| 362 | write([=[ end ]=]) | 391 | write([=[ end ]=]) |
| 363 | end | 392 | end |
| 364 | 393 | ||
| 394 | if op.not_stderr then | ||
| 395 | write([=[ do ]=]) | ||
| 396 | write([=[ local line ]=]) | ||
| 397 | for i, line in ipairs(op.not_stderr.data) do | ||
| 398 | write(([=[ line = %q ]=]):format(line)) | ||
| 399 | write(([=[ s = string.find(stderr_data, line, block_at, true) ]=])) | ||
| 400 | write(([=[ assert(not s, error_message(%d, "NOT_STDERR did match unwanted output: " .. line, stderr_data)) ]=]):format(op.stderr.start + i)) | ||
| 401 | end | ||
| 402 | write([=[ end ]=]) | ||
| 403 | end | ||
| 404 | |||
| 365 | if op.exit then | 405 | if op.exit then |
| 366 | write(([=[ assert.same(%d, code, error_message(%d, "EXIT did not match: " .. %d, stderr_data)) ]=]):format(op.exit, op.exit_line, op.exit)) | 406 | write(([=[ assert.same(%d, code, error_message(%d, "EXIT did not match: " .. %d, stderr_data)) ]=]):format(op.exit, op.exit_line, op.exit)) |
| 367 | end | 407 | end |
