diff options
Diffstat (limited to 'Data/BuiltIn/Libraries/lua-stdlib/spec/io_spec.yaml')
-rw-r--r-- | Data/BuiltIn/Libraries/lua-stdlib/spec/io_spec.yaml | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/Data/BuiltIn/Libraries/lua-stdlib/spec/io_spec.yaml b/Data/BuiltIn/Libraries/lua-stdlib/spec/io_spec.yaml new file mode 100644 index 0000000..67b850f --- /dev/null +++ b/Data/BuiltIn/Libraries/lua-stdlib/spec/io_spec.yaml @@ -0,0 +1,439 @@ +# General Lua Libraries for Lua 5.1, 5.2 & 5.3 +# Copyright (C) 2011-2018 stdlib authors + +before: | + base_module = 'io' + this_module = 'std.io' + global_table = '_G' + + extend_base = {'catdir', 'catfile', 'die', 'dirname', + 'process_files', 'readlines', 'shell', 'slurp', + 'splitdir', 'warn', 'writelines'} + + dirsep = string.match(package.config, '^([^\n]+)\n') + + M = require(this_module) + + +specify std.io: +- context when required: + - context by name: + - it does not touch the global table: + expect(show_apis {added_to=global_table, by=this_module}). + to_equal {} + - it does not touch the core io table: + expect(show_apis {added_to=base_module, by=this_module}). + to_equal {} + - it contains apis from the core io table: + expect(show_apis {from=base_module, not_in=this_module}). + to_contain.a_permutation_of(extend_base) + + - context via the std module: + - it does not touch the global table: + expect(show_apis {added_to=global_table, by='std'}). + to_equal {} + - it does not touch the core io table: + expect(show_apis {added_to=base_module, by='std'}). + to_equal {} + + +- describe catdir: + - before: | + f = M.catdir + + - context with bad arguments: + badargs.diagnose(f, 'std.io.catdir(string*)') + + - it treats initial empty string as root directory: + expect(f('')).to_be(dirsep) + expect(f('', '')).to_be(dirsep) + expect(f('', 'root')).to_be(dirsep .. 'root') + - it returns a single argument unchanged: + expect(f('hello')).to_be 'hello' + - it joins multiple arguments with platform directory separator: + expect(f('one', 'two')).to_be('one' .. dirsep .. 'two') + expect(f('1', '2', '3', '4', '5')). + to_be(table.concat({'1', '2', '3', '4', '5'}, dirsep)) + + +- describe catfile: + - before: + f = M.catfile + + - context with bad arguments: + badargs.diagnose(f, 'std.io.catfile(string*)') + + - it treats initial empty string as root directory: + expect(f('', '')).to_be(dirsep) + expect(f('', 'root')).to_be(dirsep .. 'root') + - it returns a single argument unchanged: + expect(f('')).to_be '' + expect(f('hello')).to_be 'hello' + - it joins multiple arguments with platform directory separator: + expect(f('one', 'two')).to_be('one' .. dirsep .. 'two') + expect(f('1', '2', '3', '4', '5')). + to_be(table.concat({'1', '2', '3', '4', '5'}, dirsep)) + + +- describe die: + - before: | + script = [[require 'std.io'.die "By 'eck!"]] + + f = M.die + + - context with bad arguments: + badargs.diagnose(f, 'std.io.die(string, ?any*)') + + - it outputs a message to stderr: | + expect(luaproc(script)).to_fail_while_matching ": By 'eck!\n" + - it ignores `prog.line` without `prog.file` or `prog.name`: | + script = [[prog = {line=125};]] .. script + expect(luaproc(script)).to_fail_while_matching ": By 'eck!\n" + - it ignores `opts.line` without `opts.program`: | + script = [[opts = {line=99};]] .. script + expect(luaproc(script)).to_fail_while_matching ": By 'eck!\n" + - it prefixes `prog.name` if any: | + script = [[prog = {name='name'};]] .. script + expect(luaproc(script)).to_fail_while_matching ": name: By 'eck!\n" + - it appends `prog.line` if any, to `prog.name`: | + script = [[prog = {line=125, name='name'};]] .. script + expect(luaproc(script)).to_fail_while_matching ": name:125: By 'eck!\n" + - it prefixes `prog.file` if any: | + script = [[prog = {file='file'};]] .. script + expect(luaproc(script)).to_fail_while_matching ": file: By 'eck!\n" + - it appends `prog.line` if any, to `prog.name`: | + script = [[prog = {file='file', line=125};]] .. script + expect(luaproc(script)).to_fail_while_matching ": file:125: By 'eck!\n" + - it prefers `prog.name` to `prog.file` or `opts.program`: | + script = [[ + prog = {file='file', name='name'} + opts = {program='program'} + ]] .. script + expect(luaproc(script)).to_fail_while_matching ": name: By 'eck!\n" + - it appends `prog.line` if any to `prog.name` over anything else: | + script = [[ + prog = {file='file', line=125, name='name'} + opts = {line=99, program='program'} + ]] .. script + expect(luaproc(script)).to_fail_while_matching ": name:125: By 'eck!\n" + - it prefers `prog.file` to `opts.program`: | + script = [[ + prog = {file='file'}; opts = {program='program'} + ]] .. script + expect(luaproc(script)).to_fail_while_matching ": file: By 'eck!\n" + - it appends `prog.line` if any to `prog.file` over using `opts`: | + script = [[ + prog = {file='file', line=125} + opts = {line=99, program='program'} + ]] .. script + expect(luaproc(script)).to_fail_while_matching ": file:125: By 'eck!\n" + - it prefixes `opts.program` if any: | + script = [[opts = {program='program'};]] .. script + expect(luaproc(script)).to_fail_while_matching ": program: By 'eck!\n" + - it appends `opts.line` if any, to `opts.program`: | + script = [[opts = {line=99, program='program'};]] .. script + expect(luaproc(script)).to_fail_while_matching ": program:99: By 'eck!\n" + + +- describe dirname: + - before: + f = M.dirname + path = table.concat({'', 'one', 'two', 'three'}, dirsep) + + - context with bad arguments: + badargs.diagnose(f, 'std.io.dirname(string)') + + - it removes final separator and following: + expect(f(path)).to_be(table.concat({'', 'one', 'two'}, dirsep)) + + +- describe process_files: + - before: + name = 'Makefile' + names = {'LICENSE.md', 'Makefile', 'README.md'} + ascript = [[ + require 'std.io'.process_files(function(a) + print(a) + end) + ]] + lscript = [[ + require 'std.io'.process_files('=print(_1)') + ]] + iscript = [[ + require 'std.io'.process_files(function(_, i) + print(i) + end) + ]] + catscript = [[ + require 'std.io'.process_files(function() + io.write(io.input():read '*a') + end) + ]] + + f = M.process_files + + - context with bad arguments: | + badargs.diagnose(f, 'std.io.process_files(func)') + + examples { + ["it diagnoses non-file 'arg' elements"] = function() + expect(luaproc(ascript, 'not-an-existing-file')).to_contain_error.any_of { + "cannot open file 'not-an-existing-file'", -- Lua 5.2 + "bad argument #1 to 'input' (not-an-existing-file:", -- Lua 5.1 + } + end + } + + - it defaults to `-` if no arguments were passed: + expect(luaproc(ascript)).to_output '-\n' + - it iterates over arguments with supplied function: + expect(luaproc(ascript, name)).to_output(name .. '\n') + expect(luaproc(ascript, names)). + to_output(table.concat(names, '\n') .. '\n') + - it passes argument numbers to supplied function: + expect(luaproc(iscript, names)).to_output '1\n2\n3\n' + - it sets each file argument as the default input: + expect(luaproc(catscript, name)).to_output(concat_file_content(name)) + expect(luaproc(catscript, names)). + to_output(concat_file_content(unpack(names))) + - it processes io.stdin if no arguments were passed: + ## FIXME: where does that closing newline come from?? + expect(luaproc(catscript, nil, 'some\nlines\nof input')).to_output 'some\nlines\nof input\n' + - it processes io.stdin for `-` argument: + ## FIXME: where does that closing newline come from?? + expect(luaproc(catscript, '-', 'some\nlines\nof input')).to_output 'some\nlines\nof input\n' + + +- describe readlines: + - before: | + name = 'Makefile' + h = io.open(name) + lines = {} + for l in h:lines() do + lines[#lines + 1] = l + end + h:close() + + defaultin = io.input() + + f, badarg = init(M, this_module, 'readlines') + - after: + if io.type(defaultin) ~= 'closed file' then + io.input(defaultin) + end + + - context with bad arguments: | + badargs.diagnose(f, 'std.io.readlines(?file|string)') + + if have_typecheck then + examples { + ['it diagnoses non-existent file'] = function() + expect(f 'not-an-existing-file'). + to_raise "bad argument #1 to 'std.io.readlines'(" -- system dependent error message + end + } + closed = io.open(name, 'r') closed:close() + examples { + ['it diagnoses closed file argument'] = function() + expect(f(closed)).to_raise(badarg(1, '?file|string', 'closed file')) + end + } + end + + - it closes file handle upon completion: + h = io.open(name) + expect(io.type(h)).not_to_be 'closed file' + f(h) + expect(io.type(h)).to_be 'closed file' + - it reads lines from an existing named file: + expect(f(name)).to_equal(lines) + - it reads lines from an open file handle: + expect(f(io.open(name))).to_equal(lines) + - it reads from default input stream with no arguments: + io.input(name) + expect(f()).to_equal(lines) + + +- describe shell: + - before: + f = M.shell + + - context with bad arguments: + badargs.diagnose(f, 'std.io.shell(string)') + + - it returns the output from a shell command string: + expect(f [[printf '%s\n' 'foo' 'bar']]).to_be 'foo\nbar\n' + + +- describe slurp: + - before: | + name = 'Makefile' + h = io.open(name) + content = h:read '*a' + h:close() + + defaultin = io.input() + f, badarg = init(M, this_module, 'slurp') + - after: + if io.type(defaultin) ~= 'closed file' then + io.input(defaultin) + end + + - context with bad arguments: | + badargs.diagnose(f, 'std.io.slurp(?file|string)') + + if have_typecheck then + examples { + ['it diagnoses non-existent file'] = function() + expect(f 'not-an-existing-file'). + to_raise "bad argument #1 to 'std.io.slurp'(" -- system dependent error message + end + } + closed = io.open(name, 'r') closed:close() + examples { + ['it diagnoses closed file argument'] = function() + expect(f(closed)).to_raise(badarg(1, '?file|string', 'closed file')) + end + } + end + + - it reads content from an existing named file: + expect(f(name)).to_be(content) + - it reads content from an open file handle: + expect(f(io.open(name))).to_be(content) + - it closes file handle upon completion: + h = io.open(name) + expect(io.type(h)).not_to_be 'closed file' + f(h) + expect(io.type(h)).to_be 'closed file' + - it reads from default input stream with no arguments: + io.input(name) + expect(f()).to_be(content) + + +- describe splitdir: + - before: + f = M.splitdir + + - context with bad arguments: + badargs.diagnose(f, 'std.io.splitdir(string)') + + - it returns a filename as a one element list: + expect(f('hello')).to_equal {'hello'} + - it splits root directory in two empty elements: + expect(f(dirsep)).to_equal {'', ''} + - it returns initial empty string for absolute path: + expect(f(dirsep .. 'root')).to_equal {'', 'root'} + - it returns multiple components split at platform directory separator: + expect(f('one' .. dirsep .. 'two')).to_equal {'one', 'two'} + expect(f(table.concat({'1', '2', '3', '4', '5'}, dirsep))). + to_equal {'1', '2', '3', '4', '5'} + + +- describe warn: + - before: + script = [[require 'std.io'.warn 'Ayup!']] + f = M.warn + + - context with bad arguments: + badargs.diagnose(f, 'std.io.warn(string, ?any*)') + + - it outputs a message to stderr: + expect(luaproc(script)).to_output_error 'Ayup!\n' + - it ignores `prog.line` without `prog.file`, `prog.name` or `opts.program`: + script = [[prog = {line=125};]] .. script + expect(luaproc(script)).to_output_error 'Ayup!\n' + - it prefixes `prog.name` if any: | + script = [[prog = {name='name'};]] .. script + expect(luaproc(script)).to_output_error 'name: Ayup!\n' + - it appends `prog.line` if any, to `prog.name`: | + script = [[prog = {line=125, name='name'};]] .. script + expect(luaproc(script)).to_output_error 'name:125: Ayup!\n' + - it prefixes `prog.file` if any: | + script = [[prog = {file='file'};]] .. script + expect(luaproc(script)).to_output_error 'file: Ayup!\n' + - it appends `prog.line` if any, to `prog.name`: | + script = [[prog = {file='file', line=125};]] .. script + expect(luaproc(script)).to_output_error 'file:125: Ayup!\n' + - it prefers `prog.name` to `prog.file` or `opts.program`: | + script = [[ + prog = {file='file', name='name'} + opts = {program='program'} + ]] .. script + expect(luaproc(script)).to_output_error 'name: Ayup!\n' + - it appends `prog.line` if any to `prog.name` over anything else: | + script = [[ + prog = {file='file', line=125, name='name'} + opts = {line=99, program='program'} + ]] .. script + expect(luaproc(script)).to_output_error 'name:125: Ayup!\n' + - it prefers `prog.file` to `opts.program`: | + script = [[ + prog = {file='file'}; opts = {program='program'} + ]] .. script + expect(luaproc(script)).to_output_error 'file: Ayup!\n' + - it appends `prog.line` if any to `prog.file` over using `opts`: | + script = [[ + prog = {file='file', line=125} + opts = {line=99, program='program'} + ]] .. script + expect(luaproc(script)).to_output_error 'file:125: Ayup!\n' + - it prefixes `opts.program` if any: | + script = [[opts = {program='program'};]] .. script + expect(luaproc(script)).to_output_error 'program: Ayup!\n' + - it appends `opts.line` if any, to `opts.program`: | + script = [[opts = {line=99, program='program'};]] .. script + expect(luaproc(script)).to_output_error 'program:99: Ayup!\n' + + +- describe writelines: + - before: | + name = os.tmpname() + h = io.open(name, 'w') + lines = M.readlines(io.open 'Makefile') + + defaultout = io.output() + f, badarg = init(M, this_module, 'writelines') + - after: + if io.type(defaultout) ~= 'closed file' then + io.output(defaultout) + end + h:close() + os.remove(name) + + - context with bad arguments: + - 'it diagnoses argument #1 type not FILE*, string, number or nil': + if have_typecheck then + expect(f(false)).to_raise(badarg(1, '?file|string|number', 'boolean')) + end + - 'it diagnoses argument #2 type not string, number or nil': + if have_typecheck then + expect(f(1, false)).to_raise(badarg(2, 'string|number', 'boolean')) + end + - 'it diagnoses argument #3 type not string, number or nil': + if have_typecheck then + expect(f(1, 2, false)).to_raise(badarg(3, 'string|number', 'boolean')) + end + - it diagnoses closed file argument: | + closed = io.open(name, 'r') closed:close() + if have_typecheck then + expect(f(closed)).to_raise(badarg(1, '?file|string|number', 'closed file')) + end + + - it does not close the file handle upon completion: + expect(io.type(h)).not_to_be 'closed file' + f(h, 'foo') + expect(io.type(h)).not_to_be 'closed file' + - it writes lines to an open file handle: + f(h, unpack(lines)) + h:flush() + expect(M.readlines(io.open(name))).to_equal(lines) + - it accepts number valued arguments: + f(h, 1, 2, 3) + h:flush() + expect(M.readlines(io.open(name))).to_equal {'1', '2', '3'} + - it writes to default output stream with non-file first argument: + io.output(h) + f(unpack(lines)) + h:flush() + expect(M.readlines(io.open(name))).to_equal(lines) |