Merge branch 'DFHack:develop' into patch-1

develop
Ryan Williams 2021-06-23 23:08:01 -07:00 committed by GitHub
commit 5807d6fbfa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 91 additions and 7 deletions

@ -83,6 +83,19 @@ local function delay(frames)
script.sleep(frames, 'frames') script.sleep(frames, 'frames')
end end
-- Will call the predicate_fn every frame until it returns true. If it fails to
-- return true before timeout_frames have elapsed, throws an error. If
-- timeout_frames is not specified, defaults to 100.
local function delay_until(predicate_fn, timeout_frames)
timeout_frames = tonumber(timeout_frames) or 100
repeat
delay()
if predicate_fn() then return end
timeout_frames = timeout_frames - 1
until timeout_frames < 0
error('timed out while waiting for predicate to return true')
end
local function clean_require(module) local function clean_require(module)
-- wrapper around require() - forces a clean load of every module to ensure -- wrapper around require() - forces a clean load of every module to ensure
-- that modules checking for dfhack.internal.IN_TEST at load time behave -- that modules checking for dfhack.internal.IN_TEST at load time behave
@ -245,7 +258,6 @@ local function wrap_expect(func, private)
orig_printerr('Check failed! ' .. (msg or '(no message)')) orig_printerr('Check failed! ' .. (msg or '(no message)'))
-- Generate a stack trace with all function calls in the same file as the caller to expect.*() -- Generate a stack trace with all function calls in the same file as the caller to expect.*()
-- (this produces better stack traces when using helpers in tests) -- (this produces better stack traces when using helpers in tests)
-- Skip any frames corresponding to C calls, which could be pcall() / with_finalize()
local frame = 2 local frame = 2
local caller_src local caller_src
while true do while true do
@ -254,10 +266,9 @@ local function wrap_expect(func, private)
if not caller_src then if not caller_src then
caller_src = info.short_src caller_src = info.short_src
end end
if info.what == 'Lua' then -- Skip any frames corresponding to C calls, or Lua functions defined in another file
if info.short_src ~= caller_src then -- these could include pcall(), with_finalize(), etc.
break if info.what == 'Lua' and info.short_src == caller_src then
end
orig_printerr((' at %s:%d'):format(info.short_src, info.currentline)) orig_printerr((' at %s:%d'):format(info.short_src, info.currentline))
end end
frame = frame + 1 frame = frame + 1
@ -275,6 +286,7 @@ local function build_test_env()
expect = {}, expect = {},
mock = mock, mock = mock,
delay = delay, delay = delay,
delay_until = delay_until,
require = clean_require, require = clean_require,
reqscript = clean_reqscript, reqscript = clean_reqscript,
} }

@ -51,6 +51,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
- `embark-assistant`: slightly improved performance of surveying and improved code a little - `embark-assistant`: slightly improved performance of surveying and improved code a little
## Lua ## Lua
- new string utility function: ``string:wrap(width)`` wraps a string at space-separated word boundaries
- ``gui.Painter``: fixed error when calling ``viewport()`` method - ``gui.Painter``: fixed error when calling ``viewport()`` method
- `reveal`: now exposes ``unhideFlood(pos)`` functionality to Lua - `reveal`: now exposes ``unhideFlood(pos)`` functionality to Lua
- ``utils.processArgsGetopt()``: now returns negative numbers (e.g. ``-10``) in the list of positional parameters instead of treating it as an option string equivalent to ``-1 -0`` - ``utils.processArgsGetopt()``: now returns negative numbers (e.g. ``-10``) in the list of positional parameters instead of treating it as an option string equivalent to ``-1 -0``
@ -69,6 +70,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
- The ``test/main`` command to invoke the test harness has been renamed to just ``test`` - The ``test/main`` command to invoke the test harness has been renamed to just ``test``
- DFHack unit tests must now match any output expected to be printed via ``dfhack.printerr()`` - DFHack unit tests must now match any output expected to be printed via ``dfhack.printerr()``
- Fortress mode is now supported for unit tests (allowing tests that require a fortress map to be loaded) - note that these tests are skipped by continuous integration for now, pending a suitable test fortress - Fortress mode is now supported for unit tests (allowing tests that require a fortress map to be loaded) - note that these tests are skipped by continuous integration for now, pending a suitable test fortress
- Unit tests can now use ``delay_until(predicate_fn, timeout_frames)`` to delay until a condition is met
# 0.47.05-r1 # 0.47.05-r1

@ -369,6 +369,43 @@ function string:endswith(suffix)
return self:sub(-#suffix) == suffix or #suffix == 0 return self:sub(-#suffix) == suffix or #suffix == 0
end end
-- Inserts newlines into a string so no individual line exceeds the given width.
-- Lines are split at space-separated word boundaries. Any existing newlines are
-- kept in place. If a single word is longer than width, it is split over
-- multiple lines.
function string:wrap(width)
local wrapped_text = {}
for line in self:gmatch('[^\n]*') do
local line_start_pos = 1
local wrapped_line = line:gsub(
'%s*()(%S+)()',
function(start_pos, word, end_pos)
-- word fits within the current line
if end_pos - line_start_pos <= width then return end
-- word needs to go on the next line, but is not itself longer
-- than the specified width
if #word <= width then
line_start_pos = start_pos
return '\n' .. word
end
-- word is too long to fit on one line and needs to be split up
local num_chars, str = 0, start_pos == 1 and '' or '\n'
repeat
local word_frag = word:sub(num_chars + 1, num_chars + width)
str = str .. word_frag
num_chars = num_chars + #word_frag
if num_chars < #word then
str = str .. '\n'
end
line_start_pos = start_pos + num_chars
until end_pos - line_start_pos <= width
return str .. word:sub(num_chars + 1)
end)
table.insert(wrapped_text, wrapped_line)
end
return table.concat(wrapped_text, '\n')
end
-- String conversions -- String conversions
function dfhack.persistent:__tostring() function dfhack.persistent:__tostring()

@ -24,11 +24,11 @@ function expect.nil_(value, comment)
end end
function expect.eq(a, b, comment) function expect.eq(a, b, comment)
return a == b, comment, ('%s ~= %s'):format(a, b) return a == b, comment, ('"%s" ~= "%s"'):format(a, b)
end end
function expect.ne(a, b, comment) function expect.ne(a, b, comment)
return a ~= b, comment, ('%s == %s'):format(a, b) return a ~= b, comment, ('"%s" == "%s"'):format(a, b)
end end
function expect.lt(a, b, comment) function expect.lt(a, b, comment)

@ -0,0 +1,33 @@
-- tests string functions added by dfhack.lua
function test.startswith()
expect.true_(('abcd'):startswith(''))
expect.true_(('abcd'):startswith('abc'))
expect.false_(('abcd'):startswith('bcd'))
expect.false_(('abcd'):startswith('abcde'))
expect.true_((''):startswith(''))
expect.false_((''):startswith('a'))
end
function test.endswith()
expect.true_(('abcd'):endswith(''))
expect.true_(('abcd'):endswith('bcd'))
expect.false_(('abcd'):endswith('abc'))
expect.false_(('abcd'):endswith('zabcd'))
expect.true_((''):endswith(''))
expect.false_((''):endswith('a'))
end
function test.wrap()
expect.eq('hello world', ('hello world'):wrap(20))
expect.eq('hello world', ('hello world'):wrap(20))
expect.eq('hello world\nhow are you?',('hello world how are you?'):wrap(12))
expect.eq('hello\nworld', ('hello world'):wrap(5))
expect.eq('hello\nworld', ('hello world'):wrap(5))
expect.eq('hello\nworld', ('hello world'):wrap(8))
expect.eq('hel\nlo\nwor\nld', ('hello world'):wrap(3))
expect.eq('hel\nloo\nwor\nldo', ('helloo worldo'):wrap(3))
expect.eq('', (''):wrap(10))
end