implement 'fortress' unit test mode

- implement navigation function for loading a fortress from the title
  screen (requires a fortress save to be ready in region1/).
- ensure we don't try repeatedly to enter a mode that we can't reach
  (such as getting back to the title screen from fortress mode). failing
  to enter the mode once will skip all remaining tests in that mode.
develop
myk002 2021-04-19 11:26:13 -07:00
parent 27433b7388
commit d288bc6bde
No known key found for this signature in database
GPG Key ID: 8A39CA0FA0C16E78
1 changed files with 88 additions and 23 deletions

@ -66,8 +66,6 @@ local TestStatus = {
FAILED = 'failed', FAILED = 'failed',
} }
local VALID_MODES = utils.invert{'none', 'title', 'fortress'}
local function delay(frames) local function delay(frames)
frames = frames or 1 frames = frames or 1
script.sleep(frames, 'frames') script.sleep(frames, 'frames')
@ -116,29 +114,87 @@ end
test_envvars.require = clean_require test_envvars.require = clean_require
test_envvars.reqscript = clean_reqscript test_envvars.reqscript = clean_reqscript
local function is_title_screen(scr)
scr = scr or dfhack.gui.getCurViewscreen()
return df.viewscreen_titlest:is_instance(scr)
end
-- This only handles pre-fortress-load screens. It will time out if the player
-- has already loaded a fortress or is in any screen that can't get to the title
-- screen by sending ESC keys.
local function ensure_title_screen() local function ensure_title_screen()
if df.viewscreen_titlest:is_instance(dfhack.gui.getCurViewscreen()) then for i = 1, 100 do
return
end
print('Looking for title screen...')
for i = 0, 100 do
local scr = dfhack.gui.getCurViewscreen() local scr = dfhack.gui.getCurViewscreen()
if df.viewscreen_titlest:is_instance(scr) then if is_title_screen(scr) then
print('Found title screen') print('Found title screen')
break return
else end
scr:feed_key(df.interface_key.LEAVESCREEN)
delay(10)
if i % 10 == 0 then print('Looking for title screen...') end
end
qerror(string.format('Could not find title screen (timed out at %s)',
dfhack.gui.getCurFocus(true)))
end
local function is_fortress(focus_string)
focus_string = focus_string or dfhack.gui.getCurFocus(true)
return focus_string == 'dwarfmode/Default'
end
-- Requires that a fortress game is already loaded or is ready to be loaded via
-- the "Continue Playing" option in the title screen. Otherwise the function
-- will time out and/or exit with error.
local function ensure_fortress()
local focus_string = dfhack.gui.getCurFocus(true)
for screen_timeout = 1,10 do
if is_fortress(focus_string) then
print('Loaded fortress map')
-- pause the game (if it's not already paused)
dfhack.gui.resetDwarfmodeView(true)
return
end
local scr = dfhack.gui.getCurViewscreen()
if focus_string == 'title' then
scr:feed_key(df.interface_key.SELECT)
scr:feed_key(df.interface_key.SELECT)
elseif focus_string == 'dfhack/lua/load_screen' or
focus_string == 'dfhack/lua' then
scr:feed_key(df.interface_key.SELECT)
elseif focus_string == 'new_region' or
focus_string == 'adopt_region' then
qerror('Please ensure a fortress save exists in region1/')
elseif focus_string ~= 'loadgame' then
-- if we're not actively loading a game, assume we're in
-- a loaded fortress, but in some subscreen
scr:feed_key(df.interface_key.LEAVESCREEN) scr:feed_key(df.interface_key.LEAVESCREEN)
end
-- wait for active screen to change
local prev_focus_string = focus_string
for frame_timeout = 1,100 do
delay(10) delay(10)
focus_string = dfhack.gui.getCurFocus(true)
if focus_string ~= prev_focus_string then
goto next_screen
end
if frame_timeout % 10 == 0 then
print(string.format(
'Loading fortress (currently at screen: %s)',
focus_string))
end
end end
print('Timed out waiting for screen to change')
break
::next_screen::
end end
if not df.viewscreen_titlest:is_instance(dfhack.gui.getCurViewscreen()) then qerror(string.format('Could not load fortress (timed out at %s)',
error('Could not find title screen') focus_string))
end
end end
local MODE_NAVIGATE_FNS = { local MODES = {
none = function() end, none = {order=1, detect=function() return true end},
title = ensure_title_screen, title = {order=2, detect=is_title_screen, navigate=ensure_title_screen},
fortress = {order=3, detect=is_fortress, navigate=ensure_fortress},
} }
local function load_test_config(config_file) local function load_test_config(config_file)
@ -266,7 +322,7 @@ local function load_tests(file, tests)
dfhack.printerr('Error when running file: ' .. tostring(err)) dfhack.printerr('Error when running file: ' .. tostring(err))
return false return false
else else
if not VALID_MODES[env.config.mode] then if not MODES[env.config.mode] then
dfhack.printerr('Invalid config.mode: ' .. tostring(env.config.mode)) dfhack.printerr('Invalid config.mode: ' .. tostring(env.config.mode))
return false return false
end end
@ -290,10 +346,9 @@ local function sort_tests(tests)
local test_index = utils.invert(tests) local test_index = utils.invert(tests)
table.sort(tests, function(a, b) table.sort(tests, function(a, b)
if a.config.mode ~= b.config.mode then if a.config.mode ~= b.config.mode then
return VALID_MODES[a.config.mode] < VALID_MODES[b.config.mode] return MODES[a.config.mode].order < MODES[b.config.mode].order
else
return test_index[a] < test_index[b]
end end
return test_index[a] < test_index[b]
end) end)
end end
@ -418,9 +473,19 @@ end
local function run_tests(tests, status, counts) local function run_tests(tests, status, counts)
print(('Running %d tests'):format(#tests)) print(('Running %d tests'):format(#tests))
for _, test in pairs(tests) do for _, test in pairs(tests) do
MODE_NAVIGATE_FNS[test.config.mode]() status[test.full_name] = TestStatus.FAILED
local passed = run_test(test, status, counts) if MODES[test.config.mode].failed then goto skip end
status[test.full_name] = passed and TestStatus.PASSED or TestStatus.FAILED if not MODES[test.config.mode].detect() then
local ok, err = pcall(MODES[test.config.mode].navigate)
if not ok then
MODES[test.config.mode].failed = true
dfhack.printerr(tostring(err))
goto skip
end
end
status[test.full_name] = run_test(test, status, counts) and
TestStatus.PASSED or TestStatus.FAILED
::skip::
save_test_status(status) save_test_status(status)
end end