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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
- The `--parallel` unsupported-OS warning no longer claims Alpine is excluded

### Fixed
- A configured external git differ (`diff.external` / `GIT_EXTERNAL_DIFF`, e.g. difftastic) no longer blanks the multiline and snapshot failure diffs, which now render with `--no-ext-diff` (#912)
- Time reads and the JUnit report no longer set the locale with a temporary-environment prefix (`LC_ALL=C cmd`), which segfaults inside a command substitution on Bash 5.3.9 macOS (#912)
- Call assertions (`assert_not_called`, `assert_have_been_called*`) fail with `was never registered as a spy` instead of reporting zero calls when the name was never spied — a typo used to pass silently (#895)
- The per-argument form a spy records was written with a literal `$'\x1f'` separator instead of the byte, so it could not be compared against (#894)
- `--parallel` no longer discards worker stderr written outside a test body; it renders as a `Stderr from <file>` block (#864)
Expand Down
5 changes: 4 additions & 1 deletion src/clock.sh
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,10 @@ function bashunit::clock::now() {

function bashunit::clock::shell_time() {
# Get time directly from the shell variable EPOCHREALTIME (Bash 5+)
[ -n "${EPOCHREALTIME+x}" ] && [ -n "$EPOCHREALTIME" ] && LC_ALL=C echo "$EPOCHREALTIME"
# No `LC_ALL=C` prefix: the value is expanded before the temporary environment
# applies, so it cannot normalize the decimal separator (callers accept both),
# and that form segfaults inside `$()` on Bash 5.3 macOS (#912).
[ -n "${EPOCHREALTIME+x}" ] && [ -n "$EPOCHREALTIME" ] && echo "$EPOCHREALTIME"
}

function bashunit::clock::total_runtime_in_milliseconds() {
Expand Down
5 changes: 3 additions & 2 deletions src/console_results.sh
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,9 @@ function bashunit::console_results::render_diff() {

# `git diff` exits non-zero when the files differ; the `|| true` keeps that
# from tripping `set -e`/`pipefail` under --strict. `tail -n +6` drops git's
# header lines; `sed` indents the body.
git diff --no-index --word-diff "$color_flag" \
# header lines; `sed` indents the body. `--no-ext-diff` ignores a user's
# `diff.external`/`GIT_EXTERNAL_DIFF`, which would replace this word-diff.
git diff --no-index --no-ext-diff --word-diff "$color_flag" \
"$expected_file" "$actual_file" 2>/dev/null |
tail -n +6 | sed "s/^/ /" || true
}
Expand Down
6 changes: 4 additions & 2 deletions src/reports.sh
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ function bashunit::reports::generate_junit_xml() {
local tests_failed=$(bashunit::state::get_tests_failed)
local time_ms=$(bashunit::clock::total_runtime_in_milliseconds)
local time
time=$(LC_ALL=C awk -v ms="$time_ms" 'BEGIN {printf "%.3f", ms/1000}')
# `env` rather than a bare `LC_ALL=C` prefix: C keeps awk's radix a dot for the
# XML, and that prefix form segfaults inside `$()` on Bash 5.3 macOS (#912).
time=$(env LC_ALL=C awk -v ms="$time_ms" 'BEGIN {printf "%.3f", ms/1000}')

{
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
Expand All @@ -120,7 +122,7 @@ function bashunit::reports::generate_junit_xml() {
local test_time_ms="${_BASHUNIT_REPORTS_TEST_DURATIONS[$i]:-}"
local failure_message="${_BASHUNIT_REPORTS_TEST_FAILURES[$i]:-}"
local test_time
test_time=$(LC_ALL=C awk -v ms="$test_time_ms" 'BEGIN {printf "%.3f", ms/1000}')
test_time=$(env LC_ALL=C awk -v ms="$test_time_ms" 'BEGIN {printf "%.3f", ms/1000}')

echo " <testcase file=\"$file\""
echo " name=\"$name\""
Expand Down
10 changes: 5 additions & 5 deletions tests/acceptance/bashunit_init_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,23 @@ function tear_down() {

function test_bashunit_init_creates_structure() {
pushd "$TMP_DIR" >/dev/null
"$BASHUNIT_PATH" init >/tmp/init.log
"$BASHUNIT_PATH" init >"$TMP_DIR/init.log"
assert_file_exists "tests/example_test.sh"
assert_file_exists "tests/bootstrap.sh"
popd >/dev/null
}

function test_bashunit_init_custom_directory() {
pushd "$TMP_DIR" >/dev/null
"$BASHUNIT_PATH" init custom >/tmp/init.log
"$BASHUNIT_PATH" init custom >"$TMP_DIR/init.log"
assert_file_exists "custom/example_test.sh"
assert_file_exists "custom/bootstrap.sh"
popd >/dev/null
}

function test_bashunit_init_creates_github_workflow() {
pushd "$TMP_DIR" >/dev/null
"$BASHUNIT_PATH" init >/tmp/init.log
"$BASHUNIT_PATH" init >"$TMP_DIR/init.log"
assert_file_exists ".github/workflows/tests.yml"
assert_file_contains ".github/workflows/tests.yml" "TypedDevs/bashunit@"
popd >/dev/null
Expand All @@ -41,7 +41,7 @@ function test_bashunit_init_does_not_overwrite_existing_workflow() {
pushd "$TMP_DIR" >/dev/null
mkdir -p ".github/workflows"
echo "custom-workflow" >".github/workflows/tests.yml"
"$BASHUNIT_PATH" init >/tmp/init.log
"$BASHUNIT_PATH" init >"$TMP_DIR/init.log"
assert_file_contains ".github/workflows/tests.yml" "custom-workflow"
popd >/dev/null
}
Expand All @@ -51,7 +51,7 @@ function test_bashunit_init_updates_env() {

pushd "$TMP_DIR" >/dev/null
echo "BASHUNIT_BOOTSTRAP=old/bootstrap.sh" >.env
"$BASHUNIT_PATH" init custom >/tmp/init.log
"$BASHUNIT_PATH" init custom >"$TMP_DIR/init.log"
assert_file_exists "custom/example_test.sh"
assert_file_exists "custom/bootstrap.sh"
assert_file_contains .env "#BASHUNIT_BOOTSTRAP=old/bootstrap.sh"
Expand Down
4 changes: 2 additions & 2 deletions tests/acceptance/bashunit_syntax_error_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function test_bashunit_when_test_file_has_syntax_error() {

local actual_raw
set +e
actual_raw="$(LC_ALL=C LANG=C ./bashunit \
actual_raw="$(./bashunit \
--no-parallel --detailed --env "$TEST_ENV_FILE" "$test_file" 2>&1)"
set -e

Expand All @@ -19,6 +19,6 @@ function test_bashunit_when_test_file_has_syntax_error() {

assert_contains "failed" "$actual"
assert_contains "Error" "$actual"
assert_general_error "$(LC_ALL=C LANG=C ./bashunit \
assert_general_error "$(./bashunit \
--no-parallel --env "$TEST_ENV_FILE" "$test_file" 2>&1)"
}
11 changes: 11 additions & 0 deletions tests/unit/bash_compatibility_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,14 @@ function test_src_has_no_coproc() {
function test_src_has_no_parameter_transformations() {
assert_empty "$(bashunit::compat::offenders '\$\{[A-Za-z_][A-Za-z0-9_]*@[QEPAKa]\}')"
}

# A temporary-environment locale prefix (`LC_ALL=C cmd`) makes bash change its
# own locale for that command. Bash 5.3.9 on macOS segfaults on that form inside
# a command substitution -- `x=$(LC_ALL=C echo hi)` exits 139 (#912) -- and no CI
# job runs that build. Use `env LC_ALL=C cmd` instead, which passes the locale
# straight to the child and never touches bash's own.
function test_src_has_no_temporary_locale_assignment_prefix() {
local pattern='(^|[;&|(])[[:space:]]*((LC_[A-Z_]+|LANG)=[^[:space:]]*[[:space:]]+)+[^[:space:]=]'

assert_empty "$(bashunit::compat::offenders "$pattern")"
}
23 changes: 23 additions & 0 deletions tests/unit/console_results_diff_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,26 @@ function test_render_diff_shows_changed_tokens_without_color() {
rm -f "$a" "$b"
unset BASHUNIT_NO_COLOR
}

function test_render_diff_ignores_a_configured_external_diff() {
if ! bashunit::dependencies::has_git; then
bashunit::skip "git not available" && return
fi
export BASHUNIT_NO_COLOR=true
# An external differ (difftastic in #912) replaces git's own output, so without
# --no-ext-diff the rendered diff is whatever it prints -- here nothing at all.
export GIT_EXTERNAL_DIFF=true
local a b
a=$(bashunit::temp_file diff_a)
b=$(bashunit::temp_file diff_b)
printf 'alpha\nbeta\ngamma\n' >"$a"
printf 'alpha\nDELTA\ngamma\n' >"$b"

local output
output=$(bashunit::console_results::render_diff "$a" "$b")

assert_contains "beta" "$output"
assert_contains "DELTA" "$output"
rm -f "$a" "$b"
unset BASHUNIT_NO_COLOR GIT_EXTERNAL_DIFF
}
1 change: 1 addition & 0 deletions tests/unit/console_results_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ function test_render_execution_time_on_osx_with_perl() {

local render_result
mock_macos
_BASHUNIT_CLOCK_NOW_IMPL="perl"
bashunit::mock bashunit::dependencies::has_perl mock_true
_BASHUNIT_START_TIME="1726393394574382186"
bashunit::mock perl <<<"1726393394574372186"
Expand Down
Loading