Skip to content

Commit 2a2e24f

Browse files
omargallobOmar GalloChemaclass
authored
refactor(coverage): improve coverage inside lifecycle hooks (#574)
Co-authored-by: Omar Gallo <omar.gallo@mercedes-benz-com> Co-authored-by: Chemaclass <chemaclass@outlook.es>
1 parent aec3eb3 commit 2a2e24f

8 files changed

Lines changed: 83 additions & 10 deletions

File tree

.github/workflows/tests-bash-3.0.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
- name: Build Bash 3.0 Docker image
2121
run: |
2222
docker build -t bashunit-bash3 -f - . <<'EOF'
23-
FROM debian:bullseye-slim
23+
FROM debian:bookworm-slim
2424
2525
RUN apt-get update && apt-get install -y \
2626
build-essential \

.github/workflows/tests.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ jobs:
7171
alpine:
7272
name: "On alpine-latest"
7373
runs-on: ubuntu-latest
74+
timeout-minutes: 10
7475
steps:
7576
- name: Checkout
7677
uses: actions/checkout@v4
@@ -89,6 +90,7 @@ jobs:
8990
simple-output:
9091
name: "Simple output"
9192
runs-on: ubuntu-latest
93+
timeout-minutes: 10
9294
steps:
9395
- name: Checkout
9496
uses: actions/checkout@v4
@@ -102,6 +104,7 @@ jobs:
102104
simple-output-parallel:
103105
name: "Simple output in parallel"
104106
runs-on: ubuntu-latest
107+
timeout-minutes: 10
105108
steps:
106109
- name: Checkout
107110
uses: actions/checkout@v4
@@ -115,6 +118,7 @@ jobs:
115118
extended-output-parallel:
116119
name: "Extended output in parallel"
117120
runs-on: ubuntu-latest
121+
timeout-minutes: 10
118122
steps:
119123
- name: Checkout
120124
uses: actions/checkout@v4
@@ -128,6 +132,7 @@ jobs:
128132
strict-mode:
129133
name: "Strict mode"
130134
runs-on: ubuntu-latest
135+
timeout-minutes: 10
131136
steps:
132137
- name: Checkout
133138
uses: actions/checkout@v4

src/assert_dates.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ function bashunit::date::to_epoch() {
3434
echo "$epoch"
3535
return 0
3636
}
37-
# Try BSD date with date-only format
38-
epoch=$(date -j -f "%Y-%m-%d" "$input" +%s 2>/dev/null) && {
37+
# Try BSD date with date-only format (append midnight for deterministic results)
38+
epoch=$(date -j -f "%Y-%m-%d %H:%M:%S" "$input 00:00:00" +%s 2>/dev/null) && {
3939
echo "$epoch"
4040
return 0
4141
}

src/coverage.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ function bashunit::coverage::enable_trap() {
9999
# Set DEBUG trap to record line execution
100100
# Use ${VAR:-} to handle unset variables when set -u is active (in subshells)
101101
# shellcheck disable=SC2154
102-
trap 'bashunit::coverage::record_line "${BASH_SOURCE:-}" "${LINENO:-}"' DEBUG
102+
trap 'bashunit::coverage::record_line "${BASH_SOURCE[0]:-}" "${LINENO:-}"' DEBUG
103103
}
104104

105105
function bashunit::coverage::disable_trap() {

src/runner.sh

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ function bashunit::runner::load_test_files() {
2828
# Auto-discover coverage paths if not explicitly set
2929
if [[ -z "$BASHUNIT_COVERAGE_PATHS" ]]; then
3030
BASHUNIT_COVERAGE_PATHS=$(bashunit::coverage::auto_discover_paths "${files[@]}")
31+
# Fallback: if auto-discovery yields no paths, track the src/ folder
32+
if [[ -z "$BASHUNIT_COVERAGE_PATHS" ]]; then
33+
BASHUNIT_COVERAGE_PATHS="src/"
34+
fi
3135
fi
3236
bashunit::coverage::init
3337
fi
@@ -564,6 +568,11 @@ function bashunit::runner::run_test() {
564568
[[ -f ~/.profile ]] && source ~/.profile 2>/dev/null || true
565569
fi
566570
571+
# Enable coverage tracking early to include set_up/tear_down hooks
572+
if bashunit::env::is_coverage_enabled; then
573+
bashunit::coverage::enable_trap
574+
fi
575+
567576
# Run set_up and capture exit code without || to preserve errexit behavior
568577
local setup_exit_code=0
569578
bashunit::runner::run_set_up "$test_file"
@@ -579,11 +588,6 @@ function bashunit::runner::run_test() {
579588
set +euo pipefail
580589
fi
581590
582-
# Enable coverage tracking if enabled
583-
if bashunit::env::is_coverage_enabled; then
584-
bashunit::coverage::enable_trap
585-
fi
586-
587591
# 2>&1: Redirects the std-error (FD 2) to the std-output (FD 1).
588592
# points to the original std-output.
589593
"$fn_name" "$@" 2>&1
@@ -1037,10 +1041,20 @@ function bashunit::runner::run_set_up_before_script() {
10371041
local start_time
10381042
start_time=$(bashunit::clock::now)
10391043

1044+
# Enable coverage trap to attribute lines executed during set_up_before_script
1045+
if bashunit::env::is_coverage_enabled; then
1046+
bashunit::coverage::enable_trap
1047+
fi
1048+
10401049
# Execute the hook (render_header=false since header is already rendered)
10411050
bashunit::runner::execute_file_hook 'set_up_before_script' "$test_file" false
10421051
local status=$?
10431052

1053+
# Disable coverage trap after hook execution
1054+
if bashunit::env::is_coverage_enabled; then
1055+
bashunit::coverage::disable_trap
1056+
fi
1057+
10441058
local end_time
10451059
end_time=$(bashunit::clock::now)
10461060
local duration_ns=$((end_time - start_time))
@@ -1162,10 +1176,20 @@ function bashunit::runner::run_tear_down_after_script() {
11621176
local start_time
11631177
start_time=$(bashunit::clock::now)
11641178

1179+
# Enable coverage trap to attribute lines executed during tear_down_after_script
1180+
if bashunit::env::is_coverage_enabled; then
1181+
bashunit::coverage::enable_trap
1182+
fi
1183+
11651184
# Execute the hook
11661185
bashunit::runner::execute_file_hook 'tear_down_after_script' "$test_file"
11671186
local status=$?
11681187

1188+
# Disable coverage trap after hook execution
1189+
if bashunit::env::is_coverage_enabled; then
1190+
bashunit::coverage::disable_trap
1191+
fi
1192+
11691193
local end_time
11701194
end_time=$(bashunit::clock::now)
11711195
local duration_ns=$((end_time - start_time))
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env bash
2+
# shellcheck disable=SC2034
3+
4+
LCOV_FILE=""
5+
6+
function set_up_before_script() {
7+
LCOV_FILE="$(bashunit::temp_file "lcov-hooks")"
8+
}
9+
10+
function test_coverage_tracks_src_lines_executed_in_hooks() {
11+
local output
12+
output=$(BASHUNIT_PARALLEL_RUN=false ./bashunit \
13+
--coverage \
14+
--no-coverage-report \
15+
--coverage-paths "src/globals.sh" \
16+
--coverage-report "$LCOV_FILE" \
17+
tests/acceptance/fixtures/test_coverage_hooks.sh 2>&1)
18+
19+
assert_successful_code
20+
21+
local lcov
22+
lcov="$(cat "$LCOV_FILE" 2>/dev/null)"
23+
24+
assert_not_empty "$lcov"
25+
assert_contains "SF:" "$lcov"
26+
assert_contains "DA:" "$lcov"
27+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/env bash
2+
3+
# This fixture exercises coverage attribution inside lifecycle hooks.
4+
# The set_up hook calls src/ functions; coverage should track those lines.
5+
6+
function set_up() {
7+
local f
8+
f="$(bashunit::temp_file "cov-hooks")"
9+
if [ -n "${f:-}" ]; then
10+
echo "tmp created" > /dev/null
11+
fi
12+
}
13+
14+
function test_noop() {
15+
# No-op test; coverage should still attribute lines from set_up
16+
assert_true true
17+
}

tests/unit/assert_dates_test.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ function test_successful_assert_date_within_range_with_iso_dates() {
120120
function test_successful_assert_date_equals_with_mixed_formats() {
121121
local epoch
122122
epoch=$(date -d "2023-06-15" +%s 2>/dev/null) \
123-
|| epoch=$(date -j -f "%Y-%m-%d" "2023-06-15" +%s 2>/dev/null)
123+
|| epoch=$(date -j -f "%Y-%m-%d %H:%M:%S" "2023-06-15 00:00:00" +%s 2>/dev/null)
124124

125125
assert_empty "$(assert_date_equals "$epoch" "2023-06-15")"
126126
}

0 commit comments

Comments
 (0)