1
0
pretty/test/test_function.lua
Jon Michael Aanes 155c877987 Alternative process for determining short tables
This one is based on the representative width of the table. Not only
does this produce better results, but it's also more futureproof.
2017-04-14 12:19:23 +02:00

387 lines
13 KiB
Lua

local SUITE = require('TestSuite').new('function')
SUITE:setEnviroment{
format = require('pretty')
}
--------------------------------------------------------------------------------
local HAS_ADV_GETLOCAL = not not debug.getinfo(1, 'u').nparams -- Lua 5.1 compat
if not loadstring then loadstring = load end -- Lua 5.3 compat
local function format_test (t)
if t.longterm then return end
if t.adv_getlocal and not HAS_ADV_GETLOCAL then return end
SUITE:addTest(t.name or t.expect, function ()
local input_value = t.input
local input_options = t.options
local expected_result = t.expect
local actual_result = format(input_value, input_options)
if not t.approx or type(actual_result) ~= 'string' then
assert_equal(expected_result, actual_result)
else
if not actual_result:match(expected_result) then
error(ASSERT_ERROR_APPROX:format(expected_result, actual_result))
end
end
end, { line = debug.getinfo(2).currentline })
end
local function curline (delta)
return debug.getinfo(2).currentline + (delta or 0)
end
--------------------------------------------------------------------------------
-- Function printing
format_test {
adv_getlocal = true,
input = function () end,
expect = 'function () ... end',
}
format_test {
adv_getlocal = true,
input = function (a) end,
expect = 'function (a) ... end',
}
format_test {
adv_getlocal = true,
input = function (a, b) end,
expect = 'function (a, b) ... end',
}
format_test {
adv_getlocal = true,
input = function (...) end,
expect = 'function (...) ... end',
}
format_test {
adv_getlocal = true,
input = function (a, b, ...) end,
expect = 'function (a, b, ...) ... end',
}
do
local SOME_RANDOM_UPVALUE = false
format_test {
adv_getlocal = true,
input = function () l = SOME_RANDOM_UPVALUE end,
expect = 'function () ... end',
}
format_test {
adv_getlocal = true,
input = function () SOME_RANDOM_UPVALUE = true end,
expect = 'function () ... end',
}
format_test {
-- More function info is ignored if not at depth 0.
adv_getlocal = true,
input = { a = function () SOME_RANDOM_UPVALUE = true end },
options = { more_function_info = true },
expect = '{ a = function () ... end }',
}
local func_line = curline(2) -- Must be exactly 2 lines above function
format_test {
input = function () l = SOME_RANDOM_UPVALUE end,
adv_getlocal = true,
options = { more_function_info = true },
expect = 'function ()\n\t-- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n\t-- up_values: { SOME_RANDOM_UPVALUE = false }\n\n\t...\nend'
}
local func_line = curline(2) -- Must be exactly 2 lines above function
format_test {
input = function () SOME_RANDOM_UPVALUE = true end,
adv_getlocal = true,
options = { more_function_info = true },
expect = 'function ()\n\t-- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n\t-- up_values: { SOME_RANDOM_UPVALUE = false }\n\n\t...\nend'
}
end
do
local func_line = curline(2) -- Must be exactly 2 lines above function
format_test {
input = function () end,
adv_getlocal = true,
options = { more_function_info = true },
expect = 'function ()\n\t-- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n\n\t...\nend'
}
end
do
local index = 0
format_test {
input = function () index = index + 1; return index end,
adv_getlocal = true,
expect = 'function () ... end'
}
local func_line = curline(2) -- Must be exactly 2 lines above function
format_test {
input = function () index = index + 1; return index end,
adv_getlocal = true,
options = { more_function_info = true },
expect = 'function ()\n\t-- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n\t-- up_values: { index = 0 }\n\n\t...\nend'
}
end
format_test {
adv_getlocal = true,
input = loadstring('return function () end')(),
expect = 'function () end',
}
format_test {
adv_getlocal = true,
input = loadstring('return function () return function () end end')(),
expect = 'function () return function () end end',
}
format_test {
adv_getlocal = true,
input = loadstring('return function () return function () end\nend')()(),
expect = 'function () end',
}
format_test {
-- NOTE: This is HARD to fix. It's thus longerterm
adv_getlocal = true,
input = loadstring('return function () return function () end end')()(),
expect = 'function () end',
}
format_test {
-- More function info allows one to even get the function whole, if it was defined in a string.
input = loadstring('return function (a, b) return a + b end')(),
options = { more_function_info = true },
expect = 'function (a, b) return a + b end',
}
format_test {
-- More function info allows one to even get the function whole, if it was defined in a string.
input = loadstring('return function (a, b)\n\treturn a + b\nend')(),
options = { more_function_info = true },
expect = 'function (a, b)\n\treturn a + b\nend',
}
do
local func_line = curline(2) -- Must be exactly 2 lines above function
format_test {
input = function ()
-- NOTE: This function must cover 3 lines of code!
end,
adv_getlocal = true,
options = { more_function_info = true },
expect = 'function ()\n\t-- source_file: \'./test/test_function.lua\' [Lines: '..func_line..' - '..(func_line+2)..']\n\n\t...\nend',
}
local func_line = curline(2) -- Must be exactly 2 lines above function
format_test {
input = function () --[[ NOTE: This function must cover a single line of code! ]] end,
adv_getlocal = true,
options = { more_function_info = true },
expect = 'function ()\n\t-- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n\n\t...\nend',
}
end
format_test {
input = math.abs,
expect = 'builtin function (x) ... end',
}
format_test {
input = math.abs,
options = { more_function_info = true },
expect = 'builtin function (x)\n\t-- math.abs\n\t-- Returns the absolute value of x.\n\n\t...\nend',
}
format_test {
input = math.random,
expect = 'builtin function ([m [, n]) ... end',
}
format_test {
input = math.random,
options = { more_function_info = true },
expect = 'builtin function ([m [, n])\n\t-- math.random\n\t-- When called without arguments, returns a uniform pseudo-random real number in the range [0,1). When called with an integer number m, math.random returns a uniform pseudo-random integer in the range [1, m]. When called with two integer numbers m and n, math.random returns a uniform pseudo-random integer in the range [m, n].\n\n\t...\nend',
}
format_test {
input = string.byte,
options = { more_function_info = true },
expect = 'builtin function (s [, i [, j]])\n\t-- string.byte\n\t-- Returns the internal numerical codes of the characters s[i], s[i+1], ..., s[j]. The default value for i is 1; the default value for j is i.\n\t-- Note that numerical codes are not necessarily portable across platforms.\n\n\t...\nend',
}
-- short_builtins option: If an builtin is expected to be available by some name
-- in a standard enviroment, return that name, instead of other complex info.
format_test {
input = math.random,
options = { short_builtins = true },
expect = 'math.random',
}
format_test {
input = { math.cos, math.sin, math.abs },
options = { short_builtins = true },
expect = '{ math.cos, math.sin, math.abs }',
}
--------------------------------------------------------------------------------
-- Closure creation
-- include_closure option: If a function uses upvalues, return code that creates
-- a closure for that function, including the function code.
-- NOTE: Without AST traversal, it's impossible to garentee that values refered
-- by multiple recursive closures are the same, because they can actually refer
-- to different variables with the same name, as the following example shows:
--
-- local val_a = 1
-- local func_a = function () return val_a end
-- local val_a = 2
-- local func_c = function () return func_a() + val_a end
do
format_test {
adv_getlocal = true,
options = { more_function_info = true, include_closure = true },
input = function (a, b) return (a > b) and a or b end,
expect = 'function (a, b) return (a > b) and a or b end',
}
end
do
local input_func = (function ()
local i = 0
return function (a) i = i + a; return i end
end)()
for i = 1, 10 do input_func(1) end
format_test {
adv_getlocal = true,
options = { more_function_info = true, include_closure = true },
input = input_func,
expect = '(function () local i = 10; return function (a) i = i + a; return i end end)()',
}
end
do
local input_func = loadstring([[
return function ()
local i = 0
return function (a) i = i + a; return i end
end]])()()
for i = 1, 10 do input_func(1) end
format_test {
name = 'Can include variables in closure',
adv_getlocal = true,
options = { more_function_info = true, include_closure = true },
input = input_func,
expect = '(function () local i = 10; return function (a) i = i + a; return i end end)()',
}
end
format_test {
name = 'Can include functions in closure',
adv_getlocal = true,
options = { more_function_info = true, include_closure = true },
input = (function ()
local custom_max = function (a, b) return (a > b) and a or b end
return function (a, b) return custom_max(a, b) + 2 end
end)(),
expect = '(function () local custom_max = function (a, b) return (a > b) and a or b end; return function (a, b) return custom_max(a, b) + 2 end end)()',
}
format_test {
name = 'Can include functions defined with `function <name> () ...` style',
adv_getlocal = true,
options = { more_function_info = true, include_closure = true },
input = (function ()
local function custom_max (a, b) return (a > b) and a or b end
return function (a, b) return custom_max(a, b) + 2 end
end)(),
expect = '(function () local custom_max = function (a, b) return (a > b) and a or b end; return function (a, b) return custom_max(a, b) + 2 end end)()',
}
do
local custom_max = function (a, b) return (a > b) and a or b end
format_test {
name = 'Can include functions from outside scope into closure',
adv_getlocal = true,
options = { more_function_info = true, include_closure = true },
input = (function ()
return function (a, b) return custom_max(a, b) + 2 end
end)(),
expect = '(function () local custom_max = function (a, b) return (a > b) and a or b end; return function (a, b) return custom_max(a, b) + 2 end end)()',
}
end
do
local a_func = function (x) return x + 2 end
local b_func = function (x) return a_func(x) * a_func(x) end
local c_func = function (x) return b_func(a_func(x)) end
format_test {
name = 'Can support recursive closures',
adv_getlocal = true,
options = { more_function_info = true, include_closure = true },
input = c_func,
expect = '(function () local b_func = (function () local a_func = function (x) return x + 2 end; return function (x) return a_func(x) * a_func(x) end end)(); local a_func = function (x) return x + 2 end; return function (x) return b_func(a_func(x)) end end)()',
}
end
format_test {
name = 'Closures do not affect builtins',
input = math.abs,
options = { more_function_info = true, include_closure = true },
expect = 'builtin function (x)\n\t-- math.abs\n\t-- Returns the absolute value of x.\n\n\t...\nend',
}
--------------------------------------------------------------------------------
-- Indent functions nicely
format_test {
-- The tail part should align, letting people focus on the important aspects.
input = { random = math.random, abs = math.abs },
expect = '{\n\tabs = builtin function (x) ... end,\n\trandom = builtin function ([m [, n]) ... end\n}',
}
format_test {
-- The function part should align, if some are builtin and some are not.
adv_getlocal = true,
input = { random = math.random, abs = function (x) return x < 0 and -x or x end },
expect = '{\n\tabs = function (x) ... end,\n\trandom = builtin function ([m [, n]) ... end\n}',
}
format_test {
-- No special indent if no special function modifier.
adv_getlocal = true,
input = { max = function(a, b) return a > b and a or b end,
abs = function (x) return x < 0 and -x or x end
},
expect = '{\n\tabs = function (x) ... end,\n\tmax = function (a, b) ... end\n}',
}
--------------------------------------------------------------------------------
--[[
format_test {
adv_getlocal = true,
options = { more_function_info = true, _all_function_info = true, max_depth = 2 },
input = function() end,
expect = '',
}
--]]
return SUITE