diff options
Diffstat (limited to 'Data/BuiltIn/Libraries/lua-stdlib/spec/std_spec.yaml')
-rw-r--r-- | Data/BuiltIn/Libraries/lua-stdlib/spec/std_spec.yaml | 444 |
1 files changed, 444 insertions, 0 deletions
diff --git a/Data/BuiltIn/Libraries/lua-stdlib/spec/std_spec.yaml b/Data/BuiltIn/Libraries/lua-stdlib/spec/std_spec.yaml new file mode 100644 index 0000000..b747abf --- /dev/null +++ b/Data/BuiltIn/Libraries/lua-stdlib/spec/std_spec.yaml @@ -0,0 +1,444 @@ +# General Lua Libraries for Lua 5.1, 5.2 & 5.3 +# Copyright (C) 2011-2018 stdlib authors + +before: | + this_module = 'std' + global_table = '_G' + + exported_apis = {'assert', 'elems', 'eval', 'getmetamethod', + 'ielems', 'ipairs', 'npairs', 'pairs', + 'require', 'ripairs', 'rnpairs'} + + -- Tables with iterator metamethods used by various examples. + __pairs = setmetatable({content='a string'}, { + __pairs = function(t) + return function(x, n) + if n < #x.content then + return n+1, string.sub(x.content, n+1, n+1) + end + end, t, 0 + end, + }) + __index = setmetatable({content='a string'}, { + __index = function(t, n) + if n <= #t.content then + return t.content:sub(n, n) + end + end, + __len = function(t) + return #t.content + end, + }) + + M = require(this_module) + M.version = nil -- previous specs may have autoloaded it + + +specify std: +- context when required: + - it does not touch the global table: + expect(show_apis {added_to=global_table, by=this_module}). + to_equal {} + - it exports the documented apis: + t = {} + for k in pairs(M) do + t[#t + 1] = k + end + expect(t).to_contain.a_permutation_of(exported_apis) + +- context when lazy loading: + - it has no submodules on initial load: + for _, v in pairs(M) do + expect(type(v)).not_to_be 'table' + end + - it loads submodules on demand: + lazy = M.math + expect(lazy).to_be(require 'std.math') + - it loads submodule functions on demand: + expect(M.math.round(3.141592)).to_be(3) + +- describe assert: + - before: + f = M.assert + + - context with bad arguments: + badargs.diagnose(f, 'std.assert(?any, ?string, ?any*)') + + - context when it does not trigger: + - it has a truthy initial argument: + expect(f(1)).not_to_raise 'any error' + expect(f(true)).not_to_raise 'any error' + expect(f 'yes').not_to_raise 'any error' + expect(f(false == false)).not_to_raise 'any error' + - it returns the initial argument: + expect(f(1)).to_be(1) + expect(f(true)).to_be(true) + expect(f 'yes').to_be 'yes' + expect(f(false == false)).to_be(true) + - context when it triggers: + - it has a falsey initial argument: + expect(f()).to_raise() + expect(f(false)).to_raise() + expect(f(1 == 0)).to_raise() + - it throws an optional error string: + expect(f(false, 'ah boo')).to_raise 'ah boo' + - it plugs specifiers with string.format: | + expect(f(nil, '%s %d: %q', 'here', 42, 'a string')). + to_raise(string.format('%s %d: %q', 'here', 42, 'a string')) + + +- describe elems: + - before: + f = M.elems + + - context with bad arguments: + badargs.diagnose(f, 'std.elems(table)') + + - it is an iterator over table values: + t = {} + for e in f {'foo', bar='baz', 42} do + t[#t + 1] = e + end + expect(t).to_contain.a_permutation_of {'foo', 'baz', 42} + - it respects __pairs metamethod: | + t = {} + for v in f(__pairs) do + t[#t + 1] = v + end + expect(t). + to_contain.a_permutation_of {'a', ' ', 's', 't', 'r', 'i', 'n', 'g'} + - it works for an empty list: + t = {} + for e in f {} do + t[#t + 1] = e + end + expect(t).to_equal {} + + +- describe eval: + - before: + f = M.eval + + - context with bad arguments: + badargs.diagnose(f, 'std.eval(string)') + + - it diagnoses invalid lua: + # Some internal error when eval tries to call uncompilable '=' code. + expect(f '=').to_raise() + - it evaluates a string of lua code: + expect(f 'math.min(2, 10)').to_be(math.min(2, 10)) + + +- describe getmetamethod: + - before: + f = M.getmetamethod + + - context with bad arguments: + badargs.diagnose(f, 'std.getmetamethod(?any, string)') + + - context with a table: + - before: + method = function() + return 'called' + end + functor = setmetatable({}, {__call=method}) + t = setmetatable({}, { + _type='table', _method=method, _functor=functor, + }) + - it returns nil for missing metamethods: + expect(f(t, 'not a metamethod on t')).to_be(nil) + - it returns nil for non-callable metatable entries: + expect(f(t, '_type')).to_be(nil) + - it returns a method from the metatable: + expect(f(t, '_method')).to_be(method) + expect(f(t, '_method')()).to_be 'called' + - it returns a functor from the metatable: + expect(f(t, '_functor')).to_be(functor) + expect(f(t, '_functor')()).to_be 'called' + + +- describe ielems: + - before: + f = M.ielems + + - context with bad arguments: + badargs.diagnose(f, 'std.ielems(table)') + + - it is an iterator over integer-keyed table values: + t = {} + for e in f {'foo', 42} do + t[#t + 1] = e + end + expect(t).to_equal {'foo', 42} + - it ignores the dictionary part of a table: + t = {} + for e in f {'foo', 42; bar='baz', qux='quux'} do + t[#t + 1] = e + end + expect(t).to_equal {'foo', 42} + - it respects __len metamethod: + t = {} + for v in f(__index) do + t[#t + 1] = v + end + expect(t).to_equal {'a', ' ', 's', 't', 'r', 'i', 'n', 'g'} + - it works for an empty list: + t = {} + for e in f {} do + t[#t + 1] = e + end + expect(t).to_equal {} + + +- describe ipairs: + - before: + f = M.ipairs + + - context with bad arguments: + badargs.diagnose(f, 'std.ipairs(table)') + + - it is an iterator over integer-keyed table values: + t = {} + for i, v in f {'foo', 42} do + t[i] = v + end + expect(t).to_equal {'foo', 42} + - it ignores the dictionary part of a table: + t = {} + for i, v in f {'foo', 42; bar='baz', qux='quux'} do + t[i] = v + end + expect(t).to_equal {'foo', 42} + - it respects __len metamethod: + t = {} + for k, v in f(__index) do + t[k] = v + end + expect(t).to_equal {'a', ' ', 's', 't', 'r', 'i', 'n', 'g'} + - it works for an empty list: + t = {} + for i, v in f {} do + t[i] = v + end + expect(t).to_equal {} + + +- describe npairs: + - before: + f = M.npairs + + - context with bad arguments: + badargs.diagnose(f, 'std.npairs(table)') + + - it is an iterator over integer-keyed table values: + t = {} + for i, v in f {'foo', 42, nil, nil, 'five'} do + t[i] = v + end + expect(t).to_equal {'foo', 42, nil, nil, 'five'} + - it ignores the dictionary part of a table: + t = {} + for i, v in f {'foo', 42, nil, nil, 'five'; bar='baz', qux='quux'} do + t[i] = v + end + expect(t).to_equal {'foo', 42, nil, nil, 'five'} + - it respects __len metamethod: + t = {} + for _, v in f(setmetatable({[2]=false}, {__len=function(self) return 4 end})) do + t[#t + 1] = tostring(v) + end + expect(table.concat(t, ',')).to_be 'nil,false,nil,nil' + - it works for an empty list: + t = {} + for i, v in f {} do + t[i] = v + end + expect(t).to_equal {} + + +- describe pairs: + - before: + f = M.pairs + + - context with bad arguments: + badargs.diagnose(f, 'std.pairs(table)') + + - it is an iterator over all table values: + t = {} + for k, v in f {'foo', bar='baz', 42} do + t[k] = v + end + expect(t).to_equal {'foo', bar='baz', 42} + - it respects __pairs metamethod: | + t = {} + for k, v in f(__pairs) do + t[k] = v + end + expect(t). + to_contain.a_permutation_of {'a', ' ', 's', 't', 'r', 'i', 'n', 'g'} + - it works for an empty list: + t = {} + for k, v in f {} do + t[k] = v + end + expect(t).to_equal {} + + +- describe require: + - before: + f = M.require + + - context with bad arguments: + badargs.diagnose(f, 'std.require(string, ?string, ?string, ?string)') + + - it diagnoses non-existent module: + expect(f('module-not-exists', '', '')).to_raise 'module-not-exists' + - it diagnoses module too old: + expect(f('std', '9999', '9999')). + to_raise "require 'std' with at least version 9999," + - it diagnoses module too new: + expect(f('std', '0', '0')). + to_raise "require 'std' with version less than 0," + - context when the module version is compatible: + - it returns the module table: + expect(f('std', '0', '9999')).to_be(require 'std') + - it places no upper bound by default: + expect(f('std', '0')).to_be(require 'std') + - it places no lower bound by default: + expect(f 'std').to_be(require 'std') + - it uses _VERSION when version field is nil: + expect(luaproc [[ + package.loaded['poop'] = {_VERSION='41.1'} + f = require 'std'.require + print(f('poop', '41', '9999')._VERSION) + ]]).to_succeed_with '41.1\n' + - context with semantic versioning: + - before: + std = require 'std' + ver = std.version + std.version = '1.2.3' + - after: + std.version = ver + - it diagnoses module too old: + expect(f('std', '1.2.4')). + to_raise "require 'std' with at least version 1.2.4," + expect(f('std', '1.3')). + to_raise "require 'std' with at least version 1.3," + expect(f('std', '2.1.2')). + to_raise "require 'std' with at least version 2.1.2," + expect(f('std', '2')). + to_raise "require 'std' with at least version 2," + expect(f('std', '1.2.10')). + to_raise "require 'std' with at least version 1.2.10," + - it diagnoses module too new: + expect(f('std', nil, '1.2.2')). + to_raise "require 'std' with version less than 1.2.2," + expect(f('std', nil, '1.1')). + to_raise "require 'std' with version less than 1.1," + expect(f('std', nil, '1.1.2')). + to_raise "require 'std' with version less than 1.1.2," + expect(f('std', nil, '1')). + to_raise "require 'std' with version less than 1," + - it returns modules with version in range: + expect(f('std')).to_be(std) + expect(f('std', '1')).to_be(std) + expect(f('std', '1.2.3')).to_be(std) + expect(f('std', nil, '2')).to_be(std) + expect(f('std', nil, '1.3')).to_be(std) + expect(f('std', nil, '1.2.10')).to_be(std) + expect(f('std', '1.2.3', '1.2.4')).to_be(std) + - context with several numbers in version string: + - before: + std = require 'std' + ver = std.version + std.version = 'standard library for Lua 5.3 / 41.0.0' + - after: + std.version = ver + - it diagnoses module too old: + expect(f('std', '42')).to_raise() + - it diagnoses module too new: + expect(f('std', nil, '40')).to_raise() + - it returns modules with version in range: + expect(f('std')).to_be(std) + expect(f('std', '1')).to_be(std) + expect(f('std', '41')).to_be(std) + expect(f('std', nil, '42')).to_be(std) + expect(f('std', '41', '42')).to_be(std) + + +- describe ripairs: + - before: + f = M.ripairs + + - context with bad arguments: + badargs.diagnose(f, 'std.ripairs(table)') + + - it returns a function, the table and a number: + fn, t, i = f {1, 2, 3} + expect({type(fn), t, type(i)}).to_equal {'function', {1, 2, 3}, 'number'} + - it iterates over the array part of a table: + t, u = {1, 2, 3; a=4, b=5, c=6}, {} + for i, v in f(t) do + u[i] = v + end + expect(u).to_equal {1, 2, 3} + - it returns elements in reverse order: + t, u = {'one', 'two', 'five'}, {} + for _, v in f(t) do + u[#u + 1] = v + end + expect(u).to_equal {'five', 'two', 'one'} + - it respects __len metamethod: + t = {} + for i, v in f(__index) do + t[i] = v + end + expect(t).to_equal {'a', ' ', 's', 't', 'r', 'i', 'n', 'g'} + t = {} + for _, v in f(__index) do + t[#t + 1] = v + end + expect(t).to_equal {'g', 'n', 'i', 'r', 't', 's', ' ', 'a'} + - it works with the empty list: + t = {} + for k, v in f {} do + t[k] = v + end + expect(t).to_equal {} + + +- describe rnpairs: + - before: + f = M.rnpairs + + - context with bad arguments: + badargs.diagnose(f, 'std.rnpairs(table)') + + - it returns a function, the table and a number: + fn, t, i = f {1, 2, nil, nil, 3} + expect({type(fn), t, type(i)}). + to_equal {'function', {1, 2, nil, nil, 3}, 'number'} + - it iterates over the array part of a table: + t, u = {1, 2, nil, nil, 3; a=4, b=5, c=6}, {} + for i, v in f(t) do + u[i] = v + end + expect(u).to_equal {1, 2, nil, nil, 3} + - it returns elements in reverse order: + t, u, i = {'one', 'two', nil, nil, 'five'}, {}, 1 + for _, v in f(t) do + u[i], i = v, i + 1 + end + expect(u).to_equal {'five', nil, nil, 'two', 'one'} + - it respects __len metamethod: + t = {} + for _, v in f(setmetatable({[2]=false}, {__len=function(self) return 4 end})) do + t[#t + 1] = tostring(v) + end + expect(table.concat(t, ',')).to_be 'nil,nil,false,nil' + - it works with the empty list: + t = {} + for k, v in f {} do + t[k] = v + end + expect(t).to_equal {} |