From 7b2f01d45ba636d3755ba26cfa5a4b75f93e9844 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 9 Apr 2021 00:26:33 -0400 Subject: [PATCH 1/5] Add initial mock.patch() implementation for tests --- ci/test.lua | 2 ++ library/lua/test_util/mock.lua | 52 +++++++++++++++++++++++++++++++++ test/library/test_util/mock.lua | 45 ++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 library/lua/test_util/mock.lua create mode 100644 test/library/test_util/mock.lua diff --git a/ci/test.lua b/ci/test.lua index 5c12463f2..706560351 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -3,6 +3,7 @@ local expect = require 'test_util.expect' local json = require 'json' +local mock = require 'test_util.mock' local script = require 'gui.script' local utils = require 'utils' @@ -187,6 +188,7 @@ local function build_test_env() mode = 'none', }, expect = {}, + mock = mock, delay = delay, require = clean_require, reqscript = clean_reqscript, diff --git a/library/lua/test_util/mock.lua b/library/lua/test_util/mock.lua new file mode 100644 index 000000000..1e4609f10 --- /dev/null +++ b/library/lua/test_util/mock.lua @@ -0,0 +1,52 @@ +local mock = mkmodule('test_util.mock') + + +--[[ +Usage: + patch(table, key, value, callback) + patch({ + [{table, key}] = value, + [{table2, key2}] = value2 + }, callback) +]] +function mock.patch(...) + local args = {...} + if #args == 4 then + args = {{ + [{args[1], args[2]}] = args[3] + }, args[4]} + end + if #args ~= 2 then + error('expected 2 or 4 arguments') + end + + local callback = args[2] + local patches = {} + for k, v in pairs(args[1]) do + local p = { + table = k[1], + key = k[2], + new_value = v, + } + p.old_value = p.table[p.key] + -- no-op to ensure that the value can be restored by the finalizer below + p.table[p.key] = p.table[p.key] + table.insert(patches, p) + end + + dfhack.with_finalize( + function() + for _, p in ipairs(patches) do + p.table[p.key] = p.old_value + end + end, + function() + for _, p in ipairs(patches) do + p.table[p.key] = p.new_value + end + callback() + end + ) +end + +return mock diff --git a/test/library/test_util/mock.lua b/test/library/test_util/mock.lua new file mode 100644 index 000000000..f43fcbd65 --- /dev/null +++ b/test/library/test_util/mock.lua @@ -0,0 +1,45 @@ +local mock = require('test_util.mock') + +local test_table = { + func1 = function() + return 1 + end, + func2 = function() + return 2 + end, +} + +function test.patch_single() + expect.eq(test_table.func1(), 1) + mock.patch(test_table, 'func1', function() return 3 end, function() + expect.eq(test_table.func1(), 3) + end) + expect.eq(test_table.func1(), 1) +end + +function test.patch_single_nested() + expect.eq(test_table.func1(), 1) + mock.patch(test_table, 'func1', function() return 3 end, function() + expect.eq(test_table.func1(), 3) + mock.patch(test_table, 'func1', function() return 5 end, function() + expect.eq(test_table.func1(), 5) + end) + expect.eq(test_table.func1(), 3) + end) + expect.eq(test_table.func1(), 1) +end + +function test.patch_multiple() + expect.eq(test_table.func1(), 1) + expect.eq(test_table.func2(), 2) + mock.patch({ + [{test_table, 'func1'}] = function() return 3 end, + [{test_table, 'func2'}] = function() return 4 end, + }, function() + expect.eq(test_table.func1(), 3) + expect.eq(test_table.func2(), 4) + end) + expect.eq(test_table.func1(), 1) + expect.eq(test_table.func2(), 2) +end + From f25b8a0d143b3a27e4fe778d5877b296aa175545 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 9 Apr 2021 00:35:54 -0400 Subject: [PATCH 2/5] Fix patching value with nil --- library/lua/test_util/mock.lua | 16 +++++------ test/library/test_util/mock.lua | 51 +++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/library/lua/test_util/mock.lua b/library/lua/test_util/mock.lua index 1e4609f10..dde1b1ee2 100644 --- a/library/lua/test_util/mock.lua +++ b/library/lua/test_util/mock.lua @@ -5,15 +5,15 @@ local mock = mkmodule('test_util.mock') Usage: patch(table, key, value, callback) patch({ - [{table, key}] = value, - [{table2, key2}] = value2 + {table, key, value}, + {table2, key2, value2} }, callback) ]] function mock.patch(...) local args = {...} if #args == 4 then args = {{ - [{args[1], args[2]}] = args[3] + {args[1], args[2], args[3]} }, args[4]} end if #args ~= 2 then @@ -22,15 +22,15 @@ function mock.patch(...) local callback = args[2] local patches = {} - for k, v in pairs(args[1]) do + for _, v in ipairs(args[1]) do local p = { - table = k[1], - key = k[2], - new_value = v, + table = v[1], + key = v[2], + new_value = v[3], } p.old_value = p.table[p.key] -- no-op to ensure that the value can be restored by the finalizer below - p.table[p.key] = p.table[p.key] + p.table[p.key] = p.old_value table.insert(patches, p) end diff --git a/test/library/test_util/mock.lua b/test/library/test_util/mock.lua index f43fcbd65..40f80b165 100644 --- a/test/library/test_util/mock.lua +++ b/test/library/test_util/mock.lua @@ -33,8 +33,8 @@ function test.patch_multiple() expect.eq(test_table.func1(), 1) expect.eq(test_table.func2(), 2) mock.patch({ - [{test_table, 'func1'}] = function() return 3 end, - [{test_table, 'func2'}] = function() return 4 end, + {test_table, 'func1', function() return 3 end}, + {test_table, 'func2', function() return 4 end}, }, function() expect.eq(test_table.func1(), 3) expect.eq(test_table.func2(), 4) @@ -43,3 +43,50 @@ function test.patch_multiple() expect.eq(test_table.func2(), 2) end +function test.patch_nil_old_value() + local t = {} + mock.patch(t, 1, 2, function() + expect.eq(t[1], 2) + end) + expect.eq(t[1], nil) + expect.eq(#t, 0) +end + +function test.patch_nil_new_value() + local t = {2} + mock.patch(t, 1, nil, function() + expect.eq(t[1], nil) + expect.eq(#t, 0) + end) + expect.eq(t[1], 2) +end + +function test.patch_nil_key() + local called = false + expect.error_match('table index is nil', function() + mock.patch({}, nil, 'value', function() + called = true + end) + end) + expect.false_(called) +end + +function test.patch_nil_table() + local called = false + expect.error(function() + mock.patch(nil, 1, 2, function() + called = true + end) + end) + expect.false_(called) +end + +function test.patch_complex_key() + local key = {'key'} + local t = {[key] = 'value'} + expect.eq(t[key], 'value') + mock.patch(t, key, 2, function() + expect.eq(t[key], 2) + end) + expect.eq(t[key], 'value') +end From 54243922739f3975b487ff71fd1c153077de57f2 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 9 Apr 2021 00:41:39 -0400 Subject: [PATCH 3/5] mock.patch(): propagate return values --- library/lua/test_util/mock.lua | 4 ++-- test/library/test_util/mock.lua | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/library/lua/test_util/mock.lua b/library/lua/test_util/mock.lua index dde1b1ee2..10bdc64cf 100644 --- a/library/lua/test_util/mock.lua +++ b/library/lua/test_util/mock.lua @@ -34,7 +34,7 @@ function mock.patch(...) table.insert(patches, p) end - dfhack.with_finalize( + return dfhack.with_finalize( function() for _, p in ipairs(patches) do p.table[p.key] = p.old_value @@ -44,7 +44,7 @@ function mock.patch(...) for _, p in ipairs(patches) do p.table[p.key] = p.new_value end - callback() + return callback() end ) end diff --git a/test/library/test_util/mock.lua b/test/library/test_util/mock.lua index 40f80b165..86b621b14 100644 --- a/test/library/test_util/mock.lua +++ b/test/library/test_util/mock.lua @@ -90,3 +90,11 @@ function test.patch_complex_key() end) expect.eq(t[key], 'value') end + +function test.patch_callback_return_value() + local a, b = mock.patch({}, 'k', 'v', function() + return 3, 4 + end) + expect.eq(a, 3) + expect.eq(b, 4) +end From f44442e5e93a96c84ac4c9547601bfb98ab6c753 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 9 Apr 2021 00:50:06 -0400 Subject: [PATCH 4/5] Use mock.patch() in ci/test.lua Other tests that could benefit are currently only in the scripts repo. --- ci/test.lua | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/ci/test.lua b/ci/test.lua index 706560351..1980ddc6f 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -281,19 +281,20 @@ local function sort_tests(tests) end local function wrap_test(func) - local saved_printerr, saved_run_script = dfhack.printerr, dfhack.run_script + local saved_printerr = dfhack.printerr local printerr_called = false - dfhack.printerr = function(msg) - if msg == nil then return end - saved_printerr(msg) - printerr_called = true - end - dfhack.run_script = clean_run_script - return dfhack.with_finalize( - function() - dfhack.printerr = saved_printerr - dfhack.run_script = saved_run_script - end, + local printerr_wrapper = function(msg) + if msg == nil then return end + saved_printerr(msg) + printerr_called = true + end + + return mock.patch( + { + {dfhack, 'printerr', printerr_wrapper}, + {dfhack, 'run_script', clean_run_script}, + {dfhack, 'reqscript', clean_reqscript}, + }, function() local ok, err = pcall(func) if printerr_called then From 757736728dfa4af29db72fb03ed9fc70a415f247 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 10 Apr 2021 01:22:03 -0400 Subject: [PATCH 5/5] Add a mock.func() helper for mocking functions --- library/lua/test_util/mock.lua | 19 ++++++++++++++++- test/library/test_util/mock.lua | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/library/lua/test_util/mock.lua b/library/lua/test_util/mock.lua index 10bdc64cf..0d6eae546 100644 --- a/library/lua/test_util/mock.lua +++ b/library/lua/test_util/mock.lua @@ -1,6 +1,5 @@ local mock = mkmodule('test_util.mock') - --[[ Usage: patch(table, key, value, callback) @@ -49,4 +48,22 @@ function mock.patch(...) ) end +function mock.func(return_value) + local f = { + return_value = return_value, + call_count = 0, + call_args = {}, + } + + setmetatable(f, { + __call = function(self, ...) + self.call_count = self.call_count + 1 + table.insert(self.call_args, {...}) + return self.return_value + end, + }) + + return f +end + return mock diff --git a/test/library/test_util/mock.lua b/test/library/test_util/mock.lua index 86b621b14..584f6c188 100644 --- a/test/library/test_util/mock.lua +++ b/test/library/test_util/mock.lua @@ -98,3 +98,39 @@ function test.patch_callback_return_value() expect.eq(a, 3) expect.eq(b, 4) end + +function test.func_call_count() + local f = mock.func() + expect.eq(f.call_count, 0) + f() + expect.eq(f.call_count, 1) + f() + expect.eq(f.call_count, 2) +end + +function test.func_call_args() + local f = mock.func() + expect.eq(#f.call_args, 0) + f() + f(7) + expect.eq(#f.call_args, 2) + expect.eq(#f.call_args[1], 0) + expect.eq(#f.call_args[2], 1) + expect.eq(f.call_args[2][1], 7) +end + +function test.func_call_args_nil() + local f = mock.func() + f(nil) + f(2, nil, 4) + expect.table_eq(f.call_args[1], {nil}) + expect.table_eq(f.call_args[2], {2, nil, 4}) + expect.eq(#f.call_args[2], 3) +end + +function test.func_call_return_value() + local f = mock.func(7) + expect.eq(f(), 7) + f.return_value = 9 + expect.eq(f(), 9) +end