Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- Performance: `--coverage` is roughly 5x faster and `--coverage-report-html` roughly 19x β€” a run over this repo went from 16.2s to 2.9s, and a 128-file HTML report from 58.7s to 3.1s. The report phase emits each format in one awk invocation per run instead of Bash loops and forks per file and per row, and the capture path writes records straight to disk, normalizes a path with one fork instead of four, and reads each cache once (#1092, #1096, #1098, #1099, #1102, #1104, #1110, #1117)

### Fixed
- `assert_exec "cmd" --exit 1` works under `--strict`: the command ran with `eval` and its status was read on the next line, so `set -e` aborted the test before the assertion β€” the one assertion whose job is checking an exit code could not check a failing one. Successful commands were unaffected, which is why it went unnoticed (#1207)
- `bashunit bench` reports `No benchmarks found` and exits non-zero instead of printing a header and exiting 0 when the path does not exist, or holds no `bench_` function β€” a typo left a CI benchmark job green having measured nothing (#1199)
- `install.sh` names the real problem when the destination is unusable, instead of reporting `failed to download … from <url>` for a folder it cannot write, or leaking a raw `rm: Not a directory` when the path is a regular file. The destination is validated before any network call (#1197)
- A bootstrap file that fails to load reports it and exits non-zero, through every path that loads one (`BASHUNIT_BOOTSTRAP`, `--env`, `--boot`, and the `bench` equivalents), instead of leaving the run with no tests, no summary and exit 0. An absent bootstrap is still ignored (#1179, #1181)
Expand Down
14 changes: 10 additions & 4 deletions src/assert/core.sh
Original file line number Diff line number Diff line change
Expand Up @@ -666,12 +666,18 @@ function assert_exec() {
local stdin_file
stdin_file=$("$MKTEMP")
printf '%s' "$stdin_input" >"$stdin_file"
eval "$cmd" <"$stdin_file" >"$stdout_file" 2>"$stderr_file"
local exit_code=$?
# `|| exit_code=$?`, and the local declared first: under --strict the runner
# enables set -e, so a command that exits non-zero would abort the test
# function on the eval and never reach the next line -- the one assertion
# whose job is checking an exit code could not check a failing one (#1207).
# Declaring and assigning together would also mask the status behind
# `local`'s own.
local exit_code=0
eval "$cmd" <"$stdin_file" >"$stdout_file" 2>"$stderr_file" || exit_code=$?
rm -f "$stdin_file"
else
eval "$cmd" >"$stdout_file" 2>"$stderr_file"
local exit_code=$?
local exit_code=0
eval "$cmd" >"$stdout_file" 2>"$stderr_file" || exit_code=$?
fi

local stdout
Expand Down
33 changes: 33 additions & 0 deletions tests/acceptance/bashunit_assert_basic_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,36 @@ function test_multi_assert_help_shows_multi_syntax() {
output=$(./bashunit assert --help 2>&1)
assert_contains "Multiple assertions on command output" "$output"
}

# assert_exec runs the command with `eval "$cmd" >out 2>err` and reads $? on the
# next line. Under --strict the runner enables set -e, so a command that exits
# non-zero aborts the test function there and the assertion never runs: the one
# assertion whose job is checking an exit code could not check a failing one
# (#1207). Success cases were unaffected, which is why it went unnoticed.
function test_assert_exec_can_assert_a_nonzero_exit_under_strict() {
local dir
dir="$(bashunit::temp_dir)"
printf '#!/usr/bin/env bash\nexit 1\n' >"$dir/fails.sh"
chmod +x "$dir/fails.sh"
printf 'function test_x() { assert_exec "%s/fails.sh" --exit 1; }\n' "$dir" >"$dir/e_test.sh"

local output
output=$(./bashunit --no-parallel --strict "$dir/e_test.sh" 2>&1) || true
output=$(printf '%s' "$output" | strip_ansi)

assert_contains "1 passed" "$output"
assert_not_contains "βœ—" "$output"
}

function test_assert_exec_still_asserts_a_zero_exit_under_strict() {
local dir
dir="$(bashunit::temp_dir)"
printf '#!/usr/bin/env bash\nexit 0\n' >"$dir/ok.sh"
chmod +x "$dir/ok.sh"
printf 'function test_x() { assert_exec "%s/ok.sh" --exit 0; }\n' "$dir" >"$dir/o_test.sh"

local output
output=$(./bashunit --no-parallel --strict "$dir/o_test.sh" 2>&1) || true

assert_contains "1 passed" "$(printf '%s' "$output" | strip_ansi)"
}
Loading