Skip to content

Commit be1497b

Browse files
committed
refactor(compat): replace [[ with [ ] for Bash 3.0+ compatibility
Replace all ~410 [[ ]] test constructs across 28 source files with Bash 3.0+ compatible alternatives to ensure the framework works on macOS default bash and older systems. Replacements applied: - [[ ]] → [ ] for simple tests (-f, -n, -z, -eq, -gt, etc.) - [[ == ]] → [ = ] for string equality - [[ =~ ]] → grep -qE / sed extraction for regex matching - [[ == pattern* ]] → case statements for glob matching - Compound [[ A || B ]] → [ A ] || [ B ] - Compound [[ A && B ]] → [ A ] && [ B ]
1 parent 379a917 commit be1497b

28 files changed

Lines changed: 615 additions & 553 deletions

src/assert.sh

Lines changed: 82 additions & 54 deletions
Large diffs are not rendered by default.

src/assert_arrays.sh

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@ function assert_array_contains() {
1313
local -a actual
1414
actual=("$@")
1515

16-
if ! [[ "${actual[*]:-}" == *"$expected"* ]]; then
16+
case "${actual[*]:-}" in
17+
*"$expected"*)
18+
;;
19+
*)
1720
bashunit::assert::mark_failed
1821
bashunit::console_results::print_failed_test "${label}" "${actual[*]}" "to contain" "${expected}"
1922
return
20-
fi
23+
;;
24+
esac
2125

2226
bashunit::state::add_assertions_passed
2327
}
@@ -34,11 +38,13 @@ function assert_array_not_contains() {
3438
local -a actual
3539
actual=("$@")
3640

37-
if [[ "${actual[*]:-}" == *"$expected"* ]]; then
41+
case "${actual[*]:-}" in
42+
*"$expected"*)
3843
bashunit::assert::mark_failed
3944
bashunit::console_results::print_failed_test "${label}" "${actual[*]}" "to not contain" "${expected}"
4045
return
41-
fi
46+
;;
47+
esac
4248

4349
bashunit::state::add_assertions_passed
4450
}

src/assert_dates.sh

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ function assert_date_equals() {
5353
local actual
5454
actual="$(bashunit::date::to_epoch "$2")"
5555

56-
if [[ "$actual" -ne "$expected" ]]; then
56+
if [ "$actual" -ne "$expected" ]; then
5757
local test_fn
5858
test_fn="$(bashunit::helper::find_test_function_name)"
5959
local label
@@ -74,7 +74,7 @@ function assert_date_before() {
7474
local actual
7575
actual="$(bashunit::date::to_epoch "$2")"
7676

77-
if ! [[ "$actual" -lt "$expected" ]]; then
77+
if [ "$actual" -ge "$expected" ]; then
7878
local test_fn
7979
test_fn="$(bashunit::helper::find_test_function_name)"
8080
local label
@@ -95,7 +95,7 @@ function assert_date_after() {
9595
local actual
9696
actual="$(bashunit::date::to_epoch "$2")"
9797

98-
if ! [[ "$actual" -gt "$expected" ]]; then
98+
if [ "$actual" -le "$expected" ]; then
9999
local test_fn
100100
test_fn="$(bashunit::helper::find_test_function_name)"
101101
local label
@@ -118,7 +118,7 @@ function assert_date_within_range() {
118118
local actual
119119
actual="$(bashunit::date::to_epoch "$3")"
120120

121-
if [[ "$actual" -lt "$from" ]] || [[ "$actual" -gt "$to" ]]; then
121+
if [ "$actual" -lt "$from" ] || [ "$actual" -gt "$to" ]; then
122122
local test_fn
123123
test_fn="$(bashunit::helper::find_test_function_name)"
124124
local label
@@ -141,11 +141,11 @@ function assert_date_within_delta() {
141141
local delta="$3"
142142

143143
local diff=$((actual - expected))
144-
if [[ "$diff" -lt 0 ]]; then
144+
if [ "$diff" -lt 0 ]; then
145145
diff=$((-diff))
146146
fi
147147

148-
if [[ "$diff" -gt "$delta" ]]; then
148+
if [ "$diff" -gt "$delta" ]; then
149149
local test_fn
150150
test_fn="$(bashunit::helper::find_test_function_name)"
151151
local label

src/assert_files.sh

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function assert_file_exists() {
88
test_fn="$(bashunit::helper::find_test_function_name)"
99
local label="${3:-$(bashunit::helper::normalize_test_function_name "$test_fn")}"
1010

11-
if [[ ! -f "$expected" ]]; then
11+
if [ ! -f "$expected" ]; then
1212
bashunit::assert::mark_failed
1313
bashunit::console_results::print_failed_test "${label}" "${expected}" "to exist but" "do not exist"
1414
return
@@ -25,7 +25,7 @@ function assert_file_not_exists() {
2525
test_fn="$(bashunit::helper::find_test_function_name)"
2626
local label="${3:-$(bashunit::helper::normalize_test_function_name "$test_fn")}"
2727

28-
if [[ -f "$expected" ]]; then
28+
if [ -f "$expected" ]; then
2929
bashunit::assert::mark_failed
3030
bashunit::console_results::print_failed_test "${label}" "${expected}" "to not exist but" "the file exists"
3131
return
@@ -42,7 +42,7 @@ function assert_is_file() {
4242
test_fn="$(bashunit::helper::find_test_function_name)"
4343
local label="${3:-$(bashunit::helper::normalize_test_function_name "$test_fn")}"
4444

45-
if [[ ! -f "$expected" ]]; then
45+
if [ ! -f "$expected" ]; then
4646
bashunit::assert::mark_failed
4747
bashunit::console_results::print_failed_test "${label}" "${expected}" "to be a file" "but is not a file"
4848
return
@@ -59,7 +59,7 @@ function assert_is_file_empty() {
5959
test_fn="$(bashunit::helper::find_test_function_name)"
6060
local label="${3:-$(bashunit::helper::normalize_test_function_name "$test_fn")}"
6161

62-
if [[ -s "$expected" ]]; then
62+
if [ -s "$expected" ]; then
6363
bashunit::assert::mark_failed
6464
bashunit::console_results::print_failed_test "${label}" "${expected}" "to be empty" "but is not empty"
6565
return
@@ -74,7 +74,7 @@ function assert_files_equals() {
7474
local expected="$1"
7575
local actual="$2"
7676

77-
if [[ "$(diff -u "$expected" "$actual")" != '' ]]; then
77+
if [ "$(diff -u "$expected" "$actual")" != '' ]; then
7878
local test_fn
7979
test_fn="$(bashunit::helper::find_test_function_name)"
8080
local label
@@ -95,7 +95,7 @@ function assert_files_not_equals() {
9595
local expected="$1"
9696
local actual="$2"
9797

98-
if [[ "$(diff -u "$expected" "$actual")" == '' ]]; then
98+
if [ "$(diff -u "$expected" "$actual")" = '' ]; then
9999
local test_fn
100100
test_fn="$(bashunit::helper::find_test_function_name)"
101101
local label

src/assert_folders.sh

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function assert_directory_exists() {
88
test_fn="$(bashunit::helper::find_test_function_name)"
99
local label="${2:-$(bashunit::helper::normalize_test_function_name "$test_fn")}"
1010

11-
if [[ ! -d "$expected" ]]; then
11+
if [ ! -d "$expected" ]; then
1212
bashunit::assert::mark_failed
1313
bashunit::console_results::print_failed_test "${label}" "${expected}" "to exist but" "do not exist"
1414
return
@@ -25,7 +25,7 @@ function assert_directory_not_exists() {
2525
test_fn="$(bashunit::helper::find_test_function_name)"
2626
local label="${2:-$(bashunit::helper::normalize_test_function_name "$test_fn")}"
2727

28-
if [[ -d "$expected" ]]; then
28+
if [ -d "$expected" ]; then
2929
bashunit::assert::mark_failed
3030
bashunit::console_results::print_failed_test "${label}" "${expected}" "to not exist but" "the directory exists"
3131
return
@@ -42,7 +42,7 @@ function assert_is_directory() {
4242
test_fn="$(bashunit::helper::find_test_function_name)"
4343
local label="${2:-$(bashunit::helper::normalize_test_function_name "$test_fn")}"
4444

45-
if [[ ! -d "$expected" ]]; then
45+
if [ ! -d "$expected" ]; then
4646
bashunit::assert::mark_failed
4747
bashunit::console_results::print_failed_test "${label}" "${expected}" "to be a directory" "but is not a directory"
4848
return
@@ -59,7 +59,7 @@ function assert_is_directory_empty() {
5959
test_fn="$(bashunit::helper::find_test_function_name)"
6060
local label="${2:-$(bashunit::helper::normalize_test_function_name "$test_fn")}"
6161

62-
if [[ ! -d "$expected" || -n "$(ls -A "$expected")" ]]; then
62+
if [ ! -d "$expected" ] || [ -n "$(ls -A "$expected")" ]; then
6363
bashunit::assert::mark_failed
6464
bashunit::console_results::print_failed_test "${label}" "${expected}" "to be empty" "but is not empty"
6565
return
@@ -76,7 +76,7 @@ function assert_is_directory_not_empty() {
7676
test_fn="$(bashunit::helper::find_test_function_name)"
7777
local label="${2:-$(bashunit::helper::normalize_test_function_name "$test_fn")}"
7878

79-
if [[ ! -d "$expected" || -z "$(ls -A "$expected")" ]]; then
79+
if [ ! -d "$expected" ] || [ -z "$(ls -A "$expected")" ]; then
8080
bashunit::assert::mark_failed
8181
bashunit::console_results::print_failed_test "${label}" "${expected}" "to not be empty" "but is empty"
8282
return
@@ -93,7 +93,7 @@ function assert_is_directory_readable() {
9393
test_fn="$(bashunit::helper::find_test_function_name)"
9494
local label="${2:-$(bashunit::helper::normalize_test_function_name "$test_fn")}"
9595

96-
if [[ ! -d "$expected" || ! -r "$expected" || ! -x "$expected" ]]; then
96+
if [ ! -d "$expected" ] || [ ! -r "$expected" ] || [ ! -x "$expected" ]; then
9797
bashunit::assert::mark_failed
9898
bashunit::console_results::print_failed_test "${label}" "${expected}" "to be readable" "but is not readable"
9999
return
@@ -110,7 +110,7 @@ function assert_is_directory_not_readable() {
110110
test_fn="$(bashunit::helper::find_test_function_name)"
111111
local label="${2:-$(bashunit::helper::normalize_test_function_name "$test_fn")}"
112112

113-
if [[ ! -d "$expected" ]] || [[ -r "$expected" && -x "$expected" ]]; then
113+
if [ ! -d "$expected" ] || { [ -r "$expected" ] && [ -x "$expected" ]; }; then
114114
bashunit::assert::mark_failed
115115
bashunit::console_results::print_failed_test "${label}" "${expected}" "to be not readable" "but is readable"
116116
return
@@ -127,7 +127,7 @@ function assert_is_directory_writable() {
127127
test_fn="$(bashunit::helper::find_test_function_name)"
128128
local label="${2:-$(bashunit::helper::normalize_test_function_name "$test_fn")}"
129129

130-
if [[ ! -d "$expected" || ! -w "$expected" ]]; then
130+
if [ ! -d "$expected" ] || [ ! -w "$expected" ]; then
131131
bashunit::assert::mark_failed
132132
bashunit::console_results::print_failed_test "${label}" "${expected}" "to be writable" "but is not writable"
133133
return
@@ -144,7 +144,7 @@ function assert_is_directory_not_writable() {
144144
test_fn="$(bashunit::helper::find_test_function_name)"
145145
local label="${2:-$(bashunit::helper::normalize_test_function_name "$test_fn")}"
146146

147-
if [[ ! -d "$expected" || -w "$expected" ]]; then
147+
if [ ! -d "$expected" ] || [ -w "$expected" ]; then
148148
bashunit::assert::mark_failed
149149
bashunit::console_results::print_failed_test "${label}" "${expected}" "to be not writable" "but is writable"
150150
return

src/assert_snapshot.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ function assert_match_snapshot() {
77
test_fn="$(bashunit::helper::find_test_function_name)"
88
local snapshot_file=$(bashunit::snapshot::resolve_file "${2:-}" "$test_fn")
99

10-
if [[ ! -f "$snapshot_file" ]]; then
10+
if [ ! -f "$snapshot_file" ]; then
1111
bashunit::snapshot::initialize "$snapshot_file" "$actual"
1212
return
1313
fi
@@ -21,7 +21,7 @@ function assert_match_snapshot_ignore_colors() {
2121
test_fn="$(bashunit::helper::find_test_function_name)"
2222
local snapshot_file=$(bashunit::snapshot::resolve_file "${2:-}" "$test_fn")
2323

24-
if [[ ! -f "$snapshot_file" ]]; then
24+
if [ ! -f "$snapshot_file" ]; then
2525
bashunit::snapshot::initialize "$snapshot_file" "$actual"
2626
return
2727
fi
@@ -56,7 +56,7 @@ function bashunit::snapshot::resolve_file() {
5656
local file_hint="$1"
5757
local func_name="$2"
5858

59-
if [[ -n "$file_hint" ]]; then
59+
if [ -n "$file_hint" ]; then
6060
echo "$file_hint"
6161
else
6262
local dir="./$(dirname "${BASH_SOURCE[2]}")/snapshots"

src/benchmark.sh

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,33 @@ function bashunit::benchmark::parse_annotations() {
1616
local annotation
1717
annotation=$(awk "/function[[:space:]]+${fn_name}[[:space:]]*\(/ {print prev; exit} {prev=\$0}" "$script")
1818

19-
local _re='@revs=([0-9]+)'
20-
if [[ "$annotation" =~ $_re ]]; then
21-
revs="${BASH_REMATCH[1]}"
19+
local _extracted
20+
_extracted=$(echo "$annotation" | sed -n 's/.*@revs=\([0-9][0-9]*\).*/\1/p')
21+
if [ -n "$_extracted" ]; then
22+
revs="$_extracted"
2223
else
23-
_re='@revolutions=([0-9]+)'
24-
if [[ "$annotation" =~ $_re ]]; then
25-
revs="${BASH_REMATCH[1]}"
24+
_extracted=$(echo "$annotation" | sed -n 's/.*@revolutions=\([0-9][0-9]*\).*/\1/p')
25+
if [ -n "$_extracted" ]; then
26+
revs="$_extracted"
2627
fi
2728
fi
2829

29-
_re='@its=([0-9]+)'
30-
if [[ "$annotation" =~ $_re ]]; then
31-
its="${BASH_REMATCH[1]}"
30+
_extracted=$(echo "$annotation" | sed -n 's/.*@its=\([0-9][0-9]*\).*/\1/p')
31+
if [ -n "$_extracted" ]; then
32+
its="$_extracted"
3233
else
33-
_re='@iterations=([0-9]+)'
34-
if [[ "$annotation" =~ $_re ]]; then
35-
its="${BASH_REMATCH[1]}"
34+
_extracted=$(echo "$annotation" | sed -n 's/.*@iterations=\([0-9][0-9]*\).*/\1/p')
35+
if [ -n "$_extracted" ]; then
36+
its="$_extracted"
3637
fi
3738
fi
3839

39-
_re='@max_ms=([0-9.]+)'
40-
if [[ "$annotation" =~ $_re ]]; then
41-
max_ms="${BASH_REMATCH[1]}"
42-
else
43-
_re='@max_ms=([0-9.]+)'
44-
if [[ "$annotation" =~ $_re ]]; then
45-
max_ms="${BASH_REMATCH[1]}"
46-
fi
40+
_extracted=$(echo "$annotation" | sed -n 's/.*@max_ms=\([0-9.][0-9.]*\).*/\1/p')
41+
if [ -n "$_extracted" ]; then
42+
max_ms="$_extracted"
4743
fi
4844

49-
if [[ -n "$max_ms" ]]; then
45+
if [ -n "$max_ms" ]; then
5046
echo "$revs" "$its" "$max_ms"
5147
else
5248
echo "$revs" "$its"
@@ -122,7 +118,7 @@ function bashunit::benchmark::print_results() {
122118
local has_threshold=false
123119
local val
124120
for val in "${_BASHUNIT_BENCH_MAX_MILLIS[@]+"${_BASHUNIT_BENCH_MAX_MILLIS[@]}"}"; do
125-
if [[ -n "$val" ]]; then
121+
if [ -n "$val" ]; then
126122
has_threshold=true
127123
break
128124
fi
@@ -142,12 +138,12 @@ function bashunit::benchmark::print_results() {
142138
local avg="${_BASHUNIT_BENCH_AVERAGES[$i]:-}"
143139
local max_ms="${_BASHUNIT_BENCH_MAX_MILLIS[$i]:-}"
144140

145-
if [[ -z "$max_ms" ]]; then
141+
if [ -z "$max_ms" ]; then
146142
printf '%-40s %6s %6s %10s\n' "$name" "$revs" "$its" "$avg"
147143
continue
148144
fi
149145

150-
if [[ "$avg" -le "$max_ms" ]]; then
146+
if [ "$avg" -le "$max_ms" ]; then
151147
local raw="${max_ms}"
152148
local padded
153149
padded=$(printf "%14s" "$raw")

src/check_os.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,18 @@ function bashunit::check_os::is_alpine() {
3636
}
3737

3838
function bashunit::check_os::is_nixos() {
39-
[[ -f /etc/NIXOS ]] && return 0
39+
[ -f /etc/NIXOS ] && return 0
4040
grep -q '^ID=nixos' /etc/os-release 2>/dev/null
4141
}
4242

4343
_BASHUNIT_UNAME="$(uname)"
4444

4545
function bashunit::check_os::is_linux() {
46-
[[ "$_BASHUNIT_UNAME" == "Linux" ]]
46+
[ "$_BASHUNIT_UNAME" = "Linux" ]
4747
}
4848

4949
function bashunit::check_os::is_macos() {
50-
[[ "$_BASHUNIT_UNAME" == "Darwin" ]]
50+
[ "$_BASHUNIT_UNAME" = "Darwin" ]
5151
}
5252

5353
function bashunit::check_os::is_windows() {

src/clock.sh

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ function bashunit::clock::_choose_impl() {
2222
if ! bashunit::check_os::is_macos && ! bashunit::check_os::is_alpine; then
2323
local result
2424
result=$(date +%s%N 2>/dev/null)
25-
local _re='^[0-9]+$'
26-
if [[ "$result" != *N ]] && [[ "$result" =~ $_re ]]; then
25+
if echo "$result" | grep -qv 'N' && echo "$result" | grep -qE '^[0-9]+$'; then
2726
_BASHUNIT_CLOCK_NOW_IMPL="date"
2827
return 0
2928
fi
@@ -76,7 +75,7 @@ function bashunit::clock::_choose_impl() {
7675
}
7776

7877
function bashunit::clock::now() {
79-
if [[ -z "$_BASHUNIT_CLOCK_NOW_IMPL" ]]; then
78+
if [ -z "$_BASHUNIT_CLOCK_NOW_IMPL" ]; then
8079
bashunit::clock::_choose_impl || return 1
8180
fi
8281

@@ -131,13 +130,13 @@ EOF
131130

132131
function bashunit::clock::shell_time() {
133132
# Get time directly from the shell variable EPOCHREALTIME (Bash 5+)
134-
[[ -n ${EPOCHREALTIME+x} && -n "$EPOCHREALTIME" ]] && LC_ALL=C echo "$EPOCHREALTIME"
133+
[ -n "${EPOCHREALTIME+x}" ] && [ -n "$EPOCHREALTIME" ] && LC_ALL=C echo "$EPOCHREALTIME"
135134
}
136135

137136
function bashunit::clock::total_runtime_in_milliseconds() {
138137
local end_time
139138
end_time=$(bashunit::clock::now)
140-
if [[ -n $end_time ]]; then
139+
if [ -n "$end_time" ]; then
141140
bashunit::math::calculate "($end_time - $_BASHUNIT_START_TIME) / 1000000"
142141
else
143142
echo ""
@@ -147,7 +146,7 @@ function bashunit::clock::total_runtime_in_milliseconds() {
147146
function bashunit::clock::total_runtime_in_nanoseconds() {
148147
local end_time
149148
end_time=$(bashunit::clock::now)
150-
if [[ -n $end_time ]]; then
149+
if [ -n "$end_time" ]; then
151150
bashunit::math::calculate "$end_time - $_BASHUNIT_START_TIME"
152151
else
153152
echo ""

src/console_header.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function bashunit::console_header::print_version() {
2323
# Bash 3.0 compatible: check argument count after shift
2424
local files_count=$#
2525
local total_tests
26-
if [[ "$files_count" -eq 0 ]]; then
26+
if [ "$files_count" -eq 0 ]; then
2727
total_tests=0
2828
elif bashunit::parallel::is_enabled && bashunit::env::is_simple_output_enabled; then
2929
# Skip counting in parallel+simple mode for faster startup

0 commit comments

Comments
 (0)