diff options
Diffstat (limited to 'test/helpers.lua')
| -rw-r--r-- | test/helpers.lua | 318 | 
1 files changed, 302 insertions, 16 deletions
diff --git a/test/helpers.lua b/test/helpers.lua index aef6302da3..efc0e911f1 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -39,15 +39,28 @@ local check_logs_useless_lines = {    ['See README_MISSING_SYSCALL_OR_IOCTL for guidance']=3,  } -local eq = function(exp, act) -  return assert.are.same(exp, act) +local function eq(expected, actual) +  return assert.are.same(expected, actual)  end -local neq = function(exp, act) -  return assert.are_not.same(exp, act) +local function neq(expected, actual) +  return assert.are_not.same(expected, actual)  end -local ok = function(res) +local function ok(res)    return assert.is_true(res)  end +local function matches(pat, actual) +  if nil ~= string.match(actual, pat) then +    return true +  end +  error(string.format('Pattern does not match.\nPattern:\n%s\nActual:\n%s', pat, actual)) +end +-- Expect an error matching pattern `pat`. +local function expect_err(pat, ...) +  local fn = select(1, ...) +  local fn_args = {...} +  table.remove(fn_args, 1) +  assert.error_matches(function() return fn(unpack(fn_args)) end, pat) +end  -- initial_path:  directory to recurse into  -- re:            include pattern (string) @@ -296,6 +309,9 @@ local function repeated_read_cmd(...)  end  local function shallowcopy(orig) +  if type(orig) ~= 'table' then +    return orig +  end    local copy = {}    for orig_key, orig_value in pairs(orig) do      copy[orig_key] = orig_value @@ -303,6 +319,92 @@ local function shallowcopy(orig)    return copy  end +local deepcopy + +local function id(v) +  return v +end + +local deepcopy_funcs = { +  table = function(orig) +    local copy = {} +    for k, v in pairs(orig) do +      copy[deepcopy(k)] = deepcopy(v) +    end +    return copy +  end, +  number = id, +  string = id, +  ['nil'] = id, +  boolean = id, +} + +deepcopy = function(orig) +  return deepcopy_funcs[type(orig)](orig) +end + +local REMOVE_THIS = {} + +local function mergedicts_copy(d1, d2) +  local ret = shallowcopy(d1) +  for k, v in pairs(d2) do +    if d2[k] == REMOVE_THIS then +      ret[k] = nil +    elseif type(d1[k]) == 'table' and type(v) == 'table' then +      ret[k] = mergedicts_copy(d1[k], v) +    else +      ret[k] = v +    end +  end +  return ret +end + +-- dictdiff: find a diff so that mergedicts_copy(d1, diff) is equal to d2 +-- +-- Note: does not do copies of d2 values used. +local function dictdiff(d1, d2) +  local ret = {} +  local hasdiff = false +  for k, v in pairs(d1) do +    if d2[k] == nil then +      hasdiff = true +      ret[k] = REMOVE_THIS +    elseif type(v) == type(d2[k]) then +      if type(v) == 'table' then +        local subdiff = dictdiff(v, d2[k]) +        if subdiff ~= nil then +          hasdiff = true +          ret[k] = subdiff +        end +      elseif v ~= d2[k] then +        ret[k] = d2[k] +        hasdiff = true +      end +    else +      ret[k] = d2[k] +      hasdiff = true +    end +  end +  for k, v in pairs(d2) do +    if d1[k] == nil then +      ret[k] = shallowcopy(v) +      hasdiff = true +    end +  end +  if hasdiff then +    return ret +  else +    return nil +  end +end + +local function updated(d, d2) +  for k, v in pairs(d2) do +    d[k] = v +  end +  return d +end +  local function concat_tables(...)    local ret = {}    for i = 1, select('#', ...) do @@ -339,24 +441,208 @@ local function dedent(str, leave_indent)    return str  end +local function format_float(v) +  -- On windows exponent appears to have three digits and not two +  local ret = ('%.6e'):format(v) +  local l, f, es, e = ret:match('^(%-?%d)%.(%d+)e([+%-])0*(%d%d+)$') +  return l .. '.' .. f .. 'e' .. es .. e +end + +local SUBTBL = { +  '\\000', '\\001', '\\002', '\\003', '\\004', +  '\\005', '\\006', '\\007', '\\008', '\\t', +  '\\n',   '\\011', '\\012', '\\r',   '\\014', +  '\\015', '\\016', '\\017', '\\018', '\\019', +  '\\020', '\\021', '\\022', '\\023', '\\024', +  '\\025', '\\026', '\\027', '\\028', '\\029', +  '\\030', '\\031', +} + +local format_luav + +format_luav = function(v, indent, opts) +  opts = opts or {} +  local linesep = '\n' +  local next_indent_arg = nil +  local indent_shift = opts.indent_shift or '  ' +  local next_indent +  local nl = '\n' +  if indent == nil then +    indent = '' +    linesep = '' +    next_indent = '' +    nl = ' ' +  else +    next_indent_arg = indent .. indent_shift +    next_indent = indent .. indent_shift +  end +  local ret = '' +  if type(v) == 'string' then +    if opts.literal_strings then +      ret = v +    else +      local quote = opts.dquote_strings and '"' or '\'' +      ret = quote .. tostring(v):gsub( +        opts.dquote_strings and '["\\]' or '[\'\\]', +        '\\%0'):gsub( +          '[%z\1-\31]', function(match) +            return SUBTBL[match:byte() + 1] +          end) .. quote +    end +  elseif type(v) == 'table' then +    if v == REMOVE_THIS then +      ret = 'REMOVE_THIS' +    else +      local processed_keys = {} +      ret = '{' .. linesep +      local non_empty = false +      for i, subv in ipairs(v) do +        ret = ('%s%s%s,%s'):format(ret, next_indent, +                                   format_luav(subv, next_indent_arg, opts), nl) +        processed_keys[i] = true +        non_empty = true +      end +      for k, subv in pairs(v) do +        if not processed_keys[k] then +          if type(k) == 'string' and k:match('^[a-zA-Z_][a-zA-Z0-9_]*$') then +            ret = ret .. next_indent .. k .. ' = ' +          else +            ret = ('%s%s[%s] = '):format(ret, next_indent, +                                         format_luav(k, nil, opts)) +          end +          ret = ret .. format_luav(subv, next_indent_arg, opts) .. ',' .. nl +          non_empty = true +        end +      end +      if nl == ' ' and non_empty then +        ret = ret:sub(1, -3) +      end +      ret = ret  .. indent .. '}' +    end +  elseif type(v) == 'number' then +    if v % 1 == 0 then +      ret = ('%d'):format(v) +    else +      ret = format_float(v) +    end +  elseif type(v) == 'nil' then +    ret = 'nil' +  elseif type(v) == 'boolean' then +    ret = (v and 'true' or 'false') +  else +    print(type(v)) +    -- Not implemented yet +    assert(false) +  end +  return ret +end + +local function format_string(fmt, ...) +  local i = 0 +  local args = {...} +  local function getarg() +    i = i + 1 +    return args[i] +  end +  local ret = fmt:gsub('%%[0-9*]*%.?[0-9*]*[cdEefgGiouXxqsr%%]', function(match) +    local subfmt = match:gsub('%*', function() +      return tostring(getarg()) +    end) +    local arg = nil +    if subfmt:sub(-1) ~= '%' then +      arg = getarg() +    end +    if subfmt:sub(-1) == 'r' or subfmt:sub(-1) == 'q' then +      -- %r is like built-in %q, but it is supposed to single-quote strings and +      -- not double-quote them, and also work not only for strings. +      -- Builtin %q is replaced here as it gives invalid and inconsistent with +      -- luajit results for e.g. "\e" on lua: luajit transforms that into `\27`, +      -- lua leaves as-is. +      arg = format_luav(arg, nil, {dquote_strings = (subfmt:sub(-1) == 'q')}) +      subfmt = subfmt:sub(1, -2) .. 's' +    end +    if subfmt == '%e' then +      return format_float(arg) +    else +      return subfmt:format(arg) +    end +  end) +  return ret +end + +local function intchar2lua(ch) +  ch = tonumber(ch) +  return (20 <= ch and ch < 127) and ('%c'):format(ch) or ch +end + +local fixtbl_metatable = { +  __newindex = function() +    assert(false) +  end, +} + +local function fixtbl(tbl) +  return setmetatable(tbl, fixtbl_metatable) +end + +local function fixtbl_rec(tbl) +  for _, v in pairs(tbl) do +    if type(v) == 'table' then +      fixtbl_rec(v) +    end +  end +  return fixtbl(tbl) +end + +-- From https://github.com/premake/premake-core/blob/master/src/base/table.lua +local function table_flatten(arr) +  local result = {} +  local function _table_flatten(_arr) +    local n = #_arr +    for i = 1, n do +      local v = _arr[i] +      if type(v) == "table" then +        _table_flatten(v) +      elseif v then +        table.insert(result, v) +      end +    end +  end +  _table_flatten(arr) +  return result +end +  return { -  eq = eq, -  neq = neq, -  ok = ok, +  REMOVE_THIS = REMOVE_THIS, +  argss_to_cmd = argss_to_cmd, +  check_cores = check_cores,    check_logs = check_logs, -  uname = uname, -  tmpname = tmpname, -  map = map, +  concat_tables = concat_tables, +  dedent = dedent, +  deepcopy = deepcopy, +  dictdiff = dictdiff, +  eq = eq, +  expect_err = expect_err,    filter = filter, +  fixtbl = fixtbl, +  fixtbl_rec = fixtbl_rec, +  format_luav = format_luav, +  format_string = format_string,    glob = glob, -  check_cores = check_cores,    hasenv = hasenv, -  which = which, -  argss_to_cmd = argss_to_cmd, +  intchar2lua = intchar2lua, +  map = map, +  matches = matches, +  mergedicts_copy = mergedicts_copy, +  neq = neq, +  ok = ok,    popen_r = popen_r,    popen_w = popen_w,    repeated_read_cmd = repeated_read_cmd,    shallowcopy = shallowcopy, -  concat_tables = concat_tables, -  dedent = dedent, +  table_flatten = table_flatten, +  tmpname = tmpname, +  uname = uname, +  updated = updated, +  which = which,  }  | 
