Skip to content

Commit e068096

Browse files
authored
Merge pull request #452 from TypedDevs/fix/447-assert-snapshot
Fix broken core snapshot tests
2 parents bc2390e + 561ea08 commit e068096

File tree

7 files changed

+111
-124
lines changed

7 files changed

+111
-124
lines changed

.github/workflows/tests.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,17 @@ jobs:
118118
- name: Run Tests
119119
run: |
120120
./bashunit --parallel tests/
121+
122+
nixos:
123+
name: "NixOS"
124+
runs-on: ubuntu-latest
125+
steps:
126+
- name: Checkout
127+
uses: actions/checkout@v4
128+
with:
129+
fetch-depth: 1
130+
131+
- name: Run Tests
132+
run: |
133+
docker run --rm -v "$(pwd)":/project -w /project nixos/nix:latest \
134+
nix-shell -p bash --run "./bashunit --simple tests/"

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
- Fix broken core snapshot tests
6+
- Improve NixOS support
7+
38
## [0.22.1](https://github.com/TypedDevs/bashunit/compare/0.22.0...0.22.1) - 2025-07-23
49

510
- Fix prevents writing in src dir during tests

src/assert_snapshot.sh

Lines changed: 60 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,88 @@
11
#!/usr/bin/env bash
2+
# shellcheck disable=SC2155
23

3-
function snapshot::match_with_placeholder() {
4-
local actual="$1"
5-
local snapshot="$2"
6-
local placeholder="${BASHUNIT_SNAPSHOT_PLACEHOLDER:-::ignore::}"
7-
local token="__BASHUNIT_IGNORE__"
4+
function assert_match_snapshot() {
5+
local actual=$(echo -n "$1" | tr -d '\r')
6+
local snapshot_file=$(snapshot::resolve_file "${2:-}" "${FUNCNAME[1]}")
87

9-
local sanitized_snapshot="${snapshot//$placeholder/$token}"
10-
local regex
11-
regex=$(printf '%s' "$sanitized_snapshot" | sed -e 's/[.[\\^$*+?{}()|]/\\&/g')
12-
regex="${regex//$token/(.|\\n)*}"
13-
regex="^${regex}$"
14-
15-
if command -v perl >/dev/null 2>&1; then
16-
if REGEX="$regex" perl -0 -e 'my $r=$ENV{REGEX}; exit((join("",<>)) =~ /$r/s ? 0 : 1);' <<< "$actual"; then
17-
return 0
18-
else
19-
return 1
20-
fi
21-
else
22-
# fallback: only supports single-line ignores
23-
local fallback_pattern
24-
fallback_pattern=$(printf '%s' "$snapshot" | sed "s|$placeholder|.*|g")
25-
# escape other special regex chars
26-
fallback_pattern=$(printf '%s' "$fallback_pattern" | sed -e 's/[][\.^$*+?{}|()]/\\&/g')
27-
fallback_pattern="^${fallback_pattern}$"
28-
29-
if printf '%s\n' "$actual" | grep -Eq "$fallback_pattern"; then
30-
return 0
31-
else
32-
return 1
33-
fi
8+
if [[ ! -f "$snapshot_file" ]]; then
9+
snapshot::initialize "$snapshot_file" "$actual"
10+
return
3411
fi
12+
13+
snapshot::compare "$actual" "$snapshot_file" "${FUNCNAME[1]}"
3514
}
3615

37-
# shellcheck disable=SC2155
38-
function assert_match_snapshot() {
39-
local actual
40-
actual=$(echo -n "$1" | tr -d '\r')
41-
local snapshot_file="${2-}"
42-
43-
if [[ -z "$snapshot_file" ]]; then
44-
local directory="./$(dirname "${BASH_SOURCE[1]}")/snapshots"
45-
local test_file="$(helper::normalize_variable_name "$(basename "${BASH_SOURCE[1]}")")"
46-
local snapshot_name="$(helper::normalize_variable_name "${FUNCNAME[1]}").snapshot"
47-
snapshot_file="${directory}/${test_file}.${snapshot_name}"
48-
fi
16+
function assert_match_snapshot_ignore_colors() {
17+
local actual=$(echo -n "$1" | sed 's/\x1B\[[0-9;]*[mK]//g' | tr -d '\r')
18+
local snapshot_file=$(snapshot::resolve_file "${2:-}" "${FUNCNAME[1]}")
4919

5020
if [[ ! -f "$snapshot_file" ]]; then
51-
mkdir -p "$(dirname "$snapshot_file")"
52-
echo "$actual" > "$snapshot_file"
53-
54-
state::add_assertions_snapshot
21+
snapshot::initialize "$snapshot_file" "$actual"
5522
return
5623
fi
5724

58-
local snapshot
59-
snapshot=$(tr -d '\r' < "$snapshot_file")
25+
snapshot::compare "$actual" "$snapshot_file" "${FUNCNAME[1]}"
26+
}
6027

61-
if ! snapshot::match_with_placeholder "$actual" "$snapshot"; then
62-
local label
63-
label=$(helper::normalize_test_function_name "${FUNCNAME[1]}")
28+
function snapshot::match_with_placeholder() {
29+
local actual="$1"
30+
local snapshot="$2"
31+
local placeholder="${BASHUNIT_SNAPSHOT_PLACEHOLDER:-::ignore::}"
32+
local token="__BASHUNIT_IGNORE__"
6433

65-
state::add_assertions_failed
66-
console_results::print_failed_snapshot_test "$label" "$snapshot_file"
34+
local sanitized="${snapshot//$placeholder/$token}"
35+
local escaped=$(printf '%s' "$sanitized" | sed -e 's/[.[\\^$*+?{}()|]/\\&/g')
36+
local regex="^${escaped//$token/(.|\\n)*}$"
6737

68-
return
38+
if which perl >/dev/null 2>&1; then
39+
echo "$actual" | REGEX="$regex" perl -0 -e '
40+
my $r = $ENV{REGEX};
41+
my $input = join("", <STDIN>);
42+
exit($input =~ /$r/s ? 0 : 1);
43+
' && return 0 || return 1
44+
else
45+
local fallback=$(printf '%s' "$snapshot" | sed -e "s|$placeholder|.*|g" -e 's/[][\.^$*+?{}|()]/\\&/g')
46+
fallback="^${fallback}$"
47+
echo "$actual" | grep -Eq "$fallback" && return 0 || return 1
6948
fi
70-
71-
state::add_assertions_passed
7249
}
7350

74-
# shellcheck disable=SC2155
75-
function assert_match_snapshot_ignore_colors() {
76-
local actual
77-
actual=$(echo -n "$1" | sed -r 's/\x1B\[[0-9;]*[mK]//g' | tr -d '\r')
78-
79-
local snapshot_file="${2-}"
80-
if [[ -z "$snapshot_file" ]]; then
81-
local directory="./$(dirname "${BASH_SOURCE[1]}")/snapshots"
82-
local test_file="$(helper::normalize_variable_name "$(basename "${BASH_SOURCE[1]}")")"
83-
local snapshot_name="$(helper::normalize_variable_name "${FUNCNAME[1]}").snapshot"
84-
snapshot_file="${directory}/${test_file}.${snapshot_name}"
51+
function snapshot::resolve_file() {
52+
local file_hint="$1"
53+
local func_name="$2"
54+
55+
if [[ -n "$file_hint" ]]; then
56+
echo "$file_hint"
57+
else
58+
local dir="./$(dirname "${BASH_SOURCE[2]}")/snapshots"
59+
local test_file="$(helper::normalize_variable_name "$(basename "${BASH_SOURCE[2]}")")"
60+
local name="$(helper::normalize_variable_name "$func_name").snapshot"
61+
echo "${dir}/${test_file}.${name}"
8562
fi
63+
}
8664

87-
if [[ ! -f "$snapshot_file" ]]; then
88-
mkdir -p "$(dirname "$snapshot_file")"
89-
echo "$actual" > "$snapshot_file"
65+
function snapshot::initialize() {
66+
local path="$1"
67+
local content="$2"
68+
mkdir -p "$(dirname "$path")"
69+
echo "$content" > "$path"
70+
state::add_assertions_snapshot
71+
}
9072

91-
state::add_assertions_snapshot
92-
return
93-
fi
73+
function snapshot::compare() {
74+
local actual="$1"
75+
local snapshot_path="$2"
76+
local func_name="$3"
9477

9578
local snapshot
96-
snapshot=$(tr -d '\r' < "$snapshot_file")
79+
snapshot=$(tr -d '\r' < "$snapshot_path")
9780

9881
if ! snapshot::match_with_placeholder "$actual" "$snapshot"; then
99-
local label
100-
label=$(helper::normalize_test_function_name "${FUNCNAME[1]}")
101-
82+
local label=$(helper::normalize_test_function_name "$func_name")
10283
state::add_assertions_failed
103-
console_results::print_failed_snapshot_test "$label" "$snapshot_file"
104-
105-
return
84+
console_results::print_failed_snapshot_test "$label" "$snapshot_path"
85+
return 1
10686
fi
10787

10888
state::add_assertions_passed

src/check_os.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ function check_os::init() {
1111
_DISTRO="Ubuntu"
1212
elif check_os::is_alpine; then
1313
_DISTRO="Alpine"
14+
elif check_os::is_nixos; then
15+
_DISTRO="NixOS"
1416
else
1517
_DISTRO="Other"
1618
fi
@@ -32,6 +34,11 @@ function check_os::is_alpine() {
3234
command -v apk > /dev/null
3335
}
3436

37+
function check_os::is_nixos() {
38+
[[ -f /etc/NIXOS ]] && return 0
39+
grep -q '^ID=nixos' /etc/os-release 2>/dev/null
40+
}
41+
3542
function check_os::is_linux() {
3643
[[ "$(uname)" == "Linux" ]]
3744
}
@@ -71,3 +78,4 @@ export _DISTRO
7178
export -f check_os::is_alpine
7279
export -f check_os::is_busybox
7380
export -f check_os::is_ubuntu
81+
export -f check_os::is_nixos

tests/unit/assert_snapshot_test.sh

Lines changed: 24 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
11
#!/usr/bin/env bash
2+
# shellcheck disable=SC2155
23

34
function set_up() {
45
export BASHUNIT_SIMPLE_OUTPUT=false
6+
unset BASHUNIT_SNAPSHOT_PLACEHOLDER
57
}
68

79
function test_successful_assert_match_snapshot() {
810
assert_empty "$(assert_match_snapshot "Hello World!")"
911
}
1012

1113
function test_creates_a_snapshot() {
12-
local snapshot_path=tests/unit/snapshots/assert_snapshot_test_sh.test_creates_a_snapshot.snapshot
14+
local snapshot_path="$(temp_dir)/assert_snapshot_test_sh.test_creates_a_snapshot.snapshot"
1315
local expected=$((_ASSERTIONS_SNAPSHOT + 1))
1416

15-
assert_file_not_exists $snapshot_path
16-
17-
assert_match_snapshot "Expected snapshot"
17+
assert_file_not_exists "$snapshot_path"
18+
assert_match_snapshot "Expected snapshot" "$snapshot_path"
1819

1920
assert_same "$expected" "$_ASSERTIONS_SNAPSHOT"
20-
assert_file_exists $snapshot_path
21-
assert_same "Expected snapshot" "$(cat $snapshot_path)"
22-
23-
rm $snapshot_path
21+
assert_file_exists "$snapshot_path"
22+
assert_same "Expected snapshot" "$(cat "$snapshot_path")"
2423
}
2524

2625
function test_unsuccessful_assert_match_snapshot() {
@@ -35,34 +34,27 @@ function test_unsuccessful_assert_match_snapshot() {
3534
Expected to match the snapshot")"
3635
fi
3736

38-
local actual
39-
actual="$(assert_match_snapshot "Expected snapshot")"
37+
local actual="$(assert_match_snapshot "Expected snapshot")"
4038

4139
assert_equals "$expected" "$actual"
4240
}
4341

4442
function test_successful_assert_match_snapshot_ignore_colors() {
45-
local colored
46-
colored=$(printf '\e[31mHello\e[0m World!')
43+
local colored=$(printf '\e[31mHello\e[0m World!')
4744
assert_empty "$(assert_match_snapshot_ignore_colors "$colored")"
4845
}
4946

5047
function test_creates_a_snapshot_ignore_colors() {
51-
local snapshot_path=tests/unit/snapshots/assert_snapshot_test_sh.test_creates_a_snapshot_ignore_colors.snapshot
48+
local snapshot_path="$(temp_dir)/assert_snapshot_test_sh.test_creates_a_snapshot_ignore_colors.snapshot"
5249
local expected=$((_ASSERTIONS_SNAPSHOT + 1))
5350

54-
assert_file_not_exists $snapshot_path
55-
56-
local colored
57-
colored=$(printf '\e[32mExpected\e[0m snapshot')
58-
59-
assert_match_snapshot_ignore_colors "$colored"
51+
assert_file_not_exists "$snapshot_path"
52+
local colored=$(printf '\e[32mExpected\e[0m snapshot')
53+
assert_match_snapshot_ignore_colors "$colored" "$snapshot_path"
6054

6155
assert_same "$expected" "$_ASSERTIONS_SNAPSHOT"
62-
assert_file_exists $snapshot_path
63-
assert_same "Expected snapshot" "$(cat $snapshot_path)"
64-
65-
rm $snapshot_path
56+
assert_file_exists "$snapshot_path"
57+
assert_same "Expected snapshot" "$(cat "$snapshot_path")"
6658
}
6759

6860
function test_unsuccessful_assert_match_snapshot_ignore_colors() {
@@ -77,41 +69,31 @@ function test_unsuccessful_assert_match_snapshot_ignore_colors() {
7769
Expected to match the snapshot")"
7870
fi
7971

80-
local actual
81-
local colored
82-
colored=$(printf '\e[31mExpected snapshot\e[0m')
83-
actual="$(assert_match_snapshot_ignore_colors "$colored")"
72+
local colored=$(printf '\e[31mExpected snapshot\e[0m')
73+
local actual="$(assert_match_snapshot_ignore_colors "$colored")"
8474

8575
assert_equals "$expected" "$actual"
8676
}
8777

8878
function test_assert_match_snapshot_with_placeholder() {
89-
if check_os::is_alpine; then
90-
skip "not supported on alpine" && return
79+
if ! dependencies::has_perl; then
80+
skip "perl not available" && return
9181
fi
9282

93-
local temp_dir
94-
temp_dir=$(mktemp -d)
95-
local snapshot_path="$temp_dir/assert_snapshot_test_sh.test_assert_match_snapshot_with_placeholder.snapshot"
83+
local snapshot_path="$(temp_dir)/assert_snapshot_test_sh.test_assert_match_snapshot_with_placeholder.snapshot"
9684
echo 'Run at ::ignore::' > "$snapshot_path"
9785

98-
assert_empty "$(assert_match_snapshot "Run at $(date)" "$snapshot_path")"
99-
100-
rm -rf "$temp_dir"
86+
assert_empty "$(assert_match_snapshot "Run at $(date -u '+%F %T UTC')" "$snapshot_path")"
10187
}
10288

10389
function test_assert_match_snapshot_with_custom_placeholder() {
104-
if check_os::is_alpine; then
105-
skip "not supported on alpine" && return
90+
if ! dependencies::has_perl; then
91+
skip "perl not available" && return
10692
fi
10793

108-
local temp_dir
109-
temp_dir=$(mktemp -d)
110-
local snapshot_path="$temp_dir/assert_snapshot_test_sh.test_assert_match_snapshot_with_custom_placeholder.snapshot"
94+
local snapshot_path="$(temp_dir)/assert_snapshot_test_sh.test_assert_match_snapshot_with_custom_placeholder.snapshot"
11195
echo 'Value __ANY__' > "$snapshot_path"
11296

11397
export BASHUNIT_SNAPSHOT_PLACEHOLDER='__ANY__'
11498
assert_empty "$(assert_match_snapshot "Value 42" "$snapshot_path")"
115-
116-
rm -rf "$temp_dir"
11799
}

tests/unit/snapshots/assert_snapshot_test_sh.test_assert_match_snapshot_with_custom_placeholder.snapshot

Lines changed: 0 additions & 1 deletion
This file was deleted.

tests/unit/snapshots/assert_snapshot_test_sh.test_assert_match_snapshot_with_placeholder.snapshot

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)