Add a Lua unit_test module only available in [test] scenarios (#5708)

It contains fire_wml_menu_item along with a set of new assert functions
This commit is contained in:
Celtic Minstrel 2021-04-25 21:04:50 -04:00 committed by GitHub
parent 5dde3d735d
commit 31421f3558
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 597 additions and 94 deletions

171
data/lua/core/unit_test.lua Normal file
View file

@ -0,0 +1,171 @@
--[========[Unit Test Helpers]========]
if rawget(_G, 'unit_test') ~= nil then
print("Loading unit_test module...")
--! Causes the test to complete with a specific result.
--! This is mostly an internal detail but might very occasionally be useful to produce a result other than pass or fail
function unit_test.finish(result)
wesnoth.wml_actions.endlevel{
test_result = result,
linger_mode = true
}
end
--! End the test in unconditional failure
--! This does not immediately terminate the test; any assertions in the current event will still be run.
--! Without calling either succeed() or fail(), the test will never end.
--! This allows a test to run over multiple events and even multiple turns.
function unit_test.fail()
unit_test.finish('fail')
end
--! End the test in success if all assertions passed, otherwise in failure
--! Without calling either succeed() or fail(), the test will never end.
--! This allows a test to run over multiple events and even multiple turns.
function unit_test.succeed()
unit_test.finish('pass')
end
--! Convert a value to a string for output
--! Strings are output quoted, all other types just use tostring
function unit_test.tostring(val)
-- This exists so custom behaviour can be added for specific types if required.
if type(val) == 'string' then
-- Strings are output quoted
return string.format('%q', val)
end
return tostring(val)
end
--! Output a log message to the test output
function unit_test.log(prefix, message)
std_print(prefix .. ': ' .. message)
end
--! Fail the test with a message unless the condition is true
function unit_test.assert(condition, message)
if not condition then
unit_test.log('Assertion failed', message)
unit_test.fail()
end
end
--! Fail the test with a message unless the function exits with any error
function unit_test.assert_throws(fcn, message)
local result = pcall(fcn)
if result ~= false then
unit_test.log('Assertion failed (should be an error)', message)
unit_test.fail()
end
end
local function match_error(expect, have)
if type(expect) == 'string' then
local m = string.match(have, '^%[.-%]:%d: (.*)')
if m then return expect == m end
end
return expect == have
end
--! Fail the test with a message unless the function exits with a specific error
function unit_test.assert_throws_with(expect_err, fcn, message)
local result, err = pcall(fcn)
if result ~= false or not match_error(expect_err, err) then
unit_test.log('Assertion failed (should be an error: ' .. unit_test.tostring(expect_err) .. ' but got ' .. unit_test.tostring(err) .. ')', message)
unit_test.fail()
end
end
--! Fail the test with a message unless the function exits with no errors
function unit_test.assert_nothrow(fcn, message)
local result, err = pcall(fcn)
if result ~= true then
unit_test.log('Assertion failed (should not be an error)', message)
unit_test.log(' The following error was raised', unit_test.tostring(err))
unit_test.fail()
end
end
--! Fail the test with a message unless a == b
function unit_test.assert_equal(a, b, message)
if a ~= b then
local expr = ('expected %s == %s'):format(unit_test.tostring(a), unit_test.tostring(b))
unit_test.log('Assertion failed (' .. expr .. ')', message)
unit_test.fail()
end
end
--! Fail the test with a message unless a ~= b
function unit_test.assert_not_equal(a, b, message)
if a == b then
local expr = ('expected %s ~= %s'):format(unit_test.tostring(a), unit_test.tostring(b))
unit_test.log('Assertion failed (' .. expr .. ')', message)
unit_test.fail()
end
end
--! Fail the test with a message unless a > b
function unit_test.assert_greater(a, b, message)
if a <= b then
local expr = ('expected %s > %s'):format(unit_test.tostring(a), unit_test.tostring(b))
unit_test.log('Assertion failed (' .. expr .. ')', message)
unit_test.fail()
end
end
--! Fail the test with a message unless a < b
function unit_test.assert_less(a, b, message)
if a >= b then
local expr = ('expected %s < %s'):format(unit_test.tostring(a), unit_test.tostring(b))
unit_test.log('Assertion failed (' .. expr .. ')', message)
unit_test.fail()
end
end
--! Fail the test with a message unless a >= b
function unit_test.assert_greater_equal(a, b, message)
if a < b then
local expr = ('expected %s >= %s'):format(unit_test.tostring(a), unit_test.tostring(b))
unit_test.log('Assertion failed (' .. expr .. ')', message)
unit_test.fail()
end
end
--! Fail the test with a message unless a <= b
function unit_test.assert_less_equal(a, b, message)
if a > b then
local expr = ('expected %s <= %s'):format(unit_test.tostring(a), unit_test.tostring(b))
unit_test.log('Assertion failed (' .. expr .. ')', message)
unit_test.fail()
end
end
--! Fail the test with a message unless val is in the range [min, max]
function unit_test.assert_in_range(val, min, max, message)
if val < min or val > max then
local expr = ('expected %s <= %s <= %s'):format(unit_test.tostring(min), unit_test.tostring(val), unit_test.tostring(max))
unit_test.log('Assertion failed (' .. expr .. ')', message)
unit_test.fail()
end
end
--! Fail the test with a message unless a == b within the tolerance
--! Intended for comparing real numbers
function unit_test.assert_approx_equal(a, b, tolerance, message)
if math.abs(a - b) > tolerance then
local expr = ('expected %s == %s (within %s)'):format(unit_test.tostring(a), unit_test.tostring(b), unit_test.tostring(tolerance))
unit_test.log('Assertion failed (' .. expr .. ')', message)
unit_test.fail()
end
end
--! Fail the test with a message unless the source string contains the fragment as a substring
function unit_test.assert_contains(source, fragment, message)
if not string.find(source, fragment, 1, true) then
unit_test.log('Assertion failed (' .. source .. ' contains ' .. fragment .. ')', message)
unit_test.fail()
end
end
end

View file

@ -26,42 +26,29 @@
[lua]
code = <<
local function assert_equal(source, result)
if source ~= result then
-- Fail the test
wesnoth.wml_actions.endlevel({test_result = "fail", linger_mode = true})
end
end
local function assert_contains(source, fragment)
if not string.find(source, fragment, 1, true) then
-- Fail the test
wesnoth.wml_actions.endlevel({test_result = "fail", linger_mode = true})
end
end
assert_equal(wesnoth.as_text("a"), '"a"')
assert_equal(wesnoth.as_text(1), "1")
assert_equal(wesnoth.as_text(true), "true")
assert_equal(wesnoth.as_text({ "a", "b", "c" }), '{"1":"a","2":"b","3":"c"}')
unit_test.assert_equal(wesnoth.as_text("a"), '"a"')
unit_test.assert_equal(wesnoth.as_text(1), "1")
unit_test.assert_equal(wesnoth.as_text(true), "true")
unit_test.assert_equal(wesnoth.as_text({ "a", "b", "c" }), '{"1":"a","2":"b","3":"c"}')
-- associative table iteration order not defined and can vary between runs even when the data remains identical
local tab_txt = wesnoth.as_text({ a = 1, b = false, c = "d" })
assert_contains(tab_txt, '"a":1')
assert_contains(tab_txt, '"b":false')
assert_contains(tab_txt, '"c":"d"')
unit_test.assert_contains(tab_txt, '"a":1')
unit_test.assert_contains(tab_txt, '"b":false')
unit_test.assert_contains(tab_txt, '"c":"d"')
local wml_tab_txt = wesnoth.as_text(wml.variables["var"])
assert_contains(wml_tab_txt, '{"1":{"1":"one","2":{"1":{"1":"first","2":{')
assert_contains(wml_tab_txt, '"a":1')
assert_contains(wml_tab_txt, '"b":5')
assert_contains(wml_tab_txt, '"c":true')
assert_contains(wml_tab_txt, ',"2":{"1":"two","2":{"1":{"1":"second","2":{')
assert_contains(wml_tab_txt, '"x":9')
assert_contains(wml_tab_txt, '"y":3')
assert_contains(wml_tab_txt, '"z":false')
unit_test.assert_contains(wml_tab_txt, '{"1":{"1":"one","2":{"1":{"1":"first","2":{')
unit_test.assert_contains(wml_tab_txt, '"a":1')
unit_test.assert_contains(wml_tab_txt, '"b":5')
unit_test.assert_contains(wml_tab_txt, '"c":true')
unit_test.assert_contains(wml_tab_txt, ',"2":{"1":"two","2":{"1":{"1":"second","2":{')
unit_test.assert_contains(wml_tab_txt, '"x":9')
unit_test.assert_contains(wml_tab_txt, '"y":3')
unit_test.assert_contains(wml_tab_txt, '"z":false')
-- Pass the test. Doesn't do anything if any of the above assertions has failed.
wesnoth.wml_actions.endlevel({test_result = "pass", linger_mode = true})
unit_test.succeed()
>>
[/lua]
[/event]

View file

@ -27,3 +27,292 @@
{RETURN ([not][true][/true][/not])}
[/event]
)}
# Tests that "assert true, pass" works.
# This is a sanity check of the unit testing mechanism.
{GENERIC_UNIT_TEST "test_lua_assert" (
[event]
name = start
[lua]
code=<<
unit_test.assert(true, 'assert true')
unit_test.succeed()
>>
[/lua]
[/event]
)}
# Tests that "assert false, return true" works.
# This is a sanity check of the unit testing mechanism.
{GENERIC_UNIT_TEST "test_lua_assert_fail" (
[event]
name = start
[lua]
code=<<
unit_test.assert(false, 'assert false')
unit_test.succeed()
>>
[/lua]
[/event]
)}
# Sanity check that a fail() in a fired event causes the test to fail
{GENERIC_UNIT_TEST "test_lua_assert_fail_in_fired_event" (
[event]
id = fail_event
[lua]
code=<<
unit_test.fail()
>>
[/lua]
[/event]
[event]
name = start
[fire_event]
id = fail_event
[/fire_event]
[lua]
code=<<
unit_test.succeed()
>>
[/lua]
[/event]
)}
# Test the comparison assertions from the Lua unit_test module
{GENERIC_UNIT_TEST "test_lua_assert_compare" (
[event]
name=start
[lua]
code=<<
unit_test.assert_equal('foo', 'foo', 'string equality')
unit_test.assert_not_equal('foo', 'bar', 'string inequality')
unit_test.assert_greater('foo', 'bar', 'string ordering')
unit_test.assert_equal(1, 1, 'numeric equality')
unit_test.assert_not_equal(1, 2, 'numeric inequality')
unit_test.assert_greater(2, 1, 'numeric greater-than')
unit_test.assert_less(1, 2, 'numeric less-than')
unit_test.assert_in_range(1, 0, 2, 'numeric in-range')
unit_test.assert_approx_equal(1, 1.0001, 0.001, 'numeric approx-equal')
unit_test.assert_contains('abcdef', 'bc', 'substring')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_compare_fail1" (
[event]
name=start
[lua]
code=<<
unit_test.assert_equal('foo', 'bar', 'string equality')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_compare_fail2" (
[event]
name=start
[lua]
code=<<
unit_test.assert_not_equal('foo', 'foo', 'string inequality')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_compare_fail3" (
[event]
name=start
[lua]
code=<<
unit_test.assert_less('foo', 'bar', 'string ordering')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_compare_fail4" (
[event]
name=start
[lua]
code=<<
unit_test.assert_equal(1, 2, 'numeric equality')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_compare_fail5" (
[event]
name=start
[lua]
code=<<
unit_test.assert_not_equal(1, 1, 'numeric inequality')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_compare_fail6" (
[event]
name=start
[lua]
code=<<
unit_test.assert_greater(1, 2, 'numeric greater-than')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_compare_fail7" (
[event]
name=start
[lua]
code=<<
unit_test.assert_less(2, 1, 'numeric less-than')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_compare_fail8" (
[event]
name=start
[lua]
code=<<
unit_test.assert_in_range(1, 2, 5, 'numeric in-range')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_compare_fail9" (
[event]
name=start
[lua]
code=<<
unit_test.assert_approx_equal(1, 1.001, 0.0001, 'numeric approx-equal')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_errors1" (
[event]
name=start
[lua]
code=<<
unit_test.assert_nothrow(function() end, 'no error')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_errors2" (
[event]
name=start
[lua]
code=<<
unit_test.assert_nothrow(function() error('error') end, 'no error')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_errors3" (
[event]
name=start
[lua]
code=<<
unit_test.assert_throws(function() end, 'any error')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_errors4" (
[event]
name=start
[lua]
code=<<
unit_test.assert_throws(function() error('error') end, 'any error')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_errors5" (
[event]
name=start
[lua]
code=<<
unit_test.assert_throws_with('error', function() end, 'specific error')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_errors6" (
[event]
name=start
[lua]
code=<<
unit_test.assert_throws_with('error', function() error('error', 0) end, 'specific error')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_errors7" (
[event]
name=start
[lua]
code=<<
unit_test.assert_throws_with('error', function() error('foo', 0) end, 'specific error')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_errors8" (
[event]
name=start
[lua]
code=<<
unit_test.assert_throws_with('error', function() error('error') end, 'specific error')
unit_test.succeed()
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_assert_errors9" (
[event]
name=start
[lua]
code=<<
unit_test.assert_throws_with('error', function() error('foo') end, 'specific error')
unit_test.succeed()
>>
[/lua]
[/event]
)}

View file

@ -2,17 +2,14 @@
[event]
name = prestart
[lua]
code = << a,b,c,d = wesnoth.dofile("test/macros/test.lua")
wml.variables["a"] = a
wml.variables["b"] = b
wml.variables["c"] = c
wml.variables["d"] = d >>
code = <<
local a,b,c,d = wesnoth.dofile("test/macros/test.lua")
unit_test.assert_equal(a, 1, 'first return value')
unit_test.assert_equal(b, 2, 'second return value')
unit_test.assert_equal(c, 3, 'third return value')
unit_test.assert_equal(d, 4, 'fourth return value')
unit_test.succeed()
>>
[/lua]
{ASSERT ({VARIABLE_CONDITIONAL a equals 1})}
{ASSERT ({VARIABLE_CONDITIONAL b equals 2})}
{ASSERT ({VARIABLE_CONDITIONAL c equals 3})}
{ASSERT ({VARIABLE_CONDITIONAL d equals 4})}
{SUCCEED}
[/event]
)}

View file

@ -2,11 +2,12 @@
[event]
name = prestart
[lua]
code = << local s = wesnoth.sides.find({})
local result = (s[1].side == 1) and (s[2].side == 2)
wml.variables["result"] = result >>
code = <<
local s = wesnoth.sides.find({})
unit_test.assert_equal(s[1].side, 1)
unit_test.assert_equal(s[2].side, 2)
unit_test.succeed()
>>
[/lua]
{RETURN ({VARIABLE_CONDITIONAL result boolean_equals true})}
[/event]
)}

View file

@ -7,77 +7,70 @@
code = <<
local T = wml.tag
local function assert_equal(expect, status)
if status ~= expect then
-- Fail the test
wesnoth.wml_actions.endlevel({test_result = "fail", linger_mode = true})
end
end
-- Empty strings are not allowed.
assert_equal(false, pcall(function()
unit_test.assert_throws(function()
local table = {T[""] {}}
wml.tostring(table)
end))
end, 'Tag names cannot be empty')
-- Non-ASCII characters are not allowed.
assert_equal(false, pcall(function()
unit_test.assert_throws(function()
local table = {T["hääyö"] {}}
wml.tostring(table)
end))
end, 'Tag names cannot contain non-ASCII characters')
-- Control characters are not allowed.
assert_equal(false, pcall(function()
unit_test.assert_throws(function()
local table = {T["two\nlines"] {}}
wml.tostring(table)
end))
end, 'Tag names cannot contain control characters')
-- Alphanumeric characters are allowed.
assert_equal(true, pcall(function()
unit_test.assert_nothrow(function()
local table = {T.abcDEF123 {}}
wml.tostring(table)
end))
end, 'Tag names can contain alphanumeric characters')
-- Tag names can start with numbers.
assert_equal(true, pcall(function()
unit_test.assert_nothrow(function()
local table = {T["123abc"] {}}
wml.tostring(table)
end))
end, 'Tag names can start with digits')
-- Symbols other than underscore are not allowed.
assert_equal(false, pcall(function()
unit_test.assert_throws(function()
local table = {T["O\'Neal"] {}}
wml.tostring(table)
end))
end, 'Tag names cannot contain symbols')
-- Underscores are allowed.
assert_equal(true, pcall(function()
unit_test.assert_nothrow(function()
local table = {T.snake_case {}}
wml.tostring(table)
end))
end, 'Tag names can contain underscores')
-- Tag names can start with underscores.
assert_equal(true, pcall(function()
unit_test.assert_nothrow(function()
local table = {T._reserved {}}
wml.tostring(table)
end))
end, 'Tag names can start with underscores')
-- An underscore by itself isn't allowed.
assert_equal(false, pcall(function()
unit_test.assert_throws(function()
local table = {T._ {}}
wml.tostring(table)
end))
end, 'A lone underscore is not a valid tag name')
-- Commit 13a4822d made the WML parser accept dollar signs in tag names.
-- However, they are supposed to be rejected, and this test enforces
-- that at least the Lua API rejects them.
assert_equal(false, pcall(function()
unit_test.assert_throws(function()
local table = {T["turn$var"] {}}
wml.tostring(table)
end))
end, 'Tag names cannot contain dollar signs')
-- Pass the test. Doesn't do anything if any of the above assertions has failed.
wesnoth.wml_actions.endlevel({test_result = "pass", linger_mode = true})
unit_test.succeed()
>>
[/lua]
[/event]

View file

@ -16,7 +16,7 @@
[/set_menu_item]
[lua]
code = << wesnoth.fire_wml_menu_item("test1", 3, 3) >>
code = << unit_test.fire_wml_menu_item("test1", 3, 3) >>
[/lua]
{ASSERT {VARIABLE_CONDITIONAL mx equals 3}}
@ -53,10 +53,10 @@
[/set_menu_item]
[lua]
code = << r = wesnoth.fire_wml_menu_item("test2", 3, 3)
r = r and not wesnoth.fire_wml_menu_item("test2", 3, 3)
r = r and wesnoth.fire_wml_menu_item("test2", 4, 4)
r = r and not wesnoth.fire_wml_menu_item("test2", 4, 4)
code = << r = unit_test.fire_wml_menu_item("test2", 3, 3)
r = r and not unit_test.fire_wml_menu_item("test2", 3, 3)
r = r and unit_test.fire_wml_menu_item("test2", 4, 4)
r = r and not unit_test.fire_wml_menu_item("test2", 4, 4)
wml.variables["result"] = r >>
[/lua]
@ -97,7 +97,7 @@
[/set_menu_item]
[lua]
code = << r = wesnoth.fire_wml_menu_item("test3", 3, 3) >>
code = << r = unit_test.fire_wml_menu_item("test3", 3, 3) >>
[/lua]
{ASSERT (
[have_unit]
@ -106,7 +106,7 @@
)}
[lua]
code = << r = r and wesnoth.fire_wml_menu_item("test3", 4, 4) >>
code = << r = r and unit_test.fire_wml_menu_item("test3", 4, 4) >>
[/lua]
{ASSERT (
[have_unit]

View file

@ -2,12 +2,12 @@
[event]
name = prestart
[lua]
code = << H = wesnoth.require("helper")
A = wesnoth.require("ai/lua/extCAexample.lua")
result = H and A and true
wml.variables["result"] = result and "true" or "false" >>
code = <<
H = wesnoth.require("helper")
A = wesnoth.require("ai/lua/extCAexample.lua")
unit_test.assert(H and A and true, 'require works')
unit_test.succeed()
>>
[/lua]
{RETURN ({VARIABLE_CONDITIONAL result boolean_equals true})}
[/event]
)}

View file

@ -15,3 +15,39 @@
{RETURN ([not][true][/true][/not])}
[/event]
)}
# Same as the above two, but using the Lua unit_test module
{GENERIC_UNIT_TEST "test_lua_return" (
[event]
name = start
[lua]
code=<<unit_test.succeed()>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_return_fail" (
[event]
name = start
[lua]
code=<<unit_test.fail()>>
[/lua]
[/event]
)}
# Test results other than direct pass/fail
{GENERIC_UNIT_TEST "test_lua_return_victory" (
[event]
name = start
[lua]
code=<<unit_test.finish('victory')>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "test_lua_return_defeat" (
[event]
name = start
[lua]
code=<<unit_test.finish('defeat')>>
[/lua]
[/event]
)}

View file

@ -4125,20 +4125,23 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports
}
luaL_setfuncs(L, callbacks, 0);
if(play_controller_.get_classification().is_test()) {
static luaL_Reg const test_callbacks[] {
{ "fire_wml_menu_item", &dispatch<&game_lua_kernel::intf_fire_wml_menu_item > },
{ nullptr, nullptr }
};
luaL_setfuncs(L, test_callbacks , 0);
}
lua_setglobal(L, "wesnoth");
lua_getglobal(L, "gui");
lua_pushcfunction(L, &dispatch<&game_lua_kernel::intf_gamestate_inspector>);
lua_setfield(L, -2, "show_inspector");
lua_pop(L, 1);
if(play_controller_.get_classification().is_test()) {
// Create the unit_test module
lua_newtable(L);
static luaL_Reg const test_callbacks[] {
{ "fire_wml_menu_item", &dispatch<&game_lua_kernel::intf_fire_wml_menu_item> },
{ nullptr, nullptr }
};
luaL_setfuncs(L, test_callbacks, 0);
lua_setglobal(L, "unit_test");
}
// Create the getside metatable.
cmd_log_ << lua_team::register_metatable(L);

View file

@ -6,6 +6,32 @@
0 test_assert
1 test_assert_fail
1 test_assert_fail_two
0 test_lua_return
1 test_lua_return_fail
8 test_lua_return_victory
7 test_lua_return_defeat
0 test_lua_assert
1 test_lua_assert_fail
1 test_lua_assert_fail_in_fired_event
0 test_lua_assert_compare
1 test_lua_assert_compare_fail1
1 test_lua_assert_compare_fail2
1 test_lua_assert_compare_fail3
1 test_lua_assert_compare_fail4
1 test_lua_assert_compare_fail5
1 test_lua_assert_compare_fail6
1 test_lua_assert_compare_fail7
1 test_lua_assert_compare_fail8
1 test_lua_assert_compare_fail9
0 test_lua_assert_errors1
1 test_lua_assert_errors2
1 test_lua_assert_errors3
0 test_lua_assert_errors4
1 test_lua_assert_errors5
0 test_lua_assert_errors6
1 test_lua_assert_errors7
0 test_lua_assert_errors8
1 test_lua_assert_errors9
2 empty_test
4 break_replay_with_lua_random
0 fixed_lua_random_replay_with_sync_choice