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',
}
local VALID_MODES = utils.invert{'none', 'title', 'fortress'}
local function delay(frames)
frames = frames or 1
script.sleep(frames, 'frames')
@ -116,29 +114,87 @@ end
test_envvars.require = clean_require
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()
if df.viewscreen_titlest:is_instance(dfhack.gui.getCurViewscreen()) then
return
end
print('Looking for title screen...')
for i = 0, 100 do
for i = 1, 100 do
local scr = dfhack.gui.getCurViewscreen()
if df.viewscreen_titlest:is_instance(scr) then
if is_title_screen(scr) then
print('Found title screen')
break
else
return
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)
end
-- wait for active screen to change
local prev_focus_string = focus_string
for frame_timeout = 1,100 do
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
print('Timed out waiting for screen to change')
break
::next_screen::
end
if not df.viewscreen_titlest:is_instance(dfhack.gui.getCurViewscreen()) then
error('Could not find title screen')
end
qerror(string.format('Could not load fortress (timed out at %s)',
focus_string))
end
local MODE_NAVIGATE_FNS = {
none = function() end,
title = ensure_title_screen,
local MODES = {
none = {order=1, detect=function() return true end},
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)
@ -266,7 +322,7 @@ local function load_tests(file, tests)
dfhack.printerr('Error when running file: ' .. tostring(err))
return false
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))
return false
end
@ -290,10 +346,9 @@ local function sort_tests(tests)
local test_index = utils.invert(tests)
table.sort(tests, function(a, b)
if a.config.mode ~= b.config.mode then
return VALID_MODES[a.config.mode] < VALID_MODES[b.config.mode]
else
return test_index[a] < test_index[b]
return MODES[a.config.mode].order < MODES[b.config.mode].order
end
return test_index[a] < test_index[b]
end)
end
@ -418,9 +473,19 @@ end
local function run_tests(tests, status, counts)
print(('Running %d tests'):format(#tests))
for _, test in pairs(tests) do
MODE_NAVIGATE_FNS[test.config.mode]()
local passed = run_test(test, status, counts)
status[test.full_name] = passed and TestStatus.PASSED or TestStatus.FAILED
status[test.full_name] = TestStatus.FAILED
if MODES[test.config.mode].failed then goto skip end
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)
end