2017-01-19 13:02:34 +00:00
|
|
|
|
|
|
|
local SUITE = require('TestSuite').new('analyze_structure')
|
2017-04-03 09:24:51 +00:00
|
|
|
SUITE:setEnviroment {
|
2017-04-14 11:06:43 +00:00
|
|
|
analyze_structure = require('analyze_structure')[1],
|
2017-04-03 09:24:51 +00:00
|
|
|
TABLE_TYPE = require('table_type')
|
|
|
|
}
|
2017-01-19 13:02:34 +00:00
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- analyze_structure
|
|
|
|
|
|
|
|
SUITE:addTest('Empty Table', function ()
|
|
|
|
local input = {} -- Empty!
|
|
|
|
local table_info = analyze_structure(input)[input]
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
assert_equal(table_info.type, TABLE_TYPE.EMPTY, 'Returned bad type: '..table_info.type)
|
|
|
|
assert_equal(table_info.has_seq, false)
|
|
|
|
assert_equal(table_info.has_map, false)
|
2017-01-19 13:02:34 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Sequence', function ()
|
|
|
|
local input = { 1, 2, 3 }
|
|
|
|
local table_info = analyze_structure(input)[input]
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
assert_equal(table_info.type, TABLE_TYPE.SEQUENCE, 'Returned bad type: '..table_info.type)
|
|
|
|
assert_equal(table_info.has_seq, true)
|
|
|
|
assert_equal(table_info.has_map, false)
|
2017-01-19 13:02:34 +00:00
|
|
|
end)
|
|
|
|
|
2017-04-14 08:56:38 +00:00
|
|
|
SUITE:addTest('Sequence with holes', function ()
|
|
|
|
local input = { 1, nil, 3 }
|
|
|
|
local table_info = analyze_structure(input)[input]
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
assert_equal(table_info.type, TABLE_TYPE.SEQUENCE, 'Returned bad type: '..table_info.type)
|
|
|
|
assert_equal(table_info.has_seq, true)
|
|
|
|
assert_equal(table_info.has_map, false)
|
|
|
|
assert_equal(table_info.has_holes, true)
|
2017-04-14 08:56:38 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Sequence with hole on start', function ()
|
|
|
|
local input = { nil, 2, 3 }
|
|
|
|
local table_info = analyze_structure(input)[input]
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
assert_equal(table_info.type, TABLE_TYPE.SEQUENCE, 'Returned bad type: '..table_info.type)
|
|
|
|
assert_equal(table_info.has_seq, true)
|
|
|
|
assert_equal(table_info.has_map, false)
|
|
|
|
assert_equal(table_info.has_holes, true)
|
2017-04-14 08:56:38 +00:00
|
|
|
end)
|
|
|
|
|
2017-01-19 13:02:34 +00:00
|
|
|
SUITE:addTest('Pure Map', function ()
|
|
|
|
local input = { a = 1, [true] = 2, c = 3 }
|
|
|
|
local table_info = analyze_structure(input)[input]
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
assert_equal(table_info.type, TABLE_TYPE.PURE_MAP, 'Returned bad type: '..table_info.type)
|
|
|
|
assert_equal(table_info.has_seq, false)
|
|
|
|
assert_equal(table_info.has_map, true)
|
2017-01-19 13:02:34 +00:00
|
|
|
end)
|
|
|
|
|
2017-04-14 11:06:43 +00:00
|
|
|
SUITE:addTest('Boolean set', function ()
|
|
|
|
local input = { [true] = true, [false] = false }
|
|
|
|
local table_info = analyze_structure(input)[input]
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
assert_equal(table_info.type, TABLE_TYPE.SET, 'Returned bad type: '..table_info.type)
|
|
|
|
assert_equal(table_info.has_seq, false)
|
|
|
|
assert_equal(table_info.has_map, true)
|
2017-04-14 11:06:43 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('A Mixed table', function ()
|
|
|
|
local input = { 300, [300] = 1 }
|
|
|
|
local table_info = analyze_structure(input)[input]
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
assert_equal(table_info.has_seq, true)
|
|
|
|
assert_equal(table_info.has_map, true)
|
|
|
|
assert_equal(table_info.type, TABLE_TYPE.MIXED, 'Returned bad type: '..table_info.type)
|
2017-04-14 11:06:43 +00:00
|
|
|
end)
|
|
|
|
|
2017-01-19 13:02:34 +00:00
|
|
|
SUITE:addTest('String Map', function ()
|
|
|
|
local input = { a = 1, b = 2, c = 3 }
|
|
|
|
local table_info = analyze_structure(input)[input]
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
assert_equal(table_info.type, TABLE_TYPE.STRING_MAP, 'Returned bad type: '..table_info.type)
|
|
|
|
assert_equal(table_info.has_seq, false)
|
|
|
|
assert_equal(table_info.has_map, true)
|
2017-01-19 13:02:34 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Set', function ()
|
|
|
|
local input = { a = true, b = true, c = true }
|
|
|
|
local table_info = analyze_structure(input)[input]
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
assert_equal(table_info.type, TABLE_TYPE.SET, 'Returned bad type: '..table_info.type)
|
|
|
|
assert_equal(table_info.is_set, true)
|
2017-01-19 13:02:34 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Tabular of sequences', function ()
|
|
|
|
local input = { a = {1, 2, 3}, b = {4, 5, 6}, c = {7, 8, 9} }
|
|
|
|
local table_info = analyze_structure(input)[input]
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
assert_equal(table_info.is_tabular, {true, true, true})
|
2017-01-19 13:02:34 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Tabular of maps', function ()
|
|
|
|
local input = { a = {a = 1, b = 2}, b = {a = 3, b = 4}, c = {a = 2, b = 7} }
|
|
|
|
local table_info = analyze_structure(input)[input]
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
assert_equal(table_info.is_tabular, {a = true, b = true})
|
2017-01-19 13:02:34 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Not Tabular, due to no-sub-tables', function ()
|
|
|
|
local input = { a = 1, b = {4}, c = 7 }
|
|
|
|
local table_info = analyze_structure(input)[input]
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
assert_equal(table_info.is_tabular, false)
|
2017-01-19 13:02:34 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Not Tabular, due to not being identical sub-tables', function ()
|
|
|
|
local input = { a = { a = 1 }, b = { b = 2 }, c = { c = 3 } }
|
|
|
|
local table_info = analyze_structure(input)[input]
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
assert_equal(table_info.is_tabular, false)
|
2017-01-19 13:02:34 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Not Tabular, due to varying lengths', function ()
|
|
|
|
local input = { { 1 }, { 2, 3 }, { 4, 5, 6 } }
|
|
|
|
local table_info = analyze_structure(input)[input]
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
assert_equal(table_info.is_tabular, false)
|
2017-01-19 13:02:34 +00:00
|
|
|
end)
|
|
|
|
|
2017-06-15 17:01:41 +00:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Stops at max_depth
|
|
|
|
|
|
|
|
SUITE:addTest('Has info for root, and children', function ()
|
|
|
|
local input = { { 1 }, { 2, 3 }, { 4, 5, 6 } }
|
|
|
|
local table_info = analyze_structure(input, 1)
|
|
|
|
|
|
|
|
assert(table_info[input])
|
|
|
|
assert(table_info[input[1]])
|
|
|
|
assert(table_info[input[2]])
|
|
|
|
assert(table_info[input[3]])
|
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Has info for root, but not children', function ()
|
|
|
|
local input = { { 1 }, { 2, 3 }, { 4, 5, 6 } }
|
|
|
|
local table_info = analyze_structure(input, 0)
|
|
|
|
|
|
|
|
assert(table_info[input])
|
|
|
|
assert(not table_info[input[1]])
|
|
|
|
assert(not table_info[input[2]])
|
|
|
|
assert(not table_info[input[3]])
|
|
|
|
end)
|
|
|
|
|
2017-01-19 13:02:34 +00:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Corner cases.
|
|
|
|
|
|
|
|
SUITE:addTest('goto is special', function ()
|
|
|
|
local input = { ['goto'] = 'hi' }
|
|
|
|
local table_info = analyze_structure(input)[input]
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
assert_equal(table_info.type, TABLE_TYPE.PURE_MAP, 'Returned bad type: '..table_info.type)
|
2017-01-19 13:02:34 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- analyze_structure
|
|
|
|
|
|
|
|
SUITE:addTest('Recursive Numeration, Simple', function ()
|
|
|
|
local input = {}
|
|
|
|
input[1] = input
|
|
|
|
local info = analyze_structure(input)
|
|
|
|
|
|
|
|
assert(info[input].marker == 1)
|
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Recursive Numeration, Multiple-appear', function ()
|
|
|
|
local input = { {}, { {} } }
|
|
|
|
input[1][1] = input[2][1]
|
|
|
|
local info = analyze_structure(input)
|
|
|
|
|
|
|
|
assert(info[input[1][1]].marker == 1)
|
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Recursive Numeration, Multiple at once', function ()
|
|
|
|
local input = { {}, { {} } }
|
|
|
|
input[1][1] = input[2][1]
|
|
|
|
input[1][2] = input
|
|
|
|
local info = analyze_structure(input)
|
|
|
|
|
|
|
|
assert(type(info[input[1][1]].marker) == 'number')
|
|
|
|
assert(type(info[input].marker) == 'number')
|
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Recursive Numeration, Through Keys', function ()
|
|
|
|
local input = { }
|
|
|
|
input[input] = input
|
|
|
|
local info = analyze_structure(input)
|
|
|
|
|
|
|
|
assert(info[input].marker == 1)
|
|
|
|
end)
|
|
|
|
|
2017-06-09 13:49:15 +00:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Metatable shennanigens.
|
|
|
|
|
|
|
|
SUITE:addTest('Wont crash, even though metatable.__index throws errors', function ()
|
|
|
|
local input = setmetatable({ 'hi', 'hello' }, {__index = function (_, k) error('Undefined access on key: '..k) end})
|
|
|
|
local info = analyze_structure(input)
|
|
|
|
|
|
|
|
assert(true)
|
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Can count elements, even though metatable.__index throws errors', function ()
|
|
|
|
local input = setmetatable({ 'hi', 'hello' }, {__index = function (_, k) error('Undefined access on key: '..k) end})
|
|
|
|
local info = analyze_structure(input)
|
|
|
|
|
|
|
|
assert_equal(info[input].seq_elems, 2)
|
|
|
|
end)
|
|
|
|
|
2017-06-10 21:17:30 +00:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Uniform structure
|
|
|
|
|
|
|
|
SUITE:addTest('Can detect uniform structure', function ()
|
|
|
|
local input = { a = 'b', b = 'a' }
|
|
|
|
local info = analyze_structure(input)
|
|
|
|
|
|
|
|
assert_equal(info[input].is_uniform, true)
|
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Can detect uniform structure with different key value types', function ()
|
|
|
|
local input = { a = 1, b = 4 }
|
|
|
|
local info = analyze_structure(input)
|
|
|
|
|
|
|
|
assert_equal(info[input].is_uniform, true)
|
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Can detect basic non-uniform structure', function ()
|
|
|
|
local input = { a = 'b', b = 5 }
|
|
|
|
local info = analyze_structure(input)
|
|
|
|
|
|
|
|
assert_equal(info[input].is_uniform, false)
|
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Can detect pseudo-uniform structure with nested tables', function ()
|
|
|
|
-- It's pseudo-uniform because of the child having uniform structure with
|
|
|
|
-- equal number of elements.
|
|
|
|
local input = { a = { d = 7 }, b = { p = 3 } }
|
|
|
|
local info = analyze_structure(input)
|
|
|
|
|
|
|
|
assert_equal(info[input].is_uniform, true)
|
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('Can detect non-uniform structure with nested tables', function ()
|
|
|
|
local input = { a = { 'a', 'b', 'c' }, b = { p = 3, 'hi' } }
|
|
|
|
local info = analyze_structure(input)
|
|
|
|
|
|
|
|
assert_equal(info[input].is_uniform, false)
|
|
|
|
end)
|
|
|
|
|
|
|
|
-- TODO: Add predicate to check for pseudo-uniformness.
|
|
|
|
|
2017-01-19 13:02:34 +00:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- API stuff
|
|
|
|
|
|
|
|
SUITE:addTest('next_mark does not escape', function ()
|
|
|
|
local info = analyze_structure( {} )
|
|
|
|
assert(not info.next_mark)
|
|
|
|
end)
|
|
|
|
|
2017-06-24 15:59:55 +00:00
|
|
|
SUITE:addTest('We can extend an already existing info table', function ()
|
|
|
|
local tab1, tab2 = {}, {}
|
|
|
|
local info = analyze_structure( tab1 )
|
|
|
|
analyze_structure( tab2, math.huge, info )
|
|
|
|
assert(info[tab1])
|
|
|
|
assert(info[tab2])
|
|
|
|
end)
|
|
|
|
|
|
|
|
SUITE:addTest('When we extend an info table, we retain the previous root', function ()
|
|
|
|
local tab1, tab2 = {}, {}
|
|
|
|
local info = analyze_structure( tab1 )
|
|
|
|
analyze_structure( tab2, math.huge, info )
|
|
|
|
assert(tab1 == info.root)
|
|
|
|
end)
|
|
|
|
|
2017-01-19 13:02:34 +00:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
return SUITE
|