From 73413038dfd0729c82baa0490d3ae79f72d1ad44 Mon Sep 17 00:00:00 2001 From: myk002 Date: Wed, 26 May 2021 09:45:49 -0700 Subject: [PATCH] add quickfort ecosystem functional test harness and a few initial tests --- data/CMakeLists.txt | 15 +- .../test/ecosystem/in/allbuildings-build.csv | 76 +++++ .../test/ecosystem/in/allbuildings-dig.csv | 76 +++++ .../test/ecosystem/in/allbuildings-spec.csv | 9 + .../library/test/ecosystem/in/basic-build.csv | 6 + .../library/test/ecosystem/in/basic-dig.csv | 6 + .../library/test/ecosystem/in/basic-place.csv | 6 + .../library/test/ecosystem/in/basic-spec.csv | 4 + test/quickfort/ecosystem.lua | 286 ++++++++++++++++++ 9 files changed, 482 insertions(+), 2 deletions(-) create mode 100644 data/blueprints/library/test/ecosystem/in/allbuildings-build.csv create mode 100644 data/blueprints/library/test/ecosystem/in/allbuildings-dig.csv create mode 100644 data/blueprints/library/test/ecosystem/in/allbuildings-spec.csv create mode 100644 data/blueprints/library/test/ecosystem/in/basic-build.csv create mode 100644 data/blueprints/library/test/ecosystem/in/basic-dig.csv create mode 100644 data/blueprints/library/test/ecosystem/in/basic-place.csv create mode 100644 data/blueprints/library/test/ecosystem/in/basic-spec.csv create mode 100644 test/quickfort/ecosystem.lua diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 19acb9261..6f085884d 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -1,2 +1,13 @@ -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/blueprints/ DESTINATION blueprints) -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/quickfort/ DESTINATION "${DFHACK_DATA_DESTINATION}/data/quickfort") +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/quickfort/ + DESTINATION "${DFHACK_DATA_DESTINATION}/data/quickfort") + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/blueprints/ + DESTINATION blueprints + FILES_MATCHING PATTERN blueprints/library/test EXCLUDE) + +if(BUILD_TESTS) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/blueprints/library/test/ + DESTINATION blueprints/library/test + ) +endif() + diff --git a/data/blueprints/library/test/ecosystem/in/allbuildings-build.csv b/data/blueprints/library/test/ecosystem/in/allbuildings-build.csv new file mode 100644 index 000000000..51ec706ef --- /dev/null +++ b/data/blueprints/library/test/ecosystem/in/allbuildings-build.csv @@ -0,0 +1,76 @@ +#build +a,Mg, ,CS,trackN, , , , , ,`, ,`,`,`, , , , ,`,`,`,`,`,# +b,Mh(1x1),S,CSa,trackS, , , , , ,Mw, ,`,wm,`, , , , ,`,`,`,`,`,# +c,Mhs(1x1),m,CSaa,trackE, ,`, , , ,`, ,`,`,`, , , , ,`,`,D,`,`,# + ,Mv,v,CSaaa,trackW, ,Msu, , , , , ,`,`,`,`,`,`, ,`,`,`,`,`,# + ,Mr(1x1),j,CSaaaa,trackNS, , , , ,`,Mws,`,`,wu,`,`,ew,`, ,`,`,`,`,`,# +d, ,A,CSd,trackNE, ,`,Msk, , , , ,`,`,`,`,`,`, ,`,`,`,`,`,# + , ,R,CSda,trackNW, ,`, , ,`,`,`,`,`,`,`,`,`, ,`,`,`,`,`,# +x, ,N,CSdaa,trackSE, ,Msm, , ,`,we,`,`,wn,`,`,es,`, ,`,`,k,`,`,# + , , ,CSdaaa,trackSW, , , , ,`,`,`,`,`,`,`,`,`, ,`,`,`,`,`,# +W, , ,CSdaaaa,trackEW, ,`,Msh, , , , ,`,`,`,`,`,`, ,`,`,`,`,`,# + , , ,CSdd,trackNSE, , , , , ,wq, ,`,wr,`,`,el,`, ,`,`,`,`,`,# +B, , ,CSdda,trackNSW, , , , , , , ,`,`,`,`,`,`, ,`,`,`,`,`,# + , ,o(1x1),CSddaa,trackNEW, , , , , , , ,`,`,`,`,`,`, ,`,`,ws,`,`,# +f, , ,CSddaaa,trackSEW, , , , , ,wM, ,`,wt,`,`,eg,`, ,`,`,`,`,`,# +h, ,Cf,CSddaaaa,trackNSEW, , , , , , , ,`,`,`,`,`,`, ,`,`,`,`,`,# +r, ,Cr,CSddd,trackrampN, , , , ,`,`,`,`,`,`,`,`,`, , , , , , ,# +s, ,Cu,CSddda,trackrampS, , , , ,`,wo,`,`,wl,`,`,ea,`, , ,gx(2x2),`, , ,# + , , ,CSdddaa,trackrampE, , , , ,`,`,`,`,`,`,`,`,`, , ,`,`, , ,# +t, ,Cx,CSdddaaa,trackrampW, , , , ,`,`,`,`,`,`,`,`,`,gd(2x2),`,gs(2x2),`,ga(2x2),`,# + , ,CF,CSdddaaaa,trackrampNS, , , , ,`,wk,`,`,ww,`,`,ek,`,`,`,`,`,`,`,# +gs(1x1), , ,CSdddd,trackrampNE, , , , ,`,`,`,`,`,`,`,`,`, , ,gw(2x2),`, , ,# +ga(1x1), , ,CSdddda,trackrampNW, , , , ,`,`,`,`,`,`,`,`,`, , ,`,`, , ,# +gd(1x1), , ,CSddddaa,trackrampSE, , , , ,`,wb,`,`,wz,`,`,en,`, , , , , , ,# +gw(1x1), , ,CSddddaaa,trackrampSW, , , , ,`,`,`,`,`,`,`,`,`, , , , , , ,# +gx(1x1), , ,CSddddaaaa,trackrampEW, , , , ,`,`,`,`,`,`,`,`,`, , , , , , ,# +l, , ,Ts,trackrampNSE, , , , ,`,wc,`,`,wh,`,`,ib,`, , , , , , ,# +y, , ,Tw,trackrampNSW, , , , ,`,`,`,`,`,`,`,`,`, , , , , , ,# +Y, , ,Tl,trackrampNEW, , , , ,`,`,`,`,`,`,`,`,`, , , , , , ,# + , , ,Tp,trackrampSEW, , , , ,`,wf,`,`,wy,`,`,ic,`, , , , , , ,# + , , ,Tc,trackrampNSEW, , , , ,`,`,`,`,`,`,`,`,`, , , , , , ,# + , , , , , , , , ,`,`,`,`,`,`, , , , , , , , , ,# + , , , , , , , , ,`,wv,`,`,wd,`, , , , , , , , , ,# + , , , , , , , , ,`,`,`,`,`,`, , , , , , , , , ,# + , , , , , , , , ,`,`,`, , , , , , , , , , , , ,# + , , , , , , , , ,`,wj,`, , , , , , , , , , , , ,# + , , , , , , , , ,`,`,`, , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# +#> + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# diff --git a/data/blueprints/library/test/ecosystem/in/allbuildings-dig.csv b/data/blueprints/library/test/ecosystem/in/allbuildings-dig.csv new file mode 100644 index 000000000..dc2c48d2c --- /dev/null +++ b/data/blueprints/library/test/ecosystem/in/allbuildings-dig.csv @@ -0,0 +1,76 @@ +#dig +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# + ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# + ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +h,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# + , , , , , , , , , , , , , , , , , , , , , , , ,# +#> + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# +r, , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , ,# diff --git a/data/blueprints/library/test/ecosystem/in/allbuildings-spec.csv b/data/blueprints/library/test/ecosystem/in/allbuildings-spec.csv new file mode 100644 index 000000000..2ec2688e7 --- /dev/null +++ b/data/blueprints/library/test/ecosystem/in/allbuildings-spec.csv @@ -0,0 +1,9 @@ +#notes +description=all the buildings that work +width=24 +height=37 +depth=2 +#ignore +note that this test is very incomplete since blueprint has incomplete +or incorrect building detection for many building types. the issues +will be fixed over time. diff --git a/data/blueprints/library/test/ecosystem/in/basic-build.csv b/data/blueprints/library/test/ecosystem/in/basic-build.csv new file mode 100644 index 000000000..82b7fdf48 --- /dev/null +++ b/data/blueprints/library/test/ecosystem/in/basic-build.csv @@ -0,0 +1,6 @@ +#build + , ,d, , ,# + ,f, , , ,# +d, ,b, ,d,# + ,h, , , ,# + , ,d, , ,# diff --git a/data/blueprints/library/test/ecosystem/in/basic-dig.csv b/data/blueprints/library/test/ecosystem/in/basic-dig.csv new file mode 100644 index 000000000..391bf8fc5 --- /dev/null +++ b/data/blueprints/library/test/ecosystem/in/basic-dig.csv @@ -0,0 +1,6 @@ +#dig + , ,d, , ,# + ,d,d,d, ,# +d,d,d,d,d,# + ,d,d,d, ,# + , ,d, , ,# diff --git a/data/blueprints/library/test/ecosystem/in/basic-place.csv b/data/blueprints/library/test/ecosystem/in/basic-place.csv new file mode 100644 index 000000000..a32e03b9b --- /dev/null +++ b/data/blueprints/library/test/ecosystem/in/basic-place.csv @@ -0,0 +1,6 @@ +#place + , , , , ,# + , , , , ,# + ,f(1x1), ,f(1x1), ,# + , , , , ,# + , , , , ,# diff --git a/data/blueprints/library/test/ecosystem/in/basic-spec.csv b/data/blueprints/library/test/ecosystem/in/basic-spec.csv new file mode 100644 index 000000000..828b2ca96 --- /dev/null +++ b/data/blueprints/library/test/ecosystem/in/basic-spec.csv @@ -0,0 +1,4 @@ +#notes +description=basic test for all phases +width=5 +height=5 diff --git a/test/quickfort/ecosystem.lua b/test/quickfort/ecosystem.lua new file mode 100644 index 000000000..a808f8c20 --- /dev/null +++ b/test/quickfort/ecosystem.lua @@ -0,0 +1,286 @@ +-- tests the quickfort ecosystem end-to-end via: +-- .csv -> quickfort/buildingplan/dig-dug -> blueprint -> .csv +-- +-- test cases are sets of .csv files in the +-- blueprints/library/test/ecosystem/in directory +-- +-- test metadata is stored in an associated #notes blueprint: +-- description (required) +-- width (required) +-- height (required) +-- depth (default is 1) +-- +-- blueprint, buildingplan, and dig-dug plugins must be loaded and enabled +-- +-- note that this test harness cannot (yet) test #query blueprints that define +-- rooms since furniture is not actually built during the test. It also cannot +-- test blueprints that #build flooring and then #build a workshop on top, again +-- since the flooring is never actually built. + +config = { + mode = 'fortress', +} + +local guidm = require('gui.dwarfmode') +local quickfort_command = reqscript('internal/quickfort/command') +local quickfort_list = reqscript('internal/quickfort/list') + +local blueprints_dir = 'blueprints/' +local input_dir = 'library/test/ecosystem/in/' +local output_dir = 'library/test/ecosystem/out/' + +local mode_names = {'dig', 'build', 'place', 'query'} + +local function bad_spec(expected, varname, basename, bad_value) + qerror(('expected %s for %s in "%s" test spec; got "%s"'): + format(expected, varname, basename, bad_value)) +end + +local function get_positive_int(numstr, varname, basename) + local num = tonumber(numstr) + if not num or num <= 0 or num ~= math.floor(num) then + bad_spec('positive integer', varname, basename, numstr) + end + return num +end + +local function get_blueprint_sets() + -- find test blueprints with `quickfort list` + local mock_print = mock.func() + mock.patch(quickfort_list, 'print', mock_print, + function() + dfhack.run_script('quickfort', 'list', '-l', input_dir) + end) + + -- group blueprint sets + local sets = {} + for _,args in ipairs(mock_print.call_args) do + local line = args[1] + local _,_,listnum,fname,mode = line:find('(%d+)%) (%S+) %((%S+)%)$') + if listnum then + local _,_,file_part = fname:find('/([^/]+)$') + local _,_,basename = file_part:find('^([^-.]+)') + if not sets[basename] then sets[basename] = {spec={}, modes={}} end + sets[basename].modes[mode] = { + listnum=listnum, + input_filepath=blueprints_dir..fname, + output_filepath=blueprints_dir..output_dir..file_part} + end + end + + -- load test specs + for basename,set in pairs(sets) do + local spec, notes = set.spec, set.modes.notes + + -- set defaults + spec.depth = '1' + + -- read spec + mock.patch(quickfort_command, 'print', + function(text) + for line in text:gmatch('[^\n]*') do + local _,_,var,val = line:find('%*?%s*([^=]+)=(.*)') + if var then spec[var] = val end + end + end, + function() + dfhack.run_script('quickfort', 'run', '-q', notes.listnum) + end) + + -- validate spec and convert numbers to numeric vars + if not spec.description or spec.description == '' then + qerror(('missing description in test spec for "%s"'): + format(basename)) + end + spec.width = get_positive_int(spec.width, 'width', basename) + spec.height = get_positive_int(spec.height, 'height', basename) + spec.depth = get_positive_int(spec.depth, 'depth', basename) + end + + return sets +end + +local function is_usable_test_tile(pos) + local tiletype = dfhack.maps.getTileType(pos) + local tileattrs = df.tiletype.attrs[tiletype] + local good_material = tileattrs.material == df.tiletype_material.STONE or + tileattrs.material == df.tiletype_material.FEATURE or + tileattrs.material == df.tiletype_material.MINERAL + local good_shape = tileattrs.shape == df.tiletype_shape.WALL + return good_material and good_shape +end + +local function get_test_area(area, spec) + -- return with success if our current area meets or exceeds requirements + if area.width >= spec.width and area.height >= spec.height and + area.depth >= spec.depth then + return true + end + + -- return with failure if the test requirements cannot ever be satisfied by + -- the current map + if spec.width > df.global.world.map.x_count - 2 or + spec.height > df.global.world.map.y_count - 2 or + spec.depth > df.global.world.map.z_count then + return false + end + + -- keep this simple for now. just go down the layers and check the region + -- starting at the upper left corner of each level. + for z_start = df.global.world.map.z_count-1,0,-1 do + local z_end = z_start - spec.depth + 1 + if z_end < 1 then return false end + for z = z_start,z_end,-1 do + for y = 1,spec.height do + for x = 1,spec.width do + if not is_usable_test_tile(xyz2pos(x, y, z)) then + -- next check should start on the z-level below this one + z_start = z + goto continue + end + end + end + end + do + area.width, area.height, area.depth = + spec.width, spec.height, spec.depth + area.pos = {x=1, y=1, z=z_start} + return true + end + ::continue:: + end +end + +local function get_cursor_arg(pos) + return ('--cursor=%d,%d,%d'):format(pos.x, pos.y, pos.z) +end + +local function quickfort_cmd(cmd, listnum, pos) + dfhack.run_script('quickfort', cmd, '-q', listnum, get_cursor_arg(pos)) +end + +local function quickfort_run(listnum, pos) + quickfort_cmd('run', listnum, pos) +end + +local function quickfort_undo(listnum, pos) + quickfort_cmd('undo', listnum, pos) +end + +local function designate_area(pos, spec) + local endx, endy, endz = pos.x + spec.width - 1, pos.y + spec.height - 1, + pos.z - spec.depth + 1 + for z = pos.z,endz,-1 do for y = pos.y,endy do for x = pos.x,endx do + dfhack.maps.getTileFlags(xyz2pos(x, y, z)).dig = + df.tile_dig_designation.Default + end end end +end + +local function run_blueprint(basename, set, pos) + local blueprint_args = {'blueprint', tostring(set.spec.width), + tostring(set.spec.height), + tostring(-set.spec.depth), + output_dir..basename, get_cursor_arg(pos)} + for _,mode_name in pairs(mode_names) do + if set.modes[mode_name] then table.insert(blueprint_args, mode_name) end + end + dfhack.run_command(blueprint_args) +end + +local function reset_area(area, spec) + dfhack.run_command('tiletypes-command', 'f', 'any') + dfhack.run_command('tiletypes-command', 'p', 'any') + dfhack.run_command('tiletypes-command', 'p', 's', 'wall') + dfhack.run_command('tiletypes-command', 'p', 'sp', 'normal') + dfhack.run_command('tiletypes-command', 'p', 'h', '1') + dfhack.run_command('tiletypes-command', 'r', tostring(spec.width), + tostring(spec.height), tostring(spec.depth)) + local tiletypes_pos = copyall(area.pos) + tiletypes_pos.z = tiletypes_pos.z - spec.depth + 1 -- tiletypes goes up z's + + -- we fake the cursor position so 'tiletypes-here' works even if there is no + -- actual live game cursor + local saved_cursor = guidm.getCursorPos() + guidm.setCursorPos(tiletypes_pos) + dfhack.run_command('tiletypes-here') + if saved_cursor then guidm.setCursorPos(saved_cursor) end +end + +function test.end_to_end() + -- read in test plan + local sets = get_blueprint_sets() + + local area = {width=0, height=0, depth=0} + for basename,set in pairs(sets) do + print(('running quickfort test: "%s": %s'): + format(basename, set.spec.description)) + + -- find an unused area of the map that meets requirements, else skip + if not get_test_area(area, set.spec) then + print(('cannot find unused map area to test set "%s"; skipping'): + format(basename)) + goto continue + end + + -- quickfort run #dig blueprint (or just designate the whole block if + -- there is no #dig blueprint) + local modes = set.modes + if modes.dig then + quickfort_run(modes.dig.listnum, area.pos) + else + designate_area(area.pos, set.spec) + end + + -- run dig-dug to dig out designated tiles + dfhack.run_command('dig-dug') + + -- quickfort run remaining blueprints + for _,mode_name in pairs(mode_names) do + if mode_name ~= 'dig' and modes[mode_name] then + quickfort_run(modes[mode_name].listnum, area.pos) + end + end + + -- run blueprint to generate files in output dir + run_blueprint(basename, set, area.pos) + + -- quickfort undo blueprints + for _,mode_name in pairs(mode_names) do + if modes[mode_name] then + quickfort_undo(modes[mode_name].listnum, area.pos) + end + end + + -- run tiletypes to reset tiles in area to hidden walls + reset_area(area, set.spec) + + -- compare md5sum of input and output files + local md5File = dfhack.internal.md5File + for mode,mode_data in pairs(modes) do + if mode == 'notes' then goto continue end + local input_filepath = mode_data.input_filepath + local output_filepath = mode_data.output_filepath + local input_hash, input_size = md5File(input_filepath) + local output_hash, output_size = md5File(output_filepath) + expect.eq(input_hash, output_hash, + 'compare blueprint contents to input: '..output_filepath) + expect.eq(input_size, output_size, + 'compare blueprint length to input: '..output_filepath) + if not output_hash then goto continue end + if input_hash ~= output_hash or input_size ~= output_size then + -- show diff + local input, output = + io.open(input_filepath, 'r'), io.open(output_filepath, 'r') + local input_lines, output_lines = {}, {} + for l in input:lines() do table.insert(input_lines, l) end + for l in output:lines() do table.insert(output_lines, l) end + input:close() + output:close() + expect.table_eq(input_lines, output_lines) + end + ::continue:: + end + + ::continue:: + end +end