Skip to content

Commit 73cba6e

Browse files
committed
Show complete/incomplete calls in error messages. Closes #10.
1 parent b28744b commit 73cba6e

File tree

8 files changed

+192
-16
lines changed

8 files changed

+192
-16
lines changed

rockspecs/mach-git-0.rockspec

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ build = {
1717
['mach'] = 'mach.lua',
1818
['mach.Expectation'] = 'mach/Expectation.lua',
1919
['mach.ExpectedCall'] = 'mach/ExpectedCall.lua',
20+
['mach.CompletedCall'] = 'mach/CompletedCall.lua',
2021
['mach.unexpected_call_error'] = 'mach/unexpected_call_error.lua',
2122
['mach.unexpected_args_error'] = 'mach/unexpected_args_error.lua',
2223
['mach.out_of_order_call_error'] = 'mach/out_of_order_call_error.lua',
24+
['mach.call_status_message'] = 'mach/call_status_message.lua',
2325
}
2426
}

spec/mach_spec.lua

Lines changed: 140 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,20 @@ describe('The mach library', function()
1616
local result, actualMessage = pcall(test)
1717
_, _, actualMessage = actualMessage:find(":%w+: (.+)")
1818

19-
if(result) then
19+
if result then
2020
error('expected failure did not occur')
21-
elseif(actualMessage ~= expectedMessage) then
21+
elseif not actualMessage:find(expectedMessage, 1, true) then
22+
error('expected failure message: "' .. expectedMessage .. '" did not match actual failure message: "' .. actualMessage .. '"')
23+
end
24+
end
25+
26+
local function should_fail_with_exactly(expectedMessage, test)
27+
local result, actualMessage = pcall(test)
28+
_, _, actualMessage = actualMessage:find(":%w+: (.+)")
29+
30+
if result then
31+
error('expected failure did not occur')
32+
elseif actualMessage ~= expectedMessage then
2233
error('expected failure message: "' .. expectedMessage .. '" did not match actual failure message: "' .. actualMessage .. '"')
2334
end
2435
end
@@ -480,7 +491,7 @@ describe('The mach library', function()
480491
end)
481492
end)
482493

483-
it('should give mocked functions a default name when none is provided', function()
494+
it('should give mocked methods a default name when none is provided', function()
484495
should_fail_with('unexpected function call <anonymous>(2, 3)', function()
485496
mach.mock_method()(1, 2, 3)
486497
end)
@@ -492,4 +503,130 @@ describe('The mach library', function()
492503
f2()
493504
end)
494505
end)
506+
507+
it('should report completed and incomplete calls in unexpected call errors', function()
508+
local expected_failure =
509+
'unexpected function call f3()\n' ..
510+
'completed calls:\n' ..
511+
'\tf1()\n' ..
512+
'incomplete calls:\n' ..
513+
'\tf2()'
514+
515+
should_fail_with_exactly(expected_failure, function()
516+
f1:should_be_called():and_also(f2:should_be_called()):when(function()
517+
f1()
518+
f3()
519+
end)
520+
end)
521+
end)
522+
523+
it('should report completed and incomplete calls in unexpected argument errors', function()
524+
local expected_failure =
525+
'unexpected arguments (3) provided to function f2\n' ..
526+
'completed calls:\n' ..
527+
'\tf1()\n' ..
528+
'incomplete calls:\n' ..
529+
'\tf2()'
530+
531+
should_fail_with_exactly(expected_failure, function()
532+
f1:should_be_called():and_also(f2:should_be_called()):when(function()
533+
f1()
534+
f2(3)
535+
end)
536+
end)
537+
end)
538+
539+
it('should report completed and incomplete calls in out of order call errors', function()
540+
local expected_failure =
541+
'out of order function call f3()\n' ..
542+
'completed calls:\n' ..
543+
'\tf1()\n' ..
544+
'incomplete calls:\n' ..
545+
'\tf2()\n' ..
546+
'\tf3()'
547+
548+
should_fail_with_exactly(expected_failure, function()
549+
f1:should_be_called():
550+
and_then(f2:should_be_called()):
551+
and_then(f3:should_be_called()):
552+
when(function()
553+
f1()
554+
f3()
555+
end)
556+
end)
557+
end)
558+
559+
it('should omit the completed call list in an error when no calls were completed', function()
560+
local expected_failure =
561+
'unexpected function call f3()\n' ..
562+
'incomplete calls:\n' ..
563+
'\tf1()'
564+
565+
should_fail_with_exactly(expected_failure, function()
566+
f1:should_be_called():when(function()
567+
f3()
568+
end)
569+
end)
570+
end)
571+
572+
it('should omit the incomplete call list in an error when all calls were completed', function()
573+
local expected_failure =
574+
'unexpected function call f3()\n' ..
575+
'completed calls:\n' ..
576+
'\tf1()'
577+
578+
should_fail_with_exactly(expected_failure, function()
579+
f1:should_be_called():when(function()
580+
f1()
581+
f3()
582+
end)
583+
end)
584+
end)
585+
586+
it('should show methods in call status messages', function()
587+
local o = {
588+
m = mach.mock_method('m')
589+
}
590+
591+
local expected_failure =
592+
'unexpected function call f()\n' ..
593+
'incomplete calls:\n' ..
594+
'\tm()'
595+
596+
should_fail_with_exactly(expected_failure, function()
597+
o.m:should_be_called():when(function()
598+
f()
599+
end)
600+
end)
601+
end)
602+
603+
it('should show optional function calls as optional in call status messages', function()
604+
local expected_failure =
605+
'unexpected function call f3()\n' ..
606+
'completed calls:\n' ..
607+
'\tf1()\n' ..
608+
'incomplete calls:\n' ..
609+
'\tf2() (optional)'
610+
611+
should_fail_with_exactly(expected_failure, function()
612+
f1:should_be_called():and_also(f2:may_be_called()):when(function()
613+
f1()
614+
f3()
615+
end)
616+
end)
617+
end)
618+
619+
it('should show actual arguments in call status messages', function()
620+
local expected_failure =
621+
'unexpected function call f3()\n' ..
622+
'completed calls:\n' ..
623+
'\tf1(1, 2, 3)'
624+
625+
should_fail_with_exactly(expected_failure, function()
626+
f1:should_be_called_with_any_arguments():when(function()
627+
f1(1, 2, 3)
628+
f3()
629+
end)
630+
end)
631+
end)
495632
end)

src/mach.lua

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ local unexpected_call_error = require 'mach.unexpected_call_error'
55
local mach = {}
66

77
function unexpected_call(m, name, args)
8-
unexpected_call_error(name, args, 2)
8+
unexpected_call_error(name, args, {}, {}, 2)
99
end
1010

1111
local subscriber = unexpected_call
@@ -29,7 +29,7 @@ end
2929

3030
function mach.mock_function(name)
3131
name = name or '<anonymous>'
32-
local f = {}
32+
local f = { _name = name }
3333

3434
setmetatable(f, {
3535
__call = function(_, ...)
@@ -44,7 +44,7 @@ end
4444

4545
function mach.mock_method(name)
4646
name = name or '<anonymous>'
47-
local m = {}
47+
local m = { _name = name }
4848

4949
setmetatable(m, {
5050
__call = function(_, _, ...)

src/mach/Expectation.lua

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
local ExpectedCall = require 'mach.ExpectedCall'
2+
local CompletedCall = require 'mach.CompletedCall'
23
local unexpected_call_error = require 'mach.unexpected_call_error'
34
local unexpected_args_error = require 'mach.unexpected_args_error'
45
local out_of_order_call_error = require 'mach.out_of_order_call_error'
@@ -10,7 +11,8 @@ local function create(m)
1011
local o = {
1112
_m = m,
1213
_call_specified = false,
13-
_calls = {}
14+
_calls = {},
15+
_completed_calls = {}
1416
}
1517

1618
setmetatable(o, expectation)
@@ -57,7 +59,7 @@ function expectation:when(thunk)
5759

5860
if call:args_match(args) then
5961
if call:has_fixed_order() and incomplete_expectation_found then
60-
out_of_order_call_error(name, args, 2)
62+
out_of_order_call_error(name, args, self._completed_calls, self._calls, 2)
6163
end
6264

6365
if call:has_fixed_order() then
@@ -66,6 +68,8 @@ function expectation:when(thunk)
6668

6769
table.remove(self._calls, i)
6870

71+
table.insert(self._completed_calls, CompletedCall(name, args))
72+
6973
if call:has_error() then
7074
error(call:get_error())
7175
end
@@ -81,9 +85,9 @@ function expectation:when(thunk)
8185

8286
if not self._ignore_other_calls then
8387
if not valid_function_found then
84-
unexpected_call_error(name, args, 2)
88+
unexpected_call_error(name, args, self._completed_calls, self._calls, 2)
8589
else
86-
unexpected_args_error(name, args, 2)
90+
unexpected_args_error(name, args, self._completed_calls, self._calls, 2)
8791
end
8892
end
8993
end

src/mach/ExpectedCall.lua

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
local expected_call = {}
22
expected_call.__index = expected_call
33

4+
expected_call.__tostring = function(self)
5+
local arg_strings = {}
6+
for _, arg in ipairs(self._args) do
7+
table.insert(arg_strings, tostring(arg))
8+
end
9+
10+
local s = self._f._name .. '(' .. table.concat(arg_strings, ', ') .. ')'
11+
12+
if not self._required then
13+
s = s .. ' (optional)'
14+
end
15+
16+
return s
17+
end
18+
419
local function create(f, config)
520
local o = {
621
_f = f,

src/mach/out_of_order_call_error.lua

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
return function(name, args, level)
1+
local call_status_message = require 'mach.call_status_message'
2+
3+
return function(name, args, completed_calls, incomplete_calls, level)
24
local arg_strings = {}
35
for _, arg in ipairs(args) do
46
table.insert(arg_strings, tostring(arg))
57
end
68

7-
error('out of order function call ' .. name .. '(' .. table.concat(arg_strings, ', ') .. ')', level + 1)
9+
local error_message =
10+
'out of order function call ' .. name .. '(' .. table.concat(arg_strings, ', ') .. ')' ..
11+
call_status_message(completed_calls, incomplete_calls)
12+
13+
error(error_message, level + 1)
814
end

src/mach/unexpected_args_error.lua

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
return function(name, args, level)
1+
local call_status_message = require 'mach.call_status_message'
2+
3+
return function(name, args, completed_calls, incomplete_calls, level)
24
local arg_strings = {}
35
for _, arg in ipairs(args) do
46
table.insert(arg_strings, tostring(arg))
57
end
68

7-
error('unexpected arguments (' .. table.concat(arg_strings) .. ') provided to function ' .. name, level + 1)
9+
local error_message =
10+
'unexpected arguments (' .. table.concat(arg_strings) .. ') provided to function ' .. name ..
11+
call_status_message(completed_calls, incomplete_calls)
12+
13+
error(error_message, level + 1)
814
end

src/mach/unexpected_call_error.lua

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
return function(name, args, level)
1+
local call_status_message = require 'mach.call_status_message'
2+
3+
return function(name, args, completed_calls, incomplete_calls, level)
24
local arg_strings = {}
35
for _, arg in ipairs(args) do
46
table.insert(arg_strings, tostring(arg))
57
end
68

7-
error('unexpected function call ' .. name .. '(' .. table.concat(arg_strings, ', ') .. ')', level + 1)
9+
local message =
10+
'unexpected function call ' .. name .. '(' .. table.concat(arg_strings, ', ') .. ')' ..
11+
call_status_message(completed_calls, incomplete_calls)
12+
13+
error(message, level + 1)
814
end

0 commit comments

Comments
 (0)