435 lines
12 KiB
Lua
435 lines
12 KiB
Lua
|
|
local SUITE = require 'TestSuite' 'pretty'
|
|
SUITE:setEnvironment{
|
|
format = require('pretty')
|
|
}
|
|
|
|
local ASSERT_ERROR_APPROX = [[
|
|
Approximate strings not similar enough:
|
|
Should match: %s
|
|
Gotten: %s
|
|
]]
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Compat
|
|
if not loadstring then loadstring = load end -- Lua 5.3 compat
|
|
local HAS_ADV_GETLOCAL = not not debug.getinfo(1, 'u').nparams -- Lua 5.1 compat
|
|
local HAS_UNICODE_IDEN = not not loadstring 'local ϕ = 1; return ϕ' -- Lua 5.1 compat
|
|
local HAS_JIT_LIBRARY = type(rawget(_G, 'jit')) == 'table' -- Non-LuaJIT 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 actual_result = format(t.input, t.options)
|
|
if not t.approx or type(actual_result) ~= 'string' then
|
|
assert_equal(t.expect, actual_result)
|
|
else
|
|
if not actual_result:match(t.expect) then
|
|
error(ASSERT_ERROR_APPROX:format(t.expect, actual_result))
|
|
end
|
|
end
|
|
end, { line = debug.getinfo(2).currentline })
|
|
end
|
|
|
|
local function format_parsable_test (t)
|
|
local stripped = t.text:match '^%s*(.-)%s*$'
|
|
return format_test {
|
|
name = t.name,
|
|
input = loadstring('return '..stripped)(),
|
|
expect = stripped
|
|
}
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Primitive types
|
|
|
|
format_test {
|
|
input = nil,
|
|
expect = 'nil',
|
|
}
|
|
|
|
format_test {
|
|
input = true,
|
|
expect = 'true',
|
|
}
|
|
|
|
format_test {
|
|
input = false,
|
|
expect = 'false',
|
|
}
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Userdata printing
|
|
|
|
-- TODO: Figure out a way to print userdata.
|
|
-- Maybe look into using the one available debug.getupvalue(pairs, 1)
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Thread printing
|
|
|
|
do
|
|
local suspended_coroutine = coroutine.create(function () end)
|
|
format_test {
|
|
input = suspended_coroutine,
|
|
approx = true,
|
|
expect = 'suspended coroutine: 0x%x+',
|
|
}
|
|
end
|
|
|
|
do
|
|
local dead_coroutine = coroutine.create(function () end)
|
|
coroutine.resume(dead_coroutine)
|
|
format_test {
|
|
input = dead_coroutine,
|
|
approx = true,
|
|
expect = 'dead coroutine: 0x%x+',
|
|
}
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Single-line tables
|
|
|
|
format_test {
|
|
input = {},
|
|
expect = '{}',
|
|
}
|
|
|
|
format_test {
|
|
input = {1, 2, 3},
|
|
expect = '{ 1, 2, 3 }',
|
|
}
|
|
|
|
format_test {
|
|
input = { 'Hello', 'World' },
|
|
expect = '{ \'Hello\', \'World\' }',
|
|
}
|
|
|
|
format_test {
|
|
input = { a = 1, b = 2 },
|
|
expect = '{ a = 1, b = 2 }',
|
|
}
|
|
|
|
format_test {
|
|
input = { __hello = true },
|
|
expect = '{ __hello = true }',
|
|
}
|
|
|
|
format_test {
|
|
input = { [']]'] = true },
|
|
expect = '{ [\']]\'] = true }',
|
|
}
|
|
|
|
format_test {
|
|
input = { ['and'] = true },
|
|
expect = '{ [\'and\'] = true }',
|
|
}
|
|
|
|
format_test {
|
|
input = { [false] = false, [true] = true },
|
|
expect = '{ [false] = false, [true] = true }',
|
|
}
|
|
|
|
format_test { -- Order does not matter
|
|
input = { b = 1, a = 2 },
|
|
expect = '{ a = 2, b = 1 }',
|
|
}
|
|
|
|
format_test { -- Can include empty tables
|
|
input = { {}, {}, {} },
|
|
expect = '{ {}, {}, {} }',
|
|
}
|
|
|
|
format_test { -- Can include very small tables
|
|
input = { {1}, {2}, {3} },
|
|
expect = '{ { 1 }, { 2 }, { 3 } }',
|
|
}
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Multi-line tables
|
|
|
|
format_test {
|
|
input = { {1, 2, 3}, {4, 5, 6} },
|
|
expect = '{ { 1, 2, 3 }, { 4, 5, 6 } }',
|
|
}
|
|
|
|
format_test {
|
|
input = { a = {1, 2, 3}, b = {4, 5, 6} },
|
|
expect = '{ a = { 1, 2, 3 }, b = { 4, 5, 6 } }',
|
|
}
|
|
|
|
format_test {
|
|
name = 'Unicode characters can be used as string keys in tables',
|
|
input = { ['a'] = 1, ['ψ'] = 2 },
|
|
expect = '{ a = 1, ψ = 2 }',
|
|
}
|
|
|
|
format_test {
|
|
input = { [100] = 'Hi', [300] = 'Hello' },
|
|
expect = '{ [100] = \'Hi\', [300] = \'Hello\' }',
|
|
}
|
|
|
|
format_test {
|
|
input = { 'Hi', [300] = 'Hello' },
|
|
expect = '{ [1] = \'Hi\', [300] = \'Hello\' }',
|
|
}
|
|
|
|
format_test {
|
|
input = { { {} } },
|
|
expect = '{ { {} } }',
|
|
}
|
|
|
|
format_test {
|
|
input = { [{ 1, 2 }] = { 2, 1 } },
|
|
expect = '{ [{ 1, 2 }] = { 2, 1 } }',
|
|
}
|
|
|
|
format_test {
|
|
input = { { {1, 2}, {3, 4} }, {5, 6} },
|
|
expect = '{ { { 1, 2 }, { 3, 4 } }, { 5, 6 } }',
|
|
}
|
|
|
|
format_test {
|
|
input = { [{ {1,2}, {3,4} }] = 'Hello World' },
|
|
expect = '{ [{...}] = \'Hello World\' }',
|
|
}
|
|
|
|
format_test {
|
|
input = { a = {1,2}, bcdefg = {3,4} },
|
|
expect = '{ a = { 1, 2 }, bcdefg = { 3, 4 } }',
|
|
}
|
|
|
|
format_test {
|
|
input = { [true] = 1, [1] = false },
|
|
expect = '{ [1] = false, [true] = 1 }',
|
|
}
|
|
|
|
format_test {
|
|
-- Proper indent
|
|
input = { [1] = 1, ['whatever'] = false },
|
|
expect = '{ [1] = 1, [\'whatever\'] = false }',
|
|
}
|
|
|
|
format_test {
|
|
name = 'Proper alignment when using unicode characters as keys',
|
|
input = {
|
|
['djævle'] = 'dyr?',
|
|
['europa'] = 'måne',
|
|
['øå'] = 'en å på en ø?',
|
|
},
|
|
expect = '{\n djævle = \'dyr?\',\n europa = \'måne\',\n øå = \'en å på en ø?\'\n}',
|
|
}
|
|
|
|
format_test {
|
|
name = 'Proper alignment when using zero-width unicode characters as keys',
|
|
input = {
|
|
['hello_world_1'] = 'dyr?',
|
|
['hello_world_2'] = 'dyr!',
|
|
['hello\204\133_wo\204\133rld_3'] = 'dyr.',
|
|
},
|
|
expect = '{\n hello_world_1 = \'dyr?\',\n hello_world_2 = \'dyr!\',\n hello\204\133_wo\204\133rld_3 = \'dyr.\'\n}',
|
|
}
|
|
|
|
-- Depth Tests
|
|
|
|
format_test {
|
|
name = 'Tables with a mix of values don\'t expand subtables',
|
|
input = {
|
|
a = 'hello',
|
|
b = {1, 2, 3},
|
|
c = {1, 2, 3},
|
|
d = {1, 2, 3},
|
|
},
|
|
expect = '{\n a = \'hello\',\n b = {...},\n c = {...},\n d = {...}\n}',
|
|
}
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Pattern specific table display.
|
|
|
|
format_test {
|
|
name = 'Column style',
|
|
input = {
|
|
'hello', 'world', 'how',
|
|
'is', 'it', 'going?',
|
|
'Im', 'doing great', 'thanks',
|
|
'that', 'was', 'what',
|
|
'I', 'were', 'expecting'
|
|
},
|
|
expect = '{\n \'hello\', \'world\', \'how\',\n \'is\', \'it\', \'going?\',\n \'Im\', \'doing great\', \'thanks\',\n \'that\', \'was\', \'what\',\n \'I\', \'were\', \'expecting\'\n}',
|
|
}
|
|
|
|
format_test {
|
|
name = 'Column style with trailing last row',
|
|
input = {
|
|
'hello', 'world', 'how',
|
|
'is', 'it', 'going?',
|
|
'Im', 'doing great', 'thanks',
|
|
'that', 'was', 'what',
|
|
'I'
|
|
},
|
|
expect = '{\n \'hello\', \'world\', \'how\',\n \'is\', \'it\', \'going?\',\n \'Im\', \'doing great\', \'thanks\',\n \'that\', \'was\', \'what\',\n \'I\'\n}',
|
|
}
|
|
|
|
format_parsable_test {
|
|
name = 'Column style with aligned numbers',
|
|
text = [[
|
|
{
|
|
200, -522, 423, 516, 523, 126, 2912,
|
|
523, -620, 0, 0, 0, -5, 2,
|
|
72, 6
|
|
}
|
|
]] }
|
|
|
|
format_test {
|
|
name = 'Tabular style with strings left aligned',
|
|
input = {
|
|
{ a = 'hello', b = 'hi' },
|
|
{ a = 'hi', b = 'hello' },
|
|
{ a = 'hi', b = 'hi' },
|
|
},
|
|
expect = '{\n { a = \'hello\', b = \'hi\' },\n { a = \'hi\', b = \'hello\' },\n { a = \'hi\', b = \'hi\' }\n}',
|
|
}
|
|
|
|
format_test {
|
|
name = 'Tabular style with subtables in keys',
|
|
input = {
|
|
[false] = { a = 'hi', b = 'hello' },
|
|
[true] = { a = 'hello', b = 'hi' }
|
|
},
|
|
expect = '{\n [false] = { a = \'hi\', b = \'hello\' },\n [true] = { a = \'hello\', b = \'hi\' }\n}',
|
|
}
|
|
|
|
format_test {
|
|
name = 'Tabular style also works with strange keys',
|
|
input = {
|
|
{ [false] = 'hi', [true] = 'hello', },
|
|
{ [false] = 'hello', [true] = 'hi', }
|
|
},
|
|
expect = '{\n { [false] = \'hi\', [true] = \'hello\' },\n { [false] = \'hello\', [true] = \'hi\' }\n}',
|
|
}
|
|
|
|
format_test {
|
|
name = 'Tabular style also works with lists',
|
|
input = {
|
|
{ 'hello', 'world', 'how is things?' },
|
|
{ 'hi', 'planetdroid', 'sup?' }
|
|
},
|
|
expect = '{\n { \'hello\', \'world\', \'how is things?\' },\n { \'hi\', \'planetdroid\', \'sup?\' }\n}',
|
|
}
|
|
|
|
format_test {
|
|
name = 'Tabular style with numbers right aligned',
|
|
input = {
|
|
{ x = 140, y = 72, z = 31 },
|
|
{ x = 5010, y = 1, z = 314 }
|
|
},
|
|
expect = '{\n { x = 140, y = 72, z = 31 },\n { x = 5010, y = 1, z = 314 }\n}',
|
|
}
|
|
|
|
format_test {
|
|
name = 'Tabular style with small subtables',
|
|
input = {
|
|
{ a = 'hel', x = {b = 'abc', c = 'yo' } },
|
|
{ a = 'hi', x = {b = 'yo', c = 'abc' } }
|
|
},
|
|
expect = '{\n { a = \'hel\', x = { b = \'abc\', c = \'yo\' } },\n { a = \'hi\', x = { b = \'yo\', c = \'abc\' } }\n}',
|
|
}
|
|
|
|
|
|
------------------------
|
|
|
|
format_test {
|
|
name = 'Pseudo-Tabular style with justification',
|
|
input = {
|
|
{ st = 'ita', tx = 'annah', },
|
|
{ st = 'bld', tx = 'tommy', sz = 20 },
|
|
{ st = 'unl', tx = 'mike', },
|
|
},
|
|
expect = '{\n { st = \'ita\', tx = \'annah\' },\n { st = \'bld\', tx = \'tommy\', sz = 20 },\n { st = \'unl\', tx = \'mike\' }\n}',
|
|
}
|
|
|
|
format_test {
|
|
name = 'Pseudo-Tabular style with extreme justification',
|
|
input = {
|
|
{ st = 'ita', tx = 'annah', },
|
|
{ st = 'bld', tx = 'tommy', sz = 20 },
|
|
{ st = 'unl', tx = 'mike', sy = 21 },
|
|
},
|
|
expect = '{\n { st = \'ita\', tx = \'annah\' },\n { st = \'bld\', tx = \'tommy\', sz = 20 },\n { st = \'unl\', tx = \'mike\', sy = 21 }\n}',
|
|
}
|
|
|
|
format_test {
|
|
name = 'Pseudo-Tabular style without justification',
|
|
input = {
|
|
{ st = 'ita', tx = 'annah', sx = 19 },
|
|
{ st = 'bld', tx = 'tommy', sz = 20 },
|
|
{ st = 'unl', tx = 'mike', sy = 21 },
|
|
{ st = 'ita', tx = 'milo' },
|
|
{ st = 'bld', tx = 'yota' },
|
|
{ st = 'unl', tx = 'kilo' },
|
|
},
|
|
expect = '{\n { st = \'ita\', tx = \'annah\', sx = 19 },\n { st = \'bld\', tx = \'tommy\', sz = 20 },\n { st = \'unl\', tx = \'mike\', sy = 21 },\n { st = \'ita\', tx = \'milo\' },\n { st = \'bld\', tx = \'yota\' },\n { st = \'unl\', tx = \'kilo\' }\n}',
|
|
}
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Table recursion
|
|
|
|
SUITE:addTest('Avoid infinite loops in recursion', function ()
|
|
local rec = {}
|
|
rec[1] = rec
|
|
format(rec)
|
|
assert(true) -- We don't care about the output.
|
|
end)
|
|
|
|
-- TODO: This is a very complex topic, and will expanded upon after 1.0.0.
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- General
|
|
|
|
SUITE:addTest('UseCase: Can print global enviroment', function ()
|
|
format(_G)
|
|
assert(true)
|
|
end)
|
|
|
|
SUITE:addTest('UseCase: Can print value with __tostring returning unusual values', function ()
|
|
format( setmetatable({}, {__tostring = function() end}) )
|
|
assert(true)
|
|
end)
|
|
|
|
SUITE:addTest('UseCase: Can load function from file that is shortly deleted', function ()
|
|
local module_name = 'tmp_'..os.time()
|
|
-- Create module
|
|
local file = io.open('./'..module_name..'.lua', 'w')
|
|
file:write '\nlocal function yo ()\n -- Hello World\n return math.random()\nend\n\nreturn yo\n'
|
|
file:close()
|
|
-- Load module
|
|
local yo = require(module_name)
|
|
-- Remove module
|
|
os.remove('./'..module_name..'.lua')
|
|
package.loaded[module_name] = nil
|
|
|
|
-- Format the function, even though the module it came from is gone.
|
|
format(yo)
|
|
assert(true)
|
|
end)
|
|
|
|
local BIG_EXAMPLE_TABLE = [[
|
|
return {
|
|
[0] = 21082, [1] = 696,
|
|
[96] = 62, [97] = 334,
|
|
[98] = 119, [99] = 217,
|
|
[100] = 261
|
|
}]]
|
|
|
|
SUITE:addTest('UseCase: Big Example Table', function ()
|
|
assert_equal(BIG_EXAMPLE_TABLE, 'return '..format(loadstring(BIG_EXAMPLE_TABLE)()))
|
|
end)
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
return SUITE
|
|
|