Skip to content

Commit 2a8bb5f

Browse files
committed
feature: remove curl perl and coreutils as required dependencies
1 parent 26288bd commit 2a8bb5f

20 files changed

+439
-39
lines changed

.github/CONTRIBUTING.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ docker run --rm -it -v "$(pwd)":/project -w /project ubuntu:latest \
9191
make test/alpine
9292
# or
9393
docker run --rm -it -v "$(pwd)":/project -w /project alpine:latest \
94-
sh -c "apk add bash make shellcheck git curl perl && make test"
94+
sh -c "apk add bash make shellcheck git && make test"
9595
```
9696

9797
## Coding Guidelines

.github/workflows/tests.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ jobs:
5858
run: |
5959
docker run --rm -v "$(pwd)":/project alpine:latest /bin/sh -c " \
6060
apk update && \
61-
apk add --no-cache bash make git curl perl coreutils && \
61+
apk add --no-cache bash make git && \
6262
adduser -D builder && \
6363
chown -R builder /project && \
6464
su - builder -c 'cd /project; make test';"

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
- Display failing tests after running the entire suite
1212
- Added defer expressions with `eval` when using standalone assertions
1313
- Fixed simple output for non-successful states
14+
- Some required dependencies now optional:
15+
- perl
16+
- coreutils
17+
- Switch to testing the environment of capabilities rather than assuming various operating systems and Linux
18+
distributions have programs installed.
19+
- Upgrade and install script can now use `wget` if `curl` is not installed
20+
- Tests can be also be timed by making use of `EPOCHREALTIME` on supported system.
1421

1522
## [0.16.0](https://github.com/TypedDevs/bashunit/compare/0.15.0...0.16.0) - 2024-09-15
1623

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ test/watch: $(TEST_SCRIPTS)
7070

7171
docker/alpine:
7272
@docker run --rm -it -v "$(shell pwd)":/project -w /project alpine:latest \
73-
sh -c "apk add bash make shellcheck git curl perl coreutils && bash"
73+
sh -c "apk add bash make shellcheck git && bash"
7474

7575
env/example:
7676
@echo "Copying variables without the values from .env into .env.example"

bashunit

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ export BASHUNIT_ROOT_DIR
1010

1111
source "$BASHUNIT_ROOT_DIR/src/dev/debug.sh"
1212
source "$BASHUNIT_ROOT_DIR/src/str.sh"
13+
source "$BASHUNIT_ROOT_DIR/src/dependencies.sh"
14+
source "$BASHUNIT_ROOT_DIR/src/io.sh"
15+
source "$BASHUNIT_ROOT_DIR/src/math.sh"
1316
source "$BASHUNIT_ROOT_DIR/src/default_env_config.sh"
1417
source "$BASHUNIT_ROOT_DIR/src/env_configuration.sh"
1518
source "$BASHUNIT_ROOT_DIR/src/check_os.sh"
@@ -30,6 +33,9 @@ _ASSERT_FN=""
3033
_FILTER=""
3134
_ARGS=()
3235

36+
check_os::init
37+
clock::init
38+
3339
while [[ $# -gt 0 ]]; do
3440
argument="$1"
3541
case $argument in

install.sh

+7-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,13 @@ function install() {
4545
echo "> Downloading the latest version: '$TAG'"
4646
fi
4747

48-
curl -L -O -J "https://github.com/TypedDevs/bashunit/releases/download/$TAG/bashunit" 2>/dev/null
48+
if command -v curl > /dev/null 2>&1; then
49+
curl -L -O -J "https://github.com/TypedDevs/bashunit/releases/download/$TAG/bashunit" 2>/dev/null
50+
elif command -v wget > /dev/null 2>&1; then
51+
wget "https://github.com/TypedDevs/bashunit/releases/download/$TAG/bashunit" 2>/dev/null
52+
else
53+
echo "Cannot download bashunit: curl or wget not found."
54+
fi
4955
chmod u+x "bashunit"
5056
}
5157

src/check_os.sh

+55-12
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,63 @@
44
_OS="Unknown"
55
_DISTRO="Unknown"
66

7-
if [[ "$(uname)" == "Linux" ]]; then
8-
_OS="Linux"
9-
if command -v apt > /dev/null; then
10-
_DISTRO="Ubuntu"
11-
elif command -v apk > /dev/null; then
12-
_DISTRO="Alpine"
7+
function check_os::init() {
8+
if check_os::is_linux; then
9+
_OS="Linux"
10+
if check_os::is_ubuntu; then
11+
_DISTRO="Ubuntu"
12+
elif check_os::is_alpine; then
13+
_DISTRO="Alpine"
14+
else
15+
_DISTRO="Other"
16+
fi
17+
elif check_os::is_macos; then
18+
_OS="OSX"
19+
elif check_os::is_windows; then
20+
_OS="Windows"
1321
else
14-
_DISTRO="Other"
22+
_OS="Unknown"
23+
_DISTRO="Unknown"
1524
fi
16-
elif [[ "$(uname)" == "Darwin" ]]; then
17-
_OS="OSX"
18-
elif [[ "$(uname)" == *"MINGW"* ]]; then
19-
_OS="Windows"
20-
fi
25+
}
26+
27+
function check_os::is_ubuntu() {
28+
command -v apt > /dev/null
29+
}
30+
31+
function check_os::is_alpine() {
32+
command -v apk > /dev/null
33+
}
34+
35+
function check_os::is_linux() {
36+
[[ "$(uname)" == "Linux" ]]
37+
}
38+
39+
function check_os::is_macos() {
40+
[[ "$(uname)" == "Darwin" ]]
41+
}
42+
43+
function check_os::is_windows() {
44+
[[ "$(uname)" == *"MINGW"* ]]
45+
}
46+
47+
function check_os::is_busybox() {
48+
49+
case "$_DISTRO" in
50+
51+
"Alpine")
52+
return 0
53+
;;
54+
*)
55+
return 1
56+
;;
57+
esac
58+
}
59+
60+
check_os::init
2161

2262
export _OS
2363
export _DISTRO
64+
export -f check_os::is_alpine
65+
export -f check_os::is_busybox
66+
export -f check_os::is_ubuntu

src/clock.sh

+45-8
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,59 @@
11
#!/bin/bash
22

33
function clock::now() {
4-
if perl -MTime::HiRes -e "" > /dev/null 2>&1; then
5-
perl -MTime::HiRes -e 'printf("%.0f\n", Time::HiRes::time() * 1000)'
6-
elif [[ "${_OS:-}" != "OSX" ]]; then
7-
date +%s%N
8-
else
9-
echo ""
4+
5+
if dependencies::has_perl && perl -MTime::HiRes -e "" > /dev/null 2>&1; then
6+
if perl -MTime::HiRes -e 'printf("%.0f\n",Time::HiRes::time()*1000000000)'; then
7+
return 0
8+
fi
109
fi
10+
11+
if ! check_os::is_macos && ! check_os::is_alpine; then
12+
date +%s%N
13+
return 0
14+
fi
15+
16+
17+
local shell_time has_shell_time
18+
shell_time="$(clock::shell_time)"
19+
has_shell_time="$?"
20+
if [[ "$has_shell_time" -eq 0 ]]; then
21+
local seconds microseconds
22+
seconds=$(echo "$shell_time" | cut -f 1 -d '.')
23+
microseconds=$(echo "$shell_time" | cut -f 2 -d '.')
24+
25+
math::calculate "($seconds * 1000000000) + ($microseconds * 1000)"
26+
return 0
27+
fi
28+
29+
echo ""
30+
return 1
31+
}
32+
33+
function clock::shell_time() {
34+
# Get time directly from the shell rather than a program.
35+
[[ -n ${EPOCHREALTIME+x} && -n "$EPOCHREALTIME" ]] && LC_ALL=C echo "$EPOCHREALTIME"
1136
}
1237

13-
_START_TIME=$(clock::now)
1438

1539
function clock::total_runtime_in_milliseconds() {
1640
end_time=$(clock::now)
1741
if [[ -n $end_time ]]; then
18-
echo $(( end_time - _START_TIME ))
42+
math::calculate "($end_time-$_START_TIME)/1000000"
43+
else
44+
echo ""
45+
fi
46+
}
47+
48+
function clock::total_runtime_in_nanoseconds() {
49+
end_time=$(clock::now)
50+
if [[ -n $end_time ]]; then
51+
math::calculate "($end_time-$_START_TIME)"
1952
else
2053
echo ""
2154
fi
2255
}
56+
57+
function clock::init() {
58+
_START_TIME=$(clock::now)
59+
}

src/console_results.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ function console_results::print_failed_snapshot_test() {
175175
line="$(printf "${_COLOR_FAILED}✗ Failed${_COLOR_DEFAULT}: %s
176176
${_COLOR_FAINT}Expected to match the snapshot${_COLOR_DEFAULT}\n" "$function_name")"
177177

178-
if command -v git > /dev/null; then
178+
if dependencies::has_git; then
179179
local actual_file="${snapshot_file}.tmp"
180180
echo "$actual" > "$actual_file"
181181

src/dependencies.sh

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
function dependencies::has_perl() {
5+
command -v perl >/dev/null 2>&1
6+
}
7+
8+
function dependencies::has_adjtimex() {
9+
command -v adjtimex >/dev/null 2>&1
10+
}
11+
12+
function dependencies::has_bc() {
13+
command -v bc >/dev/null 2>&1
14+
}
15+
16+
function dependencies::has_awk() {
17+
command -v awk >/dev/null 2>&1
18+
}
19+
20+
function dependencies::has_git() {
21+
command -v git >/dev/null 2>&1
22+
}
23+
24+
function dependencies::has_curl() {
25+
command -v curl >/dev/null 2>&1
26+
}
27+
28+
function dependencies::has_wget() {
29+
command -v wget >/dev/null 2>&1
30+
}

src/io.sh

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/bash
2+
3+
function io::download_to() {
4+
local url="$1"
5+
local output="$2"
6+
if dependencies::has_curl; then
7+
curl -L -J -o "$output" "$url" 2>/dev/null
8+
elif dependencies::has_wget; then
9+
wget -q -O "$output" "$url" 2>/dev/null
10+
else
11+
return 1
12+
fi
13+
}

src/math.sh

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
3+
if dependencies::has_bc; then
4+
# bc is better than awk because bc has no integer limits.
5+
function math::calculate() {
6+
echo "$*" | bc
7+
}
8+
elif dependencies::has_awk; then
9+
function math::calculate() {
10+
awk "BEGIN { print ""$*"" }"
11+
}
12+
fi

src/runner.sh

+6-2
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ function runner::run_test() {
179179
echo "$test_execution_result" |\
180180
tail -n 1 |\
181181
sed -E -e 's/.*##TEST_OUTPUT=(.*)##.*/\1/g' |\
182-
base64 --decode
182+
base64 -d
183183
)
184184

185185
if [[ -n "$subshell_output" ]]; then
@@ -213,7 +213,11 @@ function runner::run_test() {
213213

214214
local end_time
215215
end_time=$(clock::now)
216-
local duration=$((end_time - start_time))
216+
local duration
217+
local duration_ns
218+
duration_ns=$(math::calculate "($end_time - $start_time) ")
219+
duration=$(math::calculate "$duration_ns / 1000000")
220+
#
217221

218222
if [[ -n $runtime_error ]]; then
219223
state::add_tests_failed

src/upgrade.sh

+5-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ function upgrade::upgrade() {
1313

1414
echo "> Upgrading bashunit to latest version"
1515
cd "$script_path" || exit
16-
curl -L -J -o bashunit "https://github.com/TypedDevs/bashunit/releases/download/$latest_tag/bashunit" 2>/dev/null
16+
17+
if ! io::download_to "https://github.com/TypedDevs/bashunit/releases/download/$latest_tag/bashunit" "bashunit"; then
18+
echo "Failed to download bashunit"
19+
fi
20+
1721
chmod u+x "bashunit"
1822

1923
echo "> bashunit upgraded successfully to latest version $latest_tag"

tests/globals.sh

+64
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,67 @@ function current_dir() {
88
function current_filename() {
99
basename "${BASH_SOURCE[1]}"
1010
}
11+
12+
13+
function mock_non_existing_fn() {
14+
return 127;
15+
}
16+
17+
function mock_false() {
18+
return 1;
19+
}
20+
21+
function mock_true() {
22+
return 0;
23+
}
24+
25+
function mock_unknown_linux_os() {
26+
mock check_os::is_linux mock_true
27+
28+
mock check_os::is_ubuntu mock_false
29+
mock check_os::is_alpine mock_false
30+
mock check_os::is_busybox mock_false
31+
mock check_os::is_macos mock_false
32+
mock check_os::is_windows mock_false
33+
}
34+
35+
36+
function mock_ubuntu_os() {
37+
mock check_os::is_linux mock_true
38+
mock check_os::is_ubuntu mock_true
39+
40+
mock check_os::is_alpine mock_false
41+
mock check_os::is_busybox mock_false
42+
mock check_os::is_macos mock_false
43+
mock check_os::is_windows mock_false
44+
}
45+
46+
function mock_alpine_os() {
47+
mock check_os::is_linux mock_true
48+
mock check_os::is_alpine mock_true
49+
mock check_os::is_busybox mock_true
50+
51+
mock check_os::is_ubuntu mock_false
52+
mock check_os::is_macos mock_false
53+
mock check_os::is_windows mock_false
54+
}
55+
56+
function mock_macos() {
57+
mock check_os::is_macos mock_true
58+
59+
mock check_os::is_linux mock_false
60+
mock check_os::is_alpine mock_false
61+
mock check_os::is_ubuntu mock_false
62+
mock check_os::is_busybox mock_false
63+
mock check_os::is_windows mock_false
64+
}
65+
66+
function mock_windows_os() {
67+
mock check_os::is_windows mock_true
68+
69+
mock check_os::is_linux mock_false
70+
mock check_os::is_alpine mock_false
71+
mock check_os::is_ubuntu mock_false
72+
mock check_os::is_busybox mock_false
73+
mock check_os::is_is_macos mock_false
74+
}

0 commit comments

Comments
 (0)