From a1cc0e71e40748d51793025aa0c86ffc7b66b2f1 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Fri, 18 Sep 2026 12:04:37 +0200 Subject: [PATCH] fix(cli): quote the typed invocation in the --assert deprecation warning bashunit -a reaches the deprecated path through the inferred test subcommand, so the warning always named bashunit test --assert, a command the user never ran. --- CHANGELOG.md | 1 + bashunit | 4 ++++ src/main/test.sh | 12 +++++++++- .../acceptance/bashunit_assert_errors_test.sh | 24 +++++++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ea7192b..c252ac81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Performance: a test in a file that defines `set_up` or `tear_down` is about 2.6x faster, which brings it level with a hookless test (14.1ms to 5.4ms per test on macOS arm64, bash 3.2). Each hook minted its output file with `mktemp` and removed it with `rm`, and the ownership marker that left behind made the runner `rm -rf` the test's temp files at exit — five forks per test, even for a test that created no temp file of its own (#1345) ### Fixed +- The deprecation warning for the old `--assert` option quotes the invocation that was typed. `bashunit -a` reaches the deprecated path through the inferred `test` subcommand, so the warning named `bashunit test --assert`, a command the user never ran, and read like a warning about something else. It now prints `bashunit -a`, `bashunit --assert` or `bashunit test --assert` to match (#1366) - `assert_contains_ignore_case` documents what it actually guarantees: ASCII case folding. Whether `ñ` matches `Ñ` depends on the shell version, the locale and which `tr` the system ships — BSD `tr` folds it, GNU and busybox `tr` do not, and `nocasematch` only folds it in a UTF-8 locale. Behaviour is unchanged (#1351) - A test function whose name another selected name starts with is no longer rejected as a duplicate. `test_a` alongside `test_ab` read as one name twice, which made the whole file select nothing. Only definition order reached it, so nothing hit it before (#1347) - Coverage counts every line of a multiline statement: array literals, quoted strings, heredocs, backslash continuations. An array written one element per line cost one uncovered line per element. Bash 3.x records the assignment on its closing `)`, so there the whole array read as uncovered. A parent statement's hits no longer mark commands inside command or process substitutions as covered, even within quotes or arrays (#1338) diff --git a/bashunit b/bashunit index fc9c76a5..2f3d8f4a 100755 --- a/bashunit +++ b/bashunit @@ -100,10 +100,14 @@ bashunit::clock::init # Subcommand detection _SUBCOMMAND="" +# Whether the subcommand was typed or inferred. A deprecation warning quotes the +# invocation back to the user, so it has to know which one they actually ran. +_SUBCOMMAND_IS_EXPLICIT=false case "${1:-}" in test | bench | doc | init | upgrade | assert | watch) _SUBCOMMAND="$1" + _SUBCOMMAND_IS_EXPLICIT=true shift ;; learn) diff --git a/src/main/test.sh b/src/main/test.sh index 17d9d5fe..9d7a7b6c 100644 --- a/src/main/test.sh +++ b/src/main/test.sh @@ -110,6 +110,7 @@ function bashunit::main::cmd_test() { local -a args=() local args_count=0 local assert_fn="" + local deprecated_assert_form="" local _bashunit_coverage_opt_set=false # Named suites are resolved into plain flags and paths before anything is @@ -140,7 +141,16 @@ function bashunit::main::cmd_test() { # accepts test-level flags (`--env`, `--no-parallel`). `bashunit assert` # forwards everything to the assertion instead. Removing this form needs # that gap closed first. - bashunit::env::warn_deprecated "\`bashunit test --assert\`" "\`bashunit assert\`" + # + # Quote back the invocation that was typed: `bashunit -a` reaches here + # through the inferred `test` subcommand, and naming a command the user + # never ran reads like a warning about something else (#1366). + deprecated_assert_form="bashunit $1" + if [ "${_SUBCOMMAND_IS_EXPLICIT:-false}" = "true" ]; then + deprecated_assert_form="bashunit test $1" + fi + bashunit::env::warn_deprecated \ + "\`$deprecated_assert_form\`" "\`bashunit assert\`" assert_fn="$2" shift ;; diff --git a/tests/acceptance/bashunit_assert_errors_test.sh b/tests/acceptance/bashunit_assert_errors_test.sh index 11791631..a9557425 100644 --- a/tests/acceptance/bashunit_assert_errors_test.sh +++ b/tests/acceptance/bashunit_assert_errors_test.sh @@ -79,6 +79,30 @@ function test_bashunit_old_assert_option_warns_that_it_is_deprecated() { assert_contains "bashunit assert" "$warnings" } +# The warning names the invocation the user typed, not the canonical spelling +# of the deprecated form: naming a command they never ran reads like an +# unrelated warning (#1366). +function test_bashunit_old_assert_option_warns_with_the_short_form_typed() { + local warnings + warnings=$(./bashunit -a equals "foo" "foo" 2>&1 >/dev/null) + + assert_contains "\`bashunit -a\`" "$warnings" +} + +function test_bashunit_old_assert_option_warns_with_the_long_form_typed() { + local warnings + warnings=$(./bashunit --assert equals "foo" "foo" 2>&1 >/dev/null) + + assert_contains "\`bashunit --assert\`" "$warnings" +} + +function test_bashunit_old_assert_option_warns_with_the_explicit_test_command() { + local warnings + warnings=$(./bashunit test --assert equals "foo" "foo" 2>&1 >/dev/null) + + assert_contains "\`bashunit test --assert\`" "$warnings" +} + function test_bashunit_new_assert_subcommand_does_not_warn() { local warnings warnings=$(./bashunit assert equals "foo" "foo" 2>&1 >/dev/null)