Skip to content

Commit 4ddc898

Browse files
authored
Merge pull request #544 from TypedDevs/feat/536-subsequent-assert-not-evaluated-after-fail
Subsequent assert not evaluated after fail
2 parents 4ba3bb0 + dbed89d commit 4ddc898

14 files changed

+213
-52
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
### Added
66
- Add `--strict` flag to enable strict shell mode (`set -euo pipefail`) for tests (fixes #540)
77
- Add `BASHUNIT_STRICT_MODE` configuration option (default: `false`)
8+
- Add `-R, --run-all` flag to run all assertions even when one fails (fixes #536)
9+
- Add `BASHUNIT_STOP_ON_ASSERTION_FAILURE` configuration option (default: `true`)
810

911
### Changed
1012
- Build script now outputs to `bin/` by default

docs/command-line.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ bashunit test tests/ --parallel --simple
5252
| `-p, --parallel` | Run tests in parallel (default) |
5353
| `--no-parallel` | Run tests sequentially |
5454
| `-r, --report-html <file>` | Write HTML report |
55+
| `-R, --run-all` | Run all assertions (don't stop on first failure) |
5556
| `-s, --simple` | Simple output (dots) |
5657
| `--detailed` | Detailed output (default) |
5758
| `-S, --stop-on-failure` | Stop on first failure |

docs/configuration.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,29 @@ Force to stop the runner right after encountering one failing test. `false` by d
8686
Similar as using `-S|--stop-on-failure` option on the [command line](/command-line#stop-on-failure).
8787

8888
::: tip Assertion behavior
89-
When an assertion fails within a test, subsequent assertions in the same test are automatically skipped. This matches popular testing libraries default behavior and prevents misleading failures caused by earlier assertion failures.
89+
By default, when an assertion fails within a test, subsequent assertions in the same test are skipped. Use `-R, --run-all` or set `BASHUNIT_STOP_ON_ASSERTION_FAILURE=false` to run all assertions even when one fails.
9090

91-
The `--stop-on-failure` flag is separate – it stops the entire test runner after a failing **test**, while assertion-level stopping happens automatically within each test.
91+
The `--stop-on-failure` flag is separate – it stops the entire test runner after a failing **test**, while assertion-level stopping happens within each test.
92+
:::
93+
94+
## Stop on assertion failure
95+
96+
> `BASHUNIT_STOP_ON_ASSERTION_FAILURE=true|false`
97+
98+
Controls whether to stop at the first failed assertion within a test. `true` by default.
99+
100+
When enabled (default), subsequent assertions in the same test are skipped after a failure.
101+
When disabled, all assertions in the test run, showing all failures at once.
102+
103+
Similar as using `-R|--run-all` option on the [command line](/command-line).
104+
105+
::: code-group
106+
```bash [Run all assertions]
107+
BASHUNIT_STOP_ON_ASSERTION_FAILURE=false
108+
```
109+
```bash [Stop on first failure (default)]
110+
BASHUNIT_STOP_ON_ASSERTION_FAILURE=true
111+
```
92112
:::
93113

94114
## Show header

src/assert.sh

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@ function bashunit::assert::mark_failed() {
66
bashunit::state::mark_assertion_failed_in_test
77
}
88

9+
# Guard clause to skip assertion if one already failed in test (when stop-on-assertion is enabled)
10+
function bashunit::assert::should_skip() {
11+
bashunit::env::is_stop_on_assertion_failure_enabled && (( _BASHUNIT_ASSERTION_FAILED_IN_TEST ))
12+
}
13+
914
function bashunit::fail() {
10-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
15+
bashunit::assert::should_skip && return 0
1116

1217
local message="${1:-${FUNCNAME[1]}}"
1318

@@ -20,7 +25,7 @@ function bashunit::fail() {
2025
}
2126

2227
function assert_true() {
23-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
28+
bashunit::assert::should_skip && return 0
2429

2530
local actual="$1"
2631

@@ -42,7 +47,7 @@ function assert_true() {
4247
}
4348

4449
function assert_false() {
45-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
50+
bashunit::assert::should_skip && return 0
4651

4752
local actual="$1"
4853

@@ -89,7 +94,7 @@ function bashunit::handle_bool_assertion_failure() {
8994
}
9095

9196
function assert_same() {
92-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
97+
bashunit::assert::should_skip && return 0
9398

9499
local expected="$1"
95100
local actual="$2"
@@ -108,7 +113,7 @@ function assert_same() {
108113
}
109114

110115
function assert_equals() {
111-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
116+
bashunit::assert::should_skip && return 0
112117

113118
local expected="$1"
114119
local actual="$2"
@@ -132,7 +137,7 @@ function assert_equals() {
132137
}
133138

134139
function assert_not_equals() {
135-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
140+
bashunit::assert::should_skip && return 0
136141

137142
local expected="$1"
138143
local actual="$2"
@@ -156,7 +161,7 @@ function assert_not_equals() {
156161
}
157162

158163
function assert_empty() {
159-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
164+
bashunit::assert::should_skip && return 0
160165

161166
local expected="$1"
162167

@@ -174,7 +179,7 @@ function assert_empty() {
174179
}
175180

176181
function assert_not_empty() {
177-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
182+
bashunit::assert::should_skip && return 0
178183

179184
local expected="$1"
180185

@@ -192,7 +197,7 @@ function assert_not_empty() {
192197
}
193198

194199
function assert_not_same() {
195-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
200+
bashunit::assert::should_skip && return 0
196201

197202
local expected="$1"
198203
local actual="$2"
@@ -211,7 +216,7 @@ function assert_not_same() {
211216
}
212217

213218
function assert_contains() {
214-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
219+
bashunit::assert::should_skip && return 0
215220

216221
local expected="$1"
217222
local actual_arr=("${@:2}")
@@ -232,7 +237,7 @@ function assert_contains() {
232237
}
233238

234239
function assert_contains_ignore_case() {
235-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
240+
bashunit::assert::should_skip && return 0
236241

237242
local expected="$1"
238243
local actual="$2"
@@ -255,7 +260,7 @@ function assert_contains_ignore_case() {
255260
}
256261

257262
function assert_not_contains() {
258-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
263+
bashunit::assert::should_skip && return 0
259264

260265
local expected="$1"
261266
local actual_arr=("${@:2}")
@@ -276,7 +281,7 @@ function assert_not_contains() {
276281
}
277282

278283
function assert_matches() {
279-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
284+
bashunit::assert::should_skip && return 0
280285

281286
local expected="$1"
282287
local actual_arr=("${@:2}")
@@ -297,7 +302,7 @@ function assert_matches() {
297302
}
298303

299304
function assert_not_matches() {
300-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
305+
bashunit::assert::should_skip && return 0
301306

302307
local expected="$1"
303308
local actual_arr=("${@:2}")
@@ -318,7 +323,7 @@ function assert_not_matches() {
318323
}
319324

320325
function assert_exec() {
321-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
326+
bashunit::assert::should_skip && return 0
322327

323328
local cmd="$1"
324329
shift
@@ -404,7 +409,7 @@ function assert_exec() {
404409

405410
function assert_exit_code() {
406411
local actual_exit_code=${3-"$?"} # Capture $? before guard check
407-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
412+
bashunit::assert::should_skip && return 0
408413

409414
local expected_exit_code="$1"
410415

@@ -423,7 +428,7 @@ function assert_exit_code() {
423428

424429
function assert_successful_code() {
425430
local actual_exit_code=${3-"$?"} # Capture $? before guard check
426-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
431+
bashunit::assert::should_skip && return 0
427432

428433
local expected_exit_code=0
429434

@@ -443,7 +448,7 @@ function assert_successful_code() {
443448

444449
function assert_unsuccessful_code() {
445450
local actual_exit_code=${3-"$?"} # Capture $? before guard check
446-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
451+
bashunit::assert::should_skip && return 0
447452

448453
if [[ "$actual_exit_code" -eq 0 ]]; then
449454
local test_fn
@@ -460,7 +465,7 @@ function assert_unsuccessful_code() {
460465

461466
function assert_general_error() {
462467
local actual_exit_code=${3-"$?"} # Capture $? before guard check
463-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
468+
bashunit::assert::should_skip && return 0
464469

465470
local expected_exit_code=1
466471

@@ -480,7 +485,7 @@ function assert_general_error() {
480485

481486
function assert_command_not_found() {
482487
local actual_exit_code=${3-"$?"} # Capture $? before guard check
483-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
488+
bashunit::assert::should_skip && return 0
484489

485490
local expected_exit_code=127
486491

@@ -499,7 +504,7 @@ function assert_command_not_found() {
499504
}
500505

501506
function assert_string_starts_with() {
502-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
507+
bashunit::assert::should_skip && return 0
503508

504509
local expected="$1"
505510
local actual_arr=("${@:2}")
@@ -520,7 +525,7 @@ function assert_string_starts_with() {
520525
}
521526

522527
function assert_string_not_starts_with() {
523-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
528+
bashunit::assert::should_skip && return 0
524529

525530
local expected="$1"
526531
local actual="$2"
@@ -539,7 +544,7 @@ function assert_string_not_starts_with() {
539544
}
540545

541546
function assert_string_ends_with() {
542-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
547+
bashunit::assert::should_skip && return 0
543548

544549
local expected="$1"
545550
local actual_arr=("${@:2}")
@@ -560,7 +565,7 @@ function assert_string_ends_with() {
560565
}
561566

562567
function assert_string_not_ends_with() {
563-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
568+
bashunit::assert::should_skip && return 0
564569

565570
local expected="$1"
566571
local actual_arr=("${@:2}")
@@ -581,7 +586,7 @@ function assert_string_not_ends_with() {
581586
}
582587

583588
function assert_less_than() {
584-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
589+
bashunit::assert::should_skip && return 0
585590

586591
local expected="$1"
587592
local actual="$2"
@@ -600,7 +605,7 @@ function assert_less_than() {
600605
}
601606

602607
function assert_less_or_equal_than() {
603-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
608+
bashunit::assert::should_skip && return 0
604609

605610
local expected="$1"
606611
local actual="$2"
@@ -619,7 +624,7 @@ function assert_less_or_equal_than() {
619624
}
620625

621626
function assert_greater_than() {
622-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
627+
bashunit::assert::should_skip && return 0
623628

624629
local expected="$1"
625630
local actual="$2"
@@ -638,7 +643,7 @@ function assert_greater_than() {
638643
}
639644

640645
function assert_greater_or_equal_than() {
641-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
646+
bashunit::assert::should_skip && return 0
642647

643648
local expected="$1"
644649
local actual="$2"
@@ -657,7 +662,7 @@ function assert_greater_or_equal_than() {
657662
}
658663

659664
function assert_line_count() {
660-
(( _BASHUNIT_ASSERTION_FAILED_IN_TEST )) && return 0
665+
bashunit::assert::should_skip && return 0
661666

662667
local expected="$1"
663668
local input_arr=("${@:2}")

src/assert_arrays.sh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#!/usr/bin/env bash
22

33
function assert_array_contains() {
4+
bashunit::assert::should_skip && return 0
5+
46
local expected="$1"
57
local test_fn
68
test_fn="$(bashunit::helper::find_test_function_name)"
@@ -11,7 +13,7 @@ function assert_array_contains() {
1113
local actual=("${@}")
1214

1315
if ! [[ "${actual[*]}" == *"$expected"* ]]; then
14-
bashunit::state::add_assertions_failed
16+
bashunit::assert::mark_failed
1517
bashunit::console_results::print_failed_test "${label}" "${actual[*]}" "to contain" "${expected}"
1618
return
1719
fi
@@ -20,6 +22,8 @@ function assert_array_contains() {
2022
}
2123

2224
function assert_array_not_contains() {
25+
bashunit::assert::should_skip && return 0
26+
2327
local expected="$1"
2428
local test_fn
2529
test_fn="$(bashunit::helper::find_test_function_name)"
@@ -29,7 +33,7 @@ function assert_array_not_contains() {
2933
local actual=("$@")
3034

3135
if [[ "${actual[*]}" == *"$expected"* ]]; then
32-
bashunit::state::add_assertions_failed
36+
bashunit::assert::mark_failed
3337
bashunit::console_results::print_failed_test "${label}" "${actual[*]}" "to not contain" "${expected}"
3438
return
3539
fi

0 commit comments

Comments
 (0)