add unit tests

develop
myk002 2021-05-07 14:07:37 -07:00
parent cc489db084
commit 816cd5cf27
No known key found for this signature in database
GPG Key ID: 8A39CA0FA0C16E78
2 changed files with 220 additions and 19 deletions

@ -5,8 +5,7 @@ local utils = require('utils')
-- the info here is very basic and minimal, so hopefully we won't need to change -- the info here is very basic and minimal, so hopefully we won't need to change
-- it when features are added and the full blueprint docs in Plugins.rst are -- it when features are added and the full blueprint docs in Plugins.rst are
-- updated. -- updated.
local help_text = local help_text = [=[
[=[
blueprint blueprint
========= =========
@ -32,6 +31,8 @@ blueprint 30 40 bedrooms
See the online DFHack documentation for more examples and details. See the online DFHack documentation for more examples and details.
]=] ]=]
function print_help() print(help_text) end
valid_phases = utils.invert{ valid_phases = utils.invert{
'dig', 'dig',
'build', 'build',
@ -39,10 +40,6 @@ valid_phases = utils.invert{
'query', 'query',
} }
function print_help()
print(help_text)
end
local function parse_cursor(opts, arg) local function parse_cursor(opts, arg)
local _, _, x, y, z = arg:find('^(%d+),(%d+),(%d+)$') local _, _, x, y, z = arg:find('^(%d+),(%d+),(%d+)$')
if not x then if not x then
@ -57,16 +54,8 @@ local function parse_cursor(opts, arg)
opts.start.z = tonumber(z) opts.start.z = tonumber(z)
end end
-- dimension must be a non-nil integer that is >= 1 (or at least non-zero if
-- negative_ok is true)
local function is_bad_dim(dim, negative_ok)
return not dim
or (not negative_ok and dim < 1 or dim == 0)
or dim ~= math.floor(dim)
end
local function parse_positionals(opts, args, start_argidx) local function parse_positionals(opts, args, start_argidx)
local argidx = start_argidx local argidx = start_argidx or 1
-- set defaults -- set defaults
opts.name, opts.auto_phase = 'blueprint', true opts.name, opts.auto_phase = 'blueprint', true
@ -111,7 +100,15 @@ end
function parse_gui_commandline(opts, args) function parse_gui_commandline(opts, args)
local positionals = process_args(opts, args) local positionals = process_args(opts, args)
if opts.help then return end if opts.help then return end
parse_positionals(opts, positionals, 1) parse_positionals(opts, positionals)
end
-- dimension must be a non-nil integer that is >= 1 (or at least non-zero if
-- negative_ok is true)
local function is_bad_dim(dim, negative_ok)
return not dim or
(not negative_ok and dim < 1 or dim == 0) or
dim ~= math.floor(dim)
end end
function parse_commandline(opts, ...) function parse_commandline(opts, ...)
@ -120,7 +117,7 @@ function parse_commandline(opts, ...)
local width, height = tonumber(positionals[1]), tonumber(positionals[2]) local width, height = tonumber(positionals[1]), tonumber(positionals[2])
if is_bad_dim(width) or is_bad_dim(height) then if is_bad_dim(width) or is_bad_dim(height) then
qerror(('invalid width and height: "%s" "%s"; width and height must' .. qerror(('invalid width or height: "%s" "%s"; width and height must' ..
' be positive integers'):format(positionals[1], positionals[2])) ' be positive integers'):format(positionals[1], positionals[2]))
end end
opts.width, opts.height, opts.depth = width, height, 1 opts.width, opts.height, opts.depth = width, height, 1
@ -160,8 +157,10 @@ local function do_blueprint(start_pos, end_pos, name, phase)
local cursor = ('--cursor=%d,%d,%d'):format(x, y, z) local cursor = ('--cursor=%d,%d,%d'):format(x, y, z)
return dfhack.run_command{'blueprint', return dfhack.run_command('blueprint',
width, height, depth, name, phase, cursor} tostring(width), tostring(height),
tostring(depth), tostring(name),
phase, cursor)
end end
for phase in pairs(valid_phases) do for phase in pairs(valid_phases) do
_ENV[phase] = function(s, e, n) do_blueprint(s, e, n, phase) end _ENV[phase] = function(s, e, n) do_blueprint(s, e, n, phase) end

@ -0,0 +1,202 @@
local b = require('plugins.blueprint')
-- also covers code shared between parse_gui_commandline and parse_commandline
function test.parse_gui_commandline()
local opts = {}
b.parse_gui_commandline(opts, {})
expect.table_eq({auto_phase=true, name='blueprint'}, opts)
opts = {}
b.parse_gui_commandline(opts, {'help'})
expect.table_eq({help=true}, opts)
opts = {}
b.parse_gui_commandline(opts, {'--help'})
expect.table_eq({help=true}, opts)
opts = {}
b.parse_gui_commandline(opts, {'-h'})
expect.table_eq({help=true}, opts)
opts = {}
b.parse_gui_commandline(opts, {'--cursor=1,2,3'})
expect.table_eq({auto_phase=true, name='blueprint', start={x=1,y=2,z=3}},
opts)
opts = {}
expect.error_match('invalid argument',
function() b.parse_gui_commandline(
opts, {'--cursor=-1,2,3'}) end,
'negative coordinate')
opts = {}
expect.error_match('invalid argument',
function() b.parse_gui_commandline(
opts, {'--cursor=1,b,3'}) end,
'non-numeric coordinate')
opts = {}
b.parse_gui_commandline(opts, {'imaname'})
expect.table_eq({auto_phase=true, name='imaname'}, opts)
opts = {}
expect.error_match('invalid basename',
function() b.parse_gui_commandline(opts, {''}) end)
opts = {}
b.parse_gui_commandline(opts, {'imaname', 'dig', 'query'})
expect.table_eq({auto_phase=false, name='imaname', dig=true, query=true},
opts)
opts = {}
b.parse_gui_commandline(opts, {'imaname', 'garbagephase'})
expect.table_eq({auto_phase=true, name='imaname'}, opts)
end
function test.parse_commandline()
local opts = {}
b.parse_commandline(opts, '1', '2')
expect.table_eq({auto_phase=true,name='blueprint',width=1,height=2,depth=1},
opts)
opts = {}
b.parse_commandline(opts, '1', '2', '3')
expect.table_eq({auto_phase=true,name='blueprint',width=1,height=2,depth=3},
opts)
opts = {}
b.parse_commandline(opts, '1', '2', '-3')
expect.table_eq({auto_phase=true,name='blueprint',width=1,height=2,depth=-3},
opts)
opts = {}
b.parse_commandline(opts, '1', '2', 'imaname')
expect.table_eq({auto_phase=true,name='imaname',width=1,height=2,depth=1},
opts)
opts = {}
b.parse_commandline(opts, '1', '2', '10imaname')
expect.table_eq({auto_phase=true,name='10imaname',width=1,height=2,depth=1},
opts, 'invalid depth is considered a basename')
opts = {}
b.parse_commandline(opts, '1', '2', '-10imaname')
expect.table_eq({auto_phase=true,name='-10imaname',width=1,height=2,depth=1},
opts, 'invalid negative depth is considered a basename')
opts = {}
b.parse_commandline(opts, '1', '2', '3', 'imaname')
expect.table_eq({auto_phase=true,name='imaname',width=1,height=2,depth=3},
opts)
opts = {}
expect.error_match('invalid width or height',
function() b.parse_commandline(opts) end,
'missing width')
opts = {}
expect.error_match('invalid width or height',
function() b.parse_commandline(opts, '10') end,
'missing height')
opts = {}
expect.error_match('invalid width or height',
function() b.parse_commandline(opts, '0') end,
'zero height')
opts = {}
expect.error_match('invalid width or height',
function() b.parse_commandline(opts, 'hi') end,
'invalid width')
opts = {}
expect.error_match('invalid width or height',
function() b.parse_commandline(opts, '10', 'hi') end,
'invalid height')
opts = {}
expect.error_match('invalid depth',
function() b.parse_commandline(opts, '1', '2', '0') end,
'zero depth')
end
function test.do_gui_no_arg()
local mock_print, mock_timeout, mock_run_script =
mock.func(), mock.func(), mock.func()
mock.patch(
{
{b, 'print', mock_print},
{dfhack, 'timeout', mock_timeout},
{dfhack, 'run_script', mock_run_script},
},
function()
b.do_gui('gui')
expect.eq(1, mock_print.call_count)
expect.eq(1, mock_timeout.call_count)
mock_timeout.call_args[1][3]()
expect.eq(1, mock_run_script.call_count)
expect.table_eq({'gui/blueprint'}, mock_run_script.call_args[1])
end)
end
function test.do_gui_with_args()
local mock_print, mock_timeout, mock_run_script =
mock.func(), mock.func(), mock.func()
mock.patch(
{
{b, 'print', mock_print},
{dfhack, 'timeout', mock_timeout},
{dfhack, 'run_script', mock_run_script},
},
function()
b.do_gui('gui', 'arg1', 'arg2', 'arg3')
expect.eq(1, mock_print.call_count)
expect.eq(1, mock_timeout.call_count)
mock_timeout.call_args[1][3]()
expect.eq(1, mock_run_script.call_count)
expect.table_eq({'gui/blueprint', 'arg1', 'arg2', 'arg3'},
mock_run_script.call_args[1])
end)
end
function test.do_blueprint_positive_dims()
local mock_run_command = mock.func()
mock.patch(dfhack, 'run_command', mock_run_command,
function()
local spos = {x=10, y=20, z=30}
local epos = {x=11, y=21, z=31}
b.query(spos, epos, 'imaname')
expect.eq(1, mock_run_command.call_count)
expect.table_eq({'blueprint', '2', '2', '2', 'imaname', 'query',
'--cursor=10,20,30'},
mock_run_command.call_args[1])
end)
end
function test.do_blueprint_negative_dims()
local mock_run_command = mock.func()
mock.patch(dfhack, 'run_command', mock_run_command,
function()
local spos = {x=11, y=21, z=31}
local epos = {x=10, y=20, z=30}
b.query(spos, epos, 'imaname')
expect.eq(1, mock_run_command.call_count)
expect.table_eq({'blueprint', '2', '2', '-2', 'imaname', 'query',
'--cursor=10,20,31'},
mock_run_command.call_args[1])
end)
end
function test.do_blueprint_ensure_cursor_is_at_upper_left()
local mock_run_command = mock.func()
mock.patch(dfhack, 'run_command', mock_run_command,
function()
local spos = {x=11, y=20, z=30}
local epos = {x=10, y=21, z=31}
b.query(spos, epos, 'imaname')
expect.eq(1, mock_run_command.call_count)
expect.table_eq({'blueprint', '2', '2', '2', 'imaname', 'query',
'--cursor=10,20,30'},
mock_run_command.call_args[1])
end)
end