From 13b83a3ea2f7c03fdd307eb746d784b41ee43da2 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 15 Jan 2024 21:14:32 +0000 Subject: [PATCH] test: move format_{string,luav} to a separate module --- test/format_string.lua | 168 ++++++++++++++++++++ test/functional/api/vim_spec.lua | 2 +- test/functional/shada/merging_spec.lua | 2 +- test/helpers.lua | 166 +------------------ test/unit/viml/expressions/parser_spec.lua | 4 +- test/unit/viml/expressions/parser_tests.lua | 4 +- 6 files changed, 175 insertions(+), 171 deletions(-) create mode 100644 test/format_string.lua diff --git a/test/format_string.lua b/test/format_string.lua new file mode 100644 index 0000000000..777fb652e8 --- /dev/null +++ b/test/format_string.lua @@ -0,0 +1,168 @@ +local luaassert = require('luassert') + +local M = {} + +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', +} + +--- @param v any +--- @return string +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 + +-- Formats Lua value `v`. +-- +-- TODO(justinmk): redundant with vim.inspect() ? +-- +-- "Nice table formatting similar to screen:snapshot_util()". +-- Commit: 520c0b91a528 +function M.format_luav(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 == vim.NIL then + ret = 'REMOVE_THIS' + else + local processed_keys = {} + ret = '{' .. linesep + local non_empty = false + local format_luav = M.format_luav + 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 + luaassert(false) + end + return ret +end + +-- Like Python repr(), "{!r}".format(s) +-- +-- Commit: 520c0b91a528 +function M.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 = M.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 + +return M diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index fb10ed34e5..91f61b5053 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -34,7 +34,7 @@ local insert = helpers.insert local skip = helpers.skip local pcall_err = helpers.pcall_err -local format_string = helpers.format_string +local format_string = require('test.format_string').format_string local intchar2lua = helpers.intchar2lua local mergedicts_copy = helpers.mergedicts_copy local endswith = vim.endswith diff --git a/test/functional/shada/merging_spec.lua b/test/functional/shada/merging_spec.lua index 94e0ee6e82..1b5c0eab5d 100644 --- a/test/functional/shada/merging_spec.lua +++ b/test/functional/shada/merging_spec.lua @@ -525,7 +525,7 @@ describe('ShaDa marks support code', function() local found = 0 for _, v in ipairs(read_shada_file(shada_fname)) do if v.type == 7 and v.value.f == mock_file_path .. '-' then - print(require('test.helpers').format_luav(v)) + print(require('test.format_string').format_luav(v)) found = found + 1 end end diff --git a/test/helpers.lua b/test/helpers.lua index 1e9160f543..47d93d8206 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -18,7 +18,6 @@ end --- @class test.helpers local module = { - REMOVE_THIS = {}, paths = Paths, } @@ -537,7 +536,7 @@ end function module.mergedicts_copy(d1, d2) local ret = module.shallowcopy(d1) for k, v in pairs(d2) do - if d2[k] == module.REMOVE_THIS then + if d2[k] == vim.NIL then ret[k] = nil elseif type(d1[k]) == 'table' and type(v) == 'table' then ret[k] = module.mergedicts_copy(d1[k], v) @@ -559,7 +558,7 @@ function module.dictdiff(d1, d2) for k, v in pairs(d1) do if d2[k] == nil then hasdiff = true - ret[k] = module.REMOVE_THIS + ret[k] = vim.NIL elseif type(v) == type(d2[k]) then if type(v) == 'table' then local subdiff = module.dictdiff(v, d2[k]) @@ -633,167 +632,6 @@ function module.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', -} - --- Formats Lua value `v`. --- --- TODO(justinmk): redundant with vim.inspect() ? --- --- "Nice table formatting similar to screen:snapshot_util()". --- Commit: 520c0b91a528 -function module.format_luav(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 == module.REMOVE_THIS then - ret = 'REMOVE_THIS' - else - local processed_keys = {} - ret = '{' .. linesep - local non_empty = false - local format_luav = module.format_luav - 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 - luaassert(false) - end - return ret -end - --- Like Python repr(), "{!r}".format(s) --- --- Commit: 520c0b91a528 -function module.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 = module.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 - function module.intchar2lua(ch) ch = tonumber(ch) return (20 <= ch and ch < 127) and ('%c'):format(ch) or ch diff --git a/test/unit/viml/expressions/parser_spec.lua b/test/unit/viml/expressions/parser_spec.lua index ae12136a5c..c7d3f8532f 100644 --- a/test/unit/viml/expressions/parser_spec.lua +++ b/test/unit/viml/expressions/parser_spec.lua @@ -14,8 +14,8 @@ local ffi = helpers.ffi local neq = helpers.neq local eq = helpers.eq local mergedicts_copy = helpers.mergedicts_copy -local format_string = helpers.format_string -local format_luav = helpers.format_luav +local format_string = require('test.format_string').format_string +local format_luav = require('test.format_string').format_luav local intchar2lua = helpers.intchar2lua local dictdiff = helpers.dictdiff diff --git a/test/unit/viml/expressions/parser_tests.lua b/test/unit/viml/expressions/parser_tests.lua index a10e1098b5..aa2bf740de 100644 --- a/test/unit/viml/expressions/parser_tests.lua +++ b/test/unit/viml/expressions/parser_tests.lua @@ -1,6 +1,4 @@ -local global_helpers = require('test.helpers') - -local REMOVE_THIS = global_helpers.REMOVE_THIS +local REMOVE_THIS = vim.NIL return function(itp, _check_parsing, hl, fmtn) local function check_parsing(...)