Skip to content

Commit 7d635c9

Browse files
authored
Merge pull request #279 from TypedDevs/feat/171-logs
Add logging
2 parents c830f41 + 96d3997 commit 7d635c9

20 files changed

+212
-16
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ SIMPLE_OUTPUT=
44
STOP_ON_FAILURE=
55
SHOW_EXECUTION_TIME=
66
DEFAULT_PATH=
7+
LOG_JUNIT=

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ docs/.vitepress/dist
1111
bin/bashunit
1212
bin/checksum
1313
lib/bashunit
14+
15+
# logger
16+
log-junit.xml

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
- Fix echo does not break test execution results
66
- Add bashunit facade to enable custom assertions
7-
- Document how to verify the sha256sum of the final executable
7+
- Document how to verify the `sha256sum` of the final executable
8+
- Enable display execution time on MacOS with `SHOW_EXECUTION_TIME`
9+
- Add `-l|--log-junit <output.xml>` option
810

911
## [0.13.0](https://github.com/TypedDevs/bashunit/compare/0.12.0...0.13.0) - 2024-06-23
1012

bashunit

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export BASHUNIT_ROOT_DIR
88

99
source "$BASHUNIT_ROOT_DIR/src/default_env_config.sh"
1010
source "$BASHUNIT_ROOT_DIR/src/env_configuration.sh"
11+
source "$BASHUNIT_ROOT_DIR/src/clock.sh"
1112
source "$BASHUNIT_ROOT_DIR/src/check_os.sh"
1213
source "$BASHUNIT_ROOT_DIR/src/state.sh"
1314
source "$BASHUNIT_ROOT_DIR/src/colors.sh"
@@ -16,6 +17,7 @@ source "$BASHUNIT_ROOT_DIR/src/console_results.sh"
1617
source "$BASHUNIT_ROOT_DIR/src/helpers.sh"
1718
source "$BASHUNIT_ROOT_DIR/src/upgrade.sh"
1819
source "$BASHUNIT_ROOT_DIR/src/assertions.sh"
20+
source "$BASHUNIT_ROOT_DIR/src/logger.sh"
1921
source "$BASHUNIT_ROOT_DIR/src/runner.sh"
2022
source "$BASHUNIT_ROOT_DIR/src/bashunit.sh"
2123
source "$BASHUNIT_ROOT_DIR/src/main.sh"
@@ -55,6 +57,11 @@ while [[ $# -gt 0 ]]; do
5557
shift
5658
shift
5759
;;
60+
-l|--log-junit)
61+
LOG_JUNIT="$2";
62+
shift
63+
shift
64+
;;
5865
--version)
5966
console_header::print_version
6067
trap '' EXIT && exit 0

docs/command-line.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,19 @@ Filters the tests to be run based on the `test name`.
7070
```
7171
:::
7272

73+
## Logging
74+
s
75+
> `bashunit -l|--log-junit log-junit.xml`
76+
77+
Create a report XML file that follows the JUnit XML format and contains information about the test results of your bashunit tests.
78+
79+
::: code-group
80+
```bash [Example]
81+
./bashunit ./tests --log-junit log-junit.xml
82+
```
83+
:::
84+
85+
7386
## Output
7487

7588
> `bashunit -s|--simple`

src/clock.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/bash
2+
3+
function clock::now() {
4+
perl -MTime::HiRes -e 'printf("%.0f\n",Time::HiRes::time()*1000)'
5+
}
6+
7+
_START_TIME=$(clock::now)
8+
9+
function clock::runtime_in_milliseconds() {
10+
echo $(( $(clock::now) - _START_TIME ))
11+
}

src/console_results.sh

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#!/bin/bash
22

3-
_START_TIME=$(date +%s%N);
43
_SUCCESSFUL_TEST_COUNT=0
54

65
function console_results::render_result() {
@@ -9,7 +8,7 @@ function console_results::render_result() {
98
printf "%s%s%s\n" "${_COLOR_RETURN_ERROR}" "Duplicate test functions found" "${_COLOR_DEFAULT}"
109
printf "File with duplicate functions: %s\n" "$(state::get_file_with_duplicated_function_names)"
1110
printf "Duplicate functions: %s\n" "$(state::get_duplicated_function_names)"
12-
exit 1
11+
return 1
1312
fi
1413

1514
echo ""
@@ -67,47 +66,45 @@ function console_results::render_result() {
6766
if [[ "$(state::get_tests_failed)" -gt 0 ]]; then
6867
printf "\n%s%s%s\n" "$_COLOR_RETURN_ERROR" " Some tests failed " "$_COLOR_DEFAULT"
6968
console_results::print_execution_time
70-
exit 1
69+
return 1
7170
fi
7271

7372
if [[ "$(state::get_tests_incomplete)" -gt 0 ]]; then
7473
printf "\n%s%s%s\n" "$_COLOR_RETURN_INCOMPLETE" " Some tests incomplete " "$_COLOR_DEFAULT"
7574
console_results::print_execution_time
76-
exit 0
75+
return 0
7776
fi
7877

7978
if [[ "$(state::get_tests_skipped)" -gt 0 ]]; then
8079
printf "\n%s%s%s\n" "$_COLOR_RETURN_SKIPPED" " Some tests skipped " "$_COLOR_DEFAULT"
8180
console_results::print_execution_time
82-
exit 0
81+
return 0
8382
fi
8483

8584
if [[ "$(state::get_tests_snapshot)" -gt 0 ]]; then
8685
printf "\n%s%s%s\n" "$_COLOR_RETURN_SNAPSHOT" " Some snapshots created " "$_COLOR_DEFAULT"
8786
console_results::print_execution_time
88-
exit 0
87+
return 0
8988
fi
9089

9190
if [[ $total_tests -eq 0 ]]; then
9291
printf "\n%s%s%s\n" "$_COLOR_RETURN_ERROR" " No tests found " "$_COLOR_DEFAULT"
9392
console_results::print_execution_time
94-
exit 1
93+
return 1
9594
fi
9695

9796
printf "\n%s%s%s\n" "$_COLOR_RETURN_SUCCESS" " All tests passed " "$_COLOR_DEFAULT"
9897
console_results::print_execution_time
99-
exit 0
98+
return 0
10099
}
101100

102101
function console_results::print_execution_time() {
103102
if [[ $SHOW_EXECUTION_TIME == false ]]; then
104103
return
105104
fi
106105

107-
if [[ "$_OS" != "OSX" ]]; then
108-
_EXECUTION_TIME=$((($(date +%s%N) - "$_START_TIME") / 1000000))
109-
printf "${_COLOR_BOLD}%s${_COLOR_DEFAULT}\n" "Time taken: ${_EXECUTION_TIME} ms"
110-
fi
106+
_EXECUTION_TIME=$(clock::runtime_in_milliseconds)
107+
printf "${_COLOR_BOLD}%s${_COLOR_DEFAULT}\n" "Time taken: ${_EXECUTION_TIME} ms"
111108
}
112109

113110
function console_results::print_successful_test() {

src/default_env_config.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ _DEFAULT_SIMPLE_OUTPUT=false
88
_DEFAULT_STOP_ON_FAILURE=false
99
_DEFAULT_SHOW_EXECUTION_TIME=true
1010
_DEFAULT_DEFAULT_PATH=
11+
_DEFAULT_LOG_JUNIT=
1112
CAT="$(which cat)"

src/env_configuration.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,7 @@ fi
3232
if [[ -z "$DEFAULT_PATH" ]]; then
3333
DEFAULT_PATH=$_DEFAULT_DEFAULT_PATH
3434
fi
35+
36+
if [[ -z "$LOG_JUNIT" ]]; then
37+
LOG_JUNIT=$_DEFAULT_LOG_JUNIT
38+
fi

src/logger.sh

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/bin/bash
2+
3+
TEST_NAMES=()
4+
TEST_STATUSES=()
5+
TEST_DURATIONS=()
6+
TEST_ERRORS=()
7+
8+
function logger::test_snapshot() {
9+
logger::log "$1" "$2" "snapshot" "$3"
10+
}
11+
12+
function logger::test_incomplete() {
13+
logger::log "$1" "$2" "incomplete" "$3"
14+
}
15+
16+
function logger::test_skipped() {
17+
logger::log "$1" "$2" "skipped" "$3"
18+
}
19+
20+
function logger::test_passed() {
21+
logger::log "$1" "$2" "passed" "$3"
22+
}
23+
24+
function logger::test_failed() {
25+
logger::log "$1" "$2" "failed" "$3"
26+
}
27+
28+
function logger::log() {
29+
local test_name="$1"
30+
local start_time="$2"
31+
local status="$3"
32+
local error_msg="${4:-}"
33+
34+
local end_time
35+
end_time=$(clock::now)
36+
local duration=$((end_time - start_time))
37+
38+
TEST_NAMES+=("$test_name")
39+
TEST_STATUSES+=("$status")
40+
TEST_DURATIONS+=("$duration")
41+
TEST_ERRORS+=("$error_msg")
42+
}
43+
44+
function logger::generate_junit_xml() {
45+
local output_file="$1"
46+
local test_passed
47+
test_passed=$(state::get_tests_passed)
48+
local tests_skipped
49+
tests_skipped=$(state::get_tests_skipped)
50+
local tests_incomplete
51+
tests_incomplete=$(state::get_tests_incomplete)
52+
local tests_snapshot
53+
tests_snapshot=$(state::get_tests_snapshot)
54+
local tests_failed
55+
tests_failed=$(state::get_tests_failed)
56+
local time
57+
time=$(clock::runtime_in_milliseconds)
58+
59+
{
60+
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
61+
echo "<testsuites>"
62+
echo " <testsuite name=\"bashunit\" tests=\"${#TEST_NAMES[@]}\" time=\"$time\""
63+
echo " passed=\"$test_passed\" failures=\"$tests_failed\" incomplete=\"$tests_incomplete\""
64+
echo " skipped=\"$tests_skipped\" snapshot=\"$tests_snapshot\">"
65+
66+
for i in "${!TEST_NAMES[@]}"; do
67+
local name="${TEST_NAMES[$i]}"
68+
local status="${TEST_STATUSES[$i]}"
69+
local test_time="${TEST_DURATIONS[$i]}"
70+
local msg="${TEST_ERRORS[$i]}"
71+
72+
echo " <testcase name=\"$name\" time=\"$test_time\" status=\"$status\">"
73+
if [[ -n $msg ]]; then
74+
echo " <message>$msg<message/>"
75+
fi
76+
echo " </testcase>"
77+
done
78+
79+
echo " </testsuite>"
80+
echo "</testsuites>"
81+
} > "$output_file"
82+
}

src/main.sh

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ function main::exec_tests() {
77
console_header::print_version_with_env
88
runner::load_test_files "$filter" "${files[@]}"
99
console_results::render_result
10-
exit 0
10+
exit_code=$?
11+
12+
if [[ -n "$LOG_JUNIT" ]]; then
13+
logger::generate_junit_xml "$LOG_JUNIT"
14+
fi
15+
16+
exit $exit_code
1117
}
1218

1319
function main::exec_assert() {

src/runner.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ function runner::parse_execution_result() {
142142
}
143143

144144
function runner::run_test() {
145+
local start_time
146+
start_time=$(clock::now)
147+
145148
local function_name="$1"
146149
shift
147150
local current_assertions_failed
@@ -188,11 +191,13 @@ function runner::run_test() {
188191
if [[ -n $runtime_error ]]; then
189192
state::add_tests_failed
190193
console_results::print_error_test "$function_name" "$runtime_error"
194+
logger::test_failed "$function_name" "$start_time"
191195
return
192196
fi
193197

194198
if [[ "$current_assertions_failed" != "$(state::get_assertions_failed)" ]]; then
195199
state::add_tests_failed
200+
logger::test_failed "$function_name" "$start_time"
196201

197202
if [ "$STOP_ON_FAILURE" = true ]; then
198203
exit 1
@@ -204,16 +209,19 @@ function runner::run_test() {
204209
if [[ "$current_assertions_snapshot" != "$(state::get_assertions_snapshot)" ]]; then
205210
state::add_tests_snapshot
206211
console_results::print_snapshot_test "$function_name"
212+
logger::test_snapshot "$function_name" "$start_time"
207213
return
208214
fi
209215

210216
if [[ "$current_assertions_incomplete" != "$(state::get_assertions_incomplete)" ]]; then
211217
state::add_tests_incomplete
218+
logger::test_incomplete "$function_name" "$start_time"
212219
return
213220
fi
214221

215222
if [[ "$current_assertions_skipped" != "$(state::get_assertions_skipped)" ]]; then
216223
state::add_tests_skipped
224+
logger::test_skipped "$function_name" "$start_time"
217225
return
218226
fi
219227

@@ -222,6 +230,7 @@ function runner::run_test() {
222230

223231
console_results::print_successful_test "${label}" "$@"
224232
state::add_tests_passed
233+
logger::test_passed "$function_name" "$start_time"
225234
}
226235

227236
function runner::run_set_up() {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/bash
2+
3+
function set_up_before_script() {
4+
TEST_ENV_FILE="tests/acceptance/fixtures/.env.default"
5+
TEST_ENV_FILE_LOG_JUNIT="tests/acceptance/fixtures/.env.log_junit"
6+
}
7+
8+
function test_bashunit_when_log_junit_option() {
9+
local test_file=./tests/acceptance/fixtures/test_bashunit_when_log_junit.sh
10+
11+
assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE" --log-junit custom.xml "$test_file")"
12+
assert_file_exists custom.xml
13+
rm custom.xml
14+
}
15+
16+
function test_bashunit_when_log_junit_env() {
17+
local test_file=./tests/acceptance/fixtures/test_bashunit_when_log_junit.sh
18+
19+
assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE_LOG_JUNIT" "$test_file")"
20+
assert_file_exists log-junit.xml
21+
rm log-junit.xml
22+
}

tests/acceptance/fixtures/.env.default

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ SIMPLE_OUTPUT=false
44
STOP_ON_FAILURE=false
55
SHOW_EXECUTION_TIME=false
66
DEFAULT_PATH=
7+
LOG_JUNIT=
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
SHOW_HEADER=false
2+
HEADER_ASCII_ART=false
3+
SIMPLE_OUTPUT=false
4+
STOP_ON_FAILURE=true
5+
SHOW_EXECUTION_TIME=false
6+
DEFAULT_PATH=
7+
LOG_JUNIT=log-junit.xml
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/bash
2+
3+
function test_a() {
4+
assert_equals 1 1
5+
}
6+
7+
function test_b() {
8+
assert_equals 2 2
9+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Running ./tests/acceptance/fixtures/test_bashunit_when_log_junit.sh
2+
✓ Passed: A
3+
✓ Passed: B
4+
5+
Tests:  2 passed, 2 total
6+
Assertions: 2 passed, 2 total
7+
8+
 All tests passed 
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Running ./tests/acceptance/fixtures/test_bashunit_when_log_junit.sh
2+
✓ Passed: A
3+
✓ Passed: B
4+
5+
Tests:  2 passed, 2 total
6+
Assertions: 2 passed, 2 total
7+
8+
 All tests passed 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Running ./tests/acceptance/fixtures/test_bashunit_when_log_junit.sh
2+
✓ Passed: A success
3+
✗ Failed: B error
4+
Expected '1'
5+
but got '2'

0 commit comments

Comments
 (0)