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 @@ -7,6 +7,7 @@
- Hot-path coverage flag now cached in `_BASHUNIT_COVERAGE_ON`, removing a function dispatch per call (#664)
- Parallel runner blocks on `wait -n` on Bash 4.3+ instead of polling `jobs -r`, removing sleep-induced slot-release latency (#667)
- Hot-path result helpers (`extract_encoded_field`, `extract_subshell_type`, `format_subshell_output`, `compute_total_assertions`) use outvar pattern, dropping a fork per call per test (#662)
- `generate_id` and `normalize_variable_name` drop `grep` and `random_str` forks via pure-bash globbing/inlining (#663)

## [0.36.0](https://github.com/TypedDevs/bashunit/compare/0.35.0...0.36.0) - 2026-05-07

Expand Down
36 changes: 24 additions & 12 deletions src/helpers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -268,14 +268,15 @@ function bashunit::helper::find_files_recursive() {

function bashunit::helper::normalize_variable_name() {
local input_string="$1"
local normalized_string

normalized_string="${input_string//[^a-zA-Z0-9_]/_}"

local _re='^[a-zA-Z_]'
if [ "$(builtin echo "$normalized_string" | "$GREP" -cE "$_re" || true)" -eq 0 ]; then
normalized_string="_$normalized_string"
fi
local normalized_string="${input_string//[^a-zA-Z0-9_]/_}"

# First character must be alpha or underscore. Empty string also gets a `_`
# prefix to satisfy the same identifier rule. Uses pure-bash globbing to
# avoid a per-call grep fork (called once per test via generate_id).
case "${normalized_string:0:1}" in
[a-zA-Z_]) ;;
*) normalized_string="_$normalized_string" ;;
esac

builtin echo "$normalized_string"
}
Expand Down Expand Up @@ -439,12 +440,23 @@ function bashunit::helper::get_function_line_number() {

function bashunit::helper::generate_id() {
local basename="$1"
local sanitized_basename
sanitized_basename="$(bashunit::helper::normalize_variable_name "$basename")"
# Inline normalize_variable_name + random_str to avoid two forks per call.
# generate_id is called once per test and per file load.
local sanitized="${basename//[^a-zA-Z0-9_]/_}"
case "${sanitized:0:1}" in
[a-zA-Z_]) ;;
*) sanitized="_$sanitized" ;;
esac
if bashunit::env::is_parallel_run_enabled; then
echo "${sanitized_basename}_$$_$(bashunit::random_str 6)"
local _chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
local _suffix=''
local _i
for ((_i = 0; _i < 6; _i++)); do
_suffix="$_suffix${_chars:RANDOM%${#_chars}:1}"
done
echo "${sanitized}_$$_${_suffix}"
else
echo "${sanitized_basename}_$$"
echo "${sanitized}_$$"
fi
}

Expand Down
39 changes: 39 additions & 0 deletions tests/unit/helpers_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,45 @@ function test_check_duplicate_functions_without_function_keyword() {
assert_general_error "$(bashunit::helper::check_duplicate_functions "$file")"
}

function test_generate_id_uses_pid_suffix_when_not_parallel() {
local _orig="${BASHUNIT_PARALLEL_RUN-}"
export BASHUNIT_PARALLEL_RUN=false

local id
id="$(bashunit::helper::generate_id "test_foo")"
assert_same "test_foo_$$" "$id"

export BASHUNIT_PARALLEL_RUN="$_orig"
}

function test_generate_id_appends_random_suffix_when_parallel() {
local _orig="${BASHUNIT_PARALLEL_RUN-}"
export BASHUNIT_PARALLEL_RUN=true

local id1 id2
id1="$(bashunit::helper::generate_id "test_foo")"
id2="$(bashunit::helper::generate_id "test_foo")"

assert_matches "^test_foo_${$}_[a-zA-Z0-9]{6}$" "$id1"
assert_matches "^test_foo_${$}_[a-zA-Z0-9]{6}$" "$id2"

export BASHUNIT_PARALLEL_RUN="$_orig"
}

function test_generate_id_sanitizes_basename() {
local _orig="${BASHUNIT_PARALLEL_RUN-}"
export BASHUNIT_PARALLEL_RUN=false

local id
id="$(bashunit::helper::generate_id "my-file.sh")"
assert_same "my_file_sh_$$" "$id"

id="$(bashunit::helper::generate_id "123start")"
assert_same "_123start_$$" "$id"

export BASHUNIT_PARALLEL_RUN="$_orig"
}

function test_normalize_variable_name() {
assert_same "valid_name123" "$(bashunit::helper::normalize_variable_name "valid_name123")"
assert_same "non_valid_symbols__________" "$(bashunit::helper::normalize_variable_name "non_valid_symbols!@#$%^&*()")"
Expand Down
Loading