Skip to content

Commit 990c47d

Browse files
Merge pull request #44 from rico-chet/refute-equal-regex
Add `refute_regex()`
2 parents 6ad25d9 + baffb32 commit 990c47d

4 files changed

Lines changed: 209 additions & 0 deletions

File tree

README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,50 @@ Note that the `BASH_REMATCH` array is available immediately after the
728728
assertion succeeds but is fragile, i.e. prone to being overwritten as a side
729729
effect of other actions.
730730

731+
### `refute_regex`
732+
733+
This function is similar to `refute_equal` but uses pattern matching instead of
734+
equality, by wrapping `! [[ value =~ pattern ]]`.
735+
736+
Fail if the value (first parameter) matches the pattern (second parameter).
737+
738+
```bash
739+
@test 'refute_regex()' {
740+
refute_regex 'WhatsApp' 'Threema'
741+
}
742+
```
743+
744+
On failure, the value, the pattern and the match are displayed.
745+
746+
```
747+
@test 'refute_regex()' {
748+
refute_regex 'WhatsApp' 'What.'
749+
}
750+
751+
-- value matches regular expression --
752+
value : WhatsApp
753+
pattern : What.
754+
match : Whats
755+
case : sensitive
756+
--
757+
```
758+
759+
If the value or pattern is longer than one line then it is displayed in
760+
*multi-line* format.
761+
762+
An error is displayed if the specified extended regular expression is invalid.
763+
764+
For description of the matching behavior, refer to the documentation of the
765+
`=~` operator in the
766+
[Bash manual]: https://www.gnu.org/software/bash/manual/html_node/Conditional-Constructs.html.
767+
768+
Note that the `BASH_REMATCH` array is available immediately after the assertion
769+
fails but is fragile, i.e. prone to being overwritten as a side effect of other
770+
actions like calling `run`. Thus, it's good practice to avoid using
771+
`BASH_REMATCH` in conjunction with `refute_regex()`. The valuable information
772+
the array contains is the matching part of the value which is printed in the
773+
failing test log, as mentioned above.
774+
731775
<!-- REFERENCES -->
732776

733777
[bats]: https://github.com/bats-core/bats-core

load.bash

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ source "$(dirname "${BASH_SOURCE[0]}")/src/refute_output.bash"
3030
source "$(dirname "${BASH_SOURCE[0]}")/src/assert_line.bash"
3131
source "$(dirname "${BASH_SOURCE[0]}")/src/refute_line.bash"
3232
source "$(dirname "${BASH_SOURCE[0]}")/src/assert_regex.bash"
33+
source "$(dirname "${BASH_SOURCE[0]}")/src/refute_regex.bash"

src/refute_regex.bash

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# `refute_regex`
2+
#
3+
# This function is similar to `refute_equal` but uses pattern matching instead
4+
# of equality, by wrapping `! [[ value =~ pattern ]]`.
5+
#
6+
# Fail if the value (first parameter) matches the pattern (second parameter).
7+
#
8+
# ```bash
9+
# @test 'refute_regex()' {
10+
# refute_regex 'WhatsApp' 'Threema'
11+
# }
12+
# ```
13+
#
14+
# On failure, the value, the pattern and the match are displayed.
15+
#
16+
# ```
17+
# @test 'refute_regex()' {
18+
# refute_regex 'WhatsApp' 'What.'
19+
# }
20+
#
21+
# -- value matches regular expression --
22+
# value : WhatsApp
23+
# pattern : What.
24+
# match : Whats
25+
# case : sensitive
26+
# --
27+
# ```
28+
#
29+
# If the value or pattern is longer than one line then it is displayed in
30+
# *multi-line* format.
31+
#
32+
# An error is displayed if the specified extended regular expression is invalid.
33+
#
34+
# For description of the matching behavior, refer to the documentation of the
35+
# `=~` operator in the
36+
# [Bash manual]: https://www.gnu.org/software/bash/manual/html_node/Conditional-Constructs.html.
37+
#
38+
# Note that the `BASH_REMATCH` array is available immediately after the
39+
# assertion fails but is fragile, i.e. prone to being overwritten as a side
40+
# effect of other actions like calling `run`. Thus, it's good practice to avoid
41+
# using `BASH_REMATCH` in conjunction with `refute_regex()`. The valuable
42+
# information the array contains is the matching part of the value which is
43+
# printed in the failing test log, as mentioned above.
44+
refute_regex() {
45+
local -r value="${1}"
46+
local -r pattern="${2}"
47+
48+
if [[ '' =~ ${pattern} ]] || (( ${?} == 2 )); then
49+
echo "Invalid extended regular expression: \`${pattern}'" \
50+
| batslib_decorate 'ERROR: refute_regex' \
51+
| fail
52+
elif [[ "${value}" =~ ${pattern} ]]; then
53+
if shopt -p nocasematch &>/dev/null; then
54+
local case_sensitive=insensitive
55+
else
56+
local case_sensitive=sensitive
57+
fi
58+
batslib_print_kv_single_or_multi 8 \
59+
'value' "${value}" \
60+
'pattern' "${pattern}" \
61+
'match' "${BASH_REMATCH[0]}" \
62+
'case' "${case_sensitive}" \
63+
| batslib_decorate 'value matches regular expression' \
64+
| fail
65+
fi
66+
}

test/refute_regex.bats

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#!/usr/bin/env bats
2+
3+
load test_helper
4+
5+
#
6+
# Literal matching
7+
#
8+
9+
# Correctness
10+
@test "refute_regex() <value> <pattern>: fails if a <value> substring matches extended regular expression <pattern>" {
11+
run refute_regex 'abc' '^[a-z]b'
12+
assert_test_fail <<'ERR_MSG'
13+
14+
-- value matches regular expression --
15+
value : abc
16+
pattern : ^[a-z]b
17+
match : ab
18+
case : sensitive
19+
--
20+
ERR_MSG
21+
}
22+
23+
@test "refute_regex() <value> <pattern>: succeeds if no <value> substring matches extended regular expression <pattern>" {
24+
run refute_regex 'bcd' '^[a-z]b[c-z]+'
25+
assert_test_pass
26+
}
27+
28+
@test "refute_regex() <value> <pattern>: provides results in BASH_REMATCH on failure" {
29+
unset -v BASH_REMATCH
30+
31+
refute_regex 'abcd' 'b.d' \
32+
|| {
33+
declare -p BASH_REMATCH && \
34+
[ "${BASH_REMATCH[0]}" = 'bcd' ]
35+
}
36+
}
37+
38+
@test "refute_regex() <value> <pattern>: matches case-insensitively when 'nocasematch' is set" {
39+
shopt -s nocasematch
40+
41+
run refute_regex 'aBc' 'ABC'
42+
assert_test_fail <<'ERR_MSG'
43+
44+
-- value matches regular expression --
45+
value : aBc
46+
pattern : ABC
47+
match : aBc
48+
case : insensitive
49+
--
50+
ERR_MSG
51+
}
52+
53+
@test "refute_regex() <value> <pattern>: outputs multi-line <value> nicely when it fails" {
54+
run refute_regex $'abc\n123' '^[a-z]b[c-z]+'
55+
assert_test_fail <<'ERR_MSG'
56+
57+
-- value matches regular expression --
58+
value (2 lines):
59+
abc
60+
123
61+
pattern (1 lines):
62+
^[a-z]b[c-z]+
63+
match (1 lines):
64+
abc
65+
case (1 lines):
66+
sensitive
67+
--
68+
ERR_MSG
69+
70+
shopt -s nocasematch
71+
run refute_regex $'aBc\n123' '^[a-z]b[c-z]+'
72+
assert_test_fail <<'ERR_MSG'
73+
74+
-- value matches regular expression --
75+
value (2 lines):
76+
aBc
77+
123
78+
pattern (1 lines):
79+
^[a-z]b[c-z]+
80+
match (1 lines):
81+
aBc
82+
case (1 lines):
83+
insensitive
84+
--
85+
ERR_MSG
86+
}
87+
88+
# Error handling
89+
@test "refute_regex() <value> <pattern>: returns 1 and displays an error message if <pattern> is not a valid extended regular expression" {
90+
run refute_regex value '[.*'
91+
92+
assert_test_fail <<'ERR_MSG'
93+
94+
-- ERROR: refute_regex --
95+
Invalid extended regular expression: `[.*'
96+
--
97+
ERR_MSG
98+
}

0 commit comments

Comments
 (0)