Skip to content

Commit fbd539e

Browse files
committed
feat: improve assert_have_been_called_with arg matching
1 parent 966de2f commit fbd539e

5 files changed

Lines changed: 92 additions & 36 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
- Improve `assert_have_been_called_with` with strict argument matching
6+
37
## [0.23.0](https://github.com/TypedDevs/bashunit/compare/0.22.3...0.23.0) - 2025-08-03
48

59
- Update docs mocks usage

docs/test-doubles.md

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ function test_example() {
8787

8888
ps foo bar
8989

90-
assert_have_been_called_with "foo bar" ps
90+
assert_have_been_called_with ps "foo bar"
9191
assert_have_been_called ps
9292
}
9393
```
@@ -117,11 +117,12 @@ function test_failure() {
117117
:::
118118

119119
## assert_have_been_called_with
120-
> `assert_have_been_called_with "expected" "spy" [call_index]`
120+
> `assert_have_been_called_with spy expected [call_index] [--strict]`
121121
122122
Reports an error if `spy` is not called with `expected`. When `call_index` is
123123
provided, the assertion checks the arguments of that specific call (starting at
124-
1). Without `call_index` it checks the last invocation.
124+
1). Without `call_index` it checks the last invocation. The optional `--strict`
125+
flag forces an exact match on argument boundaries.
125126

126127
::: code-group
127128
```bash [Example]
@@ -131,20 +132,31 @@ function test_success() {
131132
ps foo
132133
ps bar
133134

134-
assert_have_been_called_with "foo" ps 1
135-
assert_have_been_called_with "bar" ps 2
135+
assert_have_been_called_with ps "foo" 1
136+
assert_have_been_called_with ps "bar" 2
136137
}
137138

138139
function test_failure() {
139140
spy ps
140141

141142
ps bar
142143

143-
assert_have_been_called_with "foo" ps 1
144+
assert_have_been_called_with ps "foo" 1
144145
}
145146
```
146147
:::
147148

149+
### Argument boundaries
150+
151+
By default, `assert_have_been_called_with` joins arguments with spaces before comparison. This means a call like `ps "foo bar"` is indistinguishable from `ps foo bar`. Use the `--strict` flag to force an exact match on argument boundaries:
152+
153+
```bash
154+
spy ps
155+
ps "foo bar"
156+
assert_have_been_called_with ps "foo bar" --strict # succeeds
157+
assert_have_been_called_with ps foo bar --strict # fails
158+
```
159+
148160
## assert_have_been_called_times
149161
> assert_have_been_called_times "expected" "spy"
150162

src/test_doubles.sh

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,14 @@ function spy() {
5252
export "${variable}_params_file"="$params_file"
5353

5454
eval "function $command() {
55-
echo \"\$*\" >> '$params_file'
55+
local raw=\"\$*\"
56+
local serialized=\"\"
57+
local arg
58+
for arg in \"\$@\"; do
59+
serialized+=\"\$(printf '%q' \"\$arg\")$'\\x1f'\"
60+
done
61+
serialized=\${serialized%$'\\x1f'}
62+
printf '%s|%s\\n' \"\$raw\" \"\$serialized\" >> '$params_file'
5663
local _c=\$(cat '$times_file')
5764
_c=\$((_c+1))
5865
echo \"\$_c\" > '$times_file'
@@ -84,37 +91,60 @@ function assert_have_been_called() {
8491
}
8592

8693
function assert_have_been_called_with() {
87-
local expected=$1
88-
local command=$2
89-
local third_arg="${3:-}"
90-
local fourth_arg="${4:-}"
94+
local command=$1
95+
shift
96+
97+
local strict=false
98+
if [[ ${!#} == "--strict" ]]; then
99+
strict=true
100+
set -- "${@:1:$#-1}"
101+
fi
91102

92103
local index=""
93-
local label=""
94-
if [[ -n $third_arg && $third_arg =~ ^[0-9]+$ ]]; then
95-
index=$third_arg
96-
label="${fourth_arg:-$(helper::normalize_test_function_name "${FUNCNAME[1]}")}"
97-
else
98-
label="${third_arg:-$(helper::normalize_test_function_name "${FUNCNAME[1]}")}"
99-
index="$fourth_arg"
104+
if [[ ${!#} =~ ^[0-9]+$ ]]; then
105+
index=${!#}
106+
set -- "${@:1:$#-1}"
100107
fi
101108

109+
local expected=("$@")
110+
102111
local variable
103112
variable="$(helper::normalize_variable_name "$command")"
104113
local file_var="${variable}_params_file"
105-
local params=""
114+
local line=""
106115
if [[ -f "${!file_var-}" ]]; then
107116
if [[ -n $index ]]; then
108-
params=$(sed -n "${index}p" "${!file_var}")
117+
line=$(sed -n "${index}p" "${!file_var}")
109118
else
110-
params=$(tail -n 1 "${!file_var}")
119+
line=$(tail -n 1 "${!file_var}")
111120
fi
112121
fi
113122

114-
if [[ "$expected" != "$params" ]]; then
115-
state::add_assertions_failed
116-
console_results::print_failed_test "${label}" "${expected}" "but got " "$params"
117-
return
123+
local raw recorded
124+
IFS='|' read -r raw recorded <<<"$line"
125+
126+
if [[ $strict == true ]]; then
127+
local serialized=""
128+
local arg
129+
for arg in "${expected[@]}"; do
130+
serialized+="$(printf '%q' "$arg")$'\x1f'"
131+
done
132+
serialized=${serialized%$'\x1f'}
133+
if [[ "$serialized" != "$recorded" ]]; then
134+
state::add_assertions_failed
135+
local expected_joined="${expected[*]}"
136+
console_results::print_failed_test "$(helper::normalize_test_function_name \
137+
"${FUNCNAME[1]}")" "${expected_joined}" "but got " "$raw"
138+
return
139+
fi
140+
else
141+
local expected_raw="${expected[*]}"
142+
if [[ "$expected_raw" != "$raw" ]]; then
143+
state::add_assertions_failed
144+
console_results::print_failed_test "$(helper::normalize_test_function_name \
145+
"${FUNCNAME[1]}")" "${expected_raw}" "but got " "$raw"
146+
return
147+
fi
118148
fi
119149

120150
state::add_assertions_passed

tests/unit/dependencies_test.sh

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,48 @@ function test_has_perl_search_path_for_perl() {
44
spy command
55
dependencies::has_perl
66

7-
assert_have_been_called_with "-v perl" command
7+
assert_have_been_called_with command "-v perl"
88
}
99

1010
function test_has_adjtimex() {
1111
spy command
1212
dependencies::has_adjtimex
1313

14-
assert_have_been_called_with "-v adjtimex" command
14+
assert_have_been_called_with command "-v adjtimex"
1515
}
1616

1717
function test_has_bc() {
1818
spy command
1919

2020
dependencies::has_bc
2121

22-
assert_have_been_called_with "-v bc" command
22+
assert_have_been_called_with command "-v bc"
2323
}
2424

2525
function test_has_awk() {
2626
spy command
2727
dependencies::has_awk
2828

29-
assert_have_been_called_with "-v awk" command
29+
assert_have_been_called_with command "-v awk"
3030
}
3131

3232
function test_has_git() {
3333
spy command
3434
dependencies::has_git
3535

36-
assert_have_been_called_with "-v git" command
36+
assert_have_been_called_with command "-v git"
3737
}
3838

3939
function test_has_python() {
4040
spy command
4141
dependencies::has_python
4242

43-
assert_have_been_called_with "-v python" command
43+
assert_have_been_called_with command "-v python"
4444
}
4545

4646
function test_has_node() {
4747
spy command
4848
dependencies::has_node
4949

50-
assert_have_been_called_with "-v node" command
50+
assert_have_been_called_with command "-v node"
5151
}

tests/unit/test_doubles_test.sh

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ function test_successful_spy() {
3333
spy ps
3434
ps a_random_parameter_1 a_random_parameter_2
3535

36-
assert_have_been_called_with "a_random_parameter_1 a_random_parameter_2" ps
36+
assert_have_been_called_with ps "a_random_parameter_1 a_random_parameter_2"
3737
assert_have_been_called ps
3838
}
3939

@@ -122,7 +122,7 @@ function test_spy_called_in_subshell() {
122122
assert_same "done" "$result"
123123
assert_have_been_called spy_called_in_subshell
124124
assert_have_been_called_times 2 spy_called_in_subshell
125-
assert_have_been_called_with "2025-05-23" spy_called_in_subshell
125+
assert_have_been_called_with spy_called_in_subshell "2025-05-23"
126126
}
127127

128128
function test_mock_called_in_subshell() {
@@ -144,8 +144,18 @@ function test_spy_called_with_different_arguments() {
144144
ps first_a first_b
145145
ps second
146146

147-
assert_have_been_called_with "first_a first_b" ps 1
148-
assert_have_been_called_with "second" ps 2
147+
assert_have_been_called_with ps "first_a first_b" 1
148+
assert_have_been_called_with ps "second" 2
149+
}
150+
151+
function test_strict_argument_matching() {
152+
spy ps
153+
154+
ps "arg1 arg2"
155+
ps arg1 arg2
156+
157+
assert_have_been_called_with ps "arg1 arg2" 1 --strict
158+
assert_have_been_called_with ps arg1 arg2 2 --strict
149159
}
150160

151161
function test_spy_successful_not_called() {

0 commit comments

Comments
 (0)