Path: blob/main/contrib/lyaml/spec/spec_helper.lua
178586 views
--[[1LYAML binding for Lua 5.1, 5.2, 5.3 & 5.42Copyright (C) 2013-2022 Gary V. Vaughan3]]45do6local std = require 'specl.std'7local spawn = require 'specl.shell'.spawn8local objdir = spawn('./build-aux/luke --value=objdir').output91011package.path = std.package.normalize(12'./lib/?.lua',13'./lib/?/init.lua',14package.path15)16package.cpath = std.package.normalize(17'./' .. objdir:match("^objdir='(.*)'") .. '/?.so',18'./' .. objdir:match("^objdir='(.*)'") .. '/?.dll',19package.cpath20)21end2223local hell = require 'specl.shell'242526yaml = require 'yaml'2728BOM = string.char(254, 255) -- UTF-16 Byte Order Mark2930-- Allow use of bare 'pack' and 'unpack' even in Lua > 5.2.31pack = table.pack or function(...) return {n = select('#', ...), ...} end32unpack = table.unpack or unpack33list = pack343536function dump(e)37print(std.string.prettytostring(e))38end394041function github_issue(n)42return 'see http://github.com/gvvaughan/lyaml/issues/' .. tostring(n)43end444546-- Output a list of event tables to the given emitter.47function emitevents(emitter, list)48for _, v in ipairs(list) do49if type(v) == 'string' then50ok, msg = emitter.emit {type=v}51elseif type(v) == 'table' then52ok, msg = emitter.emit(v)53else54error 'expected table or string argument'55end5657if not ok then58error(msg)59elseif ok and msg then60return msg61end62end63end646566-- Create a new emitter and send STREAM_START, listed events and STREAM_END.67function emit(list)68local emitter = yaml.emitter()69emitter.emit {type='STREAM_START'}70emitevents(emitter, list)71local _, msg = emitter.emit {type='STREAM_END'}72return msg73end747576-- Create a new parser for STR, and consume the first N events.77function consume(n, str)78local e = yaml.parser(str)79for n = 1, n do80e()81end82return e83end848586-- Return a new table with only elements of T that have keys listed87-- in the following arguments.88function filter(t, ...)89local u = {}90for _, k in ipairs {...} do91u[k] = t[k]92end93return u94end959697function iscallable(x)98return type(x) == 'function' or type((getmetatable(x) or {}).__call) == 'function'99end100101102local function mkscript(code)103local f = os.tmpname()104local h = io.open(f, 'w')105-- TODO: Move this into specl, or expose arguments so that we can106-- turn this on and off based on specl `--coverage` arg.107h:write "pcall(require, 'luacov')"108h:write(code)109h:close()110return f111end112113114-- Allow user override of LUA binary used by hell.spawn, falling115-- back to environment PATH search for 'lua' if nothing else works.116local LUA = os.getenv 'LUA' or 'lua'117118119--- Run some Lua code with the given arguments and input.120-- @string code valid Lua code121-- @tparam[opt={}] string|table arg single argument, or table of122-- arguments for the script invocation.123-- @string[opt] stdin standard input contents for the script process124-- @treturn specl.shell.Process|nil status of resulting process if125-- execution was successful, otherwise nil126function luaproc(code, arg, stdin)127local f = mkscript(code)128if type(arg) ~= 'table' then arg = {arg} end129local cmd = {LUA, f, unpack(arg)}130-- inject env and stdin keys separately to avoid truncating `...` in131-- cmd constructor132cmd.env = { LUA_PATH=package.path, LUA_INIT='', LUA_INIT_5_2='' }133cmd.stdin = stdin134local proc = hell.spawn(cmd)135os.remove(f)136return proc137end138139140local function tabulate_output(code)141local proc = luaproc(code)142if proc.status ~= 0 then return error(proc.errout) end143local r = {}144proc.output:gsub('(%S*)[%s]*',145function(x)146if x ~= '' then r[x] = true end147end)148return r149end150151152--- Show changes to tables wrought by a require statement.153-- There are a few modes to this function, controlled by what named154-- arguments are given. Lists new keys in T1 after `require "import"`:155--156-- show_apis {added_to=T1, by=import}157--158-- @tparam table argt one of the combinations above159-- @treturn table a list of keys according to criteria above160function show_apis(argt)161return tabulate_output([[162local before, after = {}, {}163for k in pairs(]] .. argt.added_to .. [[) do164before[k] = true165end166167local M = require ']] .. argt.by .. [['168for k in pairs(]] .. argt.added_to .. [[) do169after[k] = true170end171172for k in pairs(after) do173if not before[k] then print(k) end174end175]])176end177178179180--[[ ========= ]]--181--[[ Call Spy. ]]--182--[[ ========= ]]--183184185spy = function(fn)186return setmetatable({}, {187__call = function(self, ...)188self[#self + 1] = list(...)189return fn(...)190end,191})192end193194195do196--[[ ================ ]]--197--[[ Custom matchers. ]]--198--[[ ================ ]]--199200local matchers = require 'specl.matchers'201local eqv = require 'specl.std'.operator.eqv202local str = require 'specl.std'.string.tostring203204local Matcher, matchers = matchers.Matcher, matchers.matchers205local concat = table.concat206207208matchers.be_called_with = Matcher {209function(self, actual, expected)210for i,v in ipairs(expected or {}) do211if not eqv(actual[i], v) then212return false213end214end215return true216end,217218actual = 'argmuents',219220format_expect = function(self, expect)221return ' arguments (' .. str(expect) .. '), '222end,223}224225matchers.be_callable = Matcher {226function(self, actual, _)227return iscallable(actual)228end,229230actual = 'callable',231232format_expect = function(self, expect)233return ' callable, '234end,235}236237matchers.be_falsey = Matcher {238function(self, actual, _)239return not actual and true or false240end,241242actual = 'falsey',243244format_expect = function(self, expect)245return ' falsey, '246end,247}248249matchers.be_truthy = Matcher {250function(self, actual, _)251return actual and true or false252end,253254actual = 'truthy',255256format_expect = function(self, expect)257return ' truthy, '258end,259}260261matchers.have_type = Matcher {262function(self, actual, expected)263return type(actual) == expected or (getmetatable(actual) or {})._type == expected264end,265266actual = 'type',267268format_expect = function(self, expect)269local article = 'a'270if match(expect, '^[aehiou]') then271article = 'an'272end273return concat{' ', article, ' ', expect, ', '}274end275}276end277278279