Julio Biason
3 years ago
7 changed files with 859 additions and 0 deletions
@ -0,0 +1,36 @@
|
||||
{ |
||||
"blurb": "The classical introductory exercise. Just say \"Hello, World!\"", |
||||
"authors": [], |
||||
"contributors": [ |
||||
"adelcambre", |
||||
"bkhl", |
||||
"budmc29", |
||||
"coreygo", |
||||
"glennj", |
||||
"guygastineau", |
||||
"IsaacG", |
||||
"kenden", |
||||
"kotp", |
||||
"kytrinyx", |
||||
"MattLewin", |
||||
"platinumthinker", |
||||
"quartzinquartz", |
||||
"rootulp", |
||||
"sjwarner-bp", |
||||
"Smarticles101", |
||||
"ZapAnton" |
||||
], |
||||
"files": { |
||||
"solution": [ |
||||
"hello_world.sh" |
||||
], |
||||
"test": [ |
||||
"hello_world.bats" |
||||
], |
||||
"example": [ |
||||
".meta/example.sh" |
||||
] |
||||
}, |
||||
"source": "This is an exercise to introduce users to using Exercism", |
||||
"source_url": "http://en.wikipedia.org/wiki/%22Hello,_world!%22_program" |
||||
} |
@ -0,0 +1 @@
|
||||
{"track":"bash","exercise":"hello-world","id":"ce9230366719441f9fb220b66f74b0c4","url":"https://exercism.org/tracks/bash/exercises/hello-world","handle":"JBiason","is_requester":true,"auto_approve":false} |
@ -0,0 +1,85 @@
|
||||
# Help |
||||
|
||||
## Running the tests |
||||
|
||||
Each exercise contains a test file. |
||||
Run the tests using the `bats` program. |
||||
```bash |
||||
bats hello_world.bats |
||||
``` |
||||
|
||||
`bats` will need to be installed. |
||||
See the [Testing on the Bash track](/docs/tracks/bash/tests) page for |
||||
instructions to install `bats` for your system. |
||||
|
||||
## Help for assert functions |
||||
|
||||
The tests use functions from the |
||||
[bats-assert](https://github.com/bats-core/bats-assert) library. |
||||
Help for the various `assert*` functions can be found there. |
||||
|
||||
## Skipped tests |
||||
|
||||
Solving an exercise means making all its tests pass. By default, only one |
||||
test (the first one) is executed when you run the tests. This is |
||||
intentional, as it allows you to focus on just making that one test pass. |
||||
Once it passes, you can enable the next test by commenting out or removing the |
||||
|
||||
[[ $BATS_RUN_SKIPPED == true ]] || skip |
||||
|
||||
annotations prepending other tests. |
||||
|
||||
To run all tests, including the ones with `skip` annotations, you can run: |
||||
```bash |
||||
BATS_RUN_SKIPPED=true bats exercise_name.bats |
||||
``` |
||||
|
||||
## Submitting your solution |
||||
|
||||
You can submit your solution using the `exercism submit hello_world.sh` command. |
||||
This command will upload your solution to the Exercism website and print the solution page's URL. |
||||
|
||||
It's possible to submit an incomplete solution which allows you to: |
||||
|
||||
- See how others have completed the exercise |
||||
- Request help from a mentor |
||||
|
||||
## Need to get help? |
||||
|
||||
If you'd like help solving the exercise, check the following pages: |
||||
|
||||
- The [Bash track's documentation](https://exercism.org/docs/tracks/bash) |
||||
- [Exercism's support channel on gitter](https://gitter.im/exercism/support) |
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) |
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. |
||||
|
||||
Check your code for syntax errors: paste your code into |
||||
[https://shellcheck.net](https://shellcheck.net) (or [install it](https://github.com/koalaman/shellcheck#user-content-installing) on your machine). |
||||
|
||||
Stack Overflow will be your first stop for bash questions. |
||||
|
||||
* start with the [`bash` tag](https://stackoverflow.com/questions/tagged/bash) to search for your specific question: it's probably already been asked |
||||
* under the bash tag on Stackoverflow, the [Learn more...](https://stackoverflow.com/tags/bash/info) link has _tons_ of good information. |
||||
* the "Books and Resources" section is particularly useful. |
||||
* the [`bash` tag](https://unix.stackexchange.com/questions/tagged/bash) on Unix & Linux is also active |
||||
|
||||
## External utilities |
||||
|
||||
`bash` is a language to write "scripts" -- programs that can call |
||||
external tools, such as |
||||
[`sed`](https://www.gnu.org/software/sed/), |
||||
[`awk`](https://www.gnu.org/software/gawk/), |
||||
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html) |
||||
and even programs written in other programming languages, |
||||
like [`Python`](https://www.python.org/). |
||||
This track does not restrict the usage of these utilities, and as long |
||||
as your solution is portable between systems and does not require |
||||
installation of third party applications, feel free to use them to solve |
||||
the exercise. |
||||
|
||||
For an extra challenge, if you would like to have a better understanding of |
||||
the language, try to re-implement the solution in pure bash, without using |
||||
any external tools. There are some types of problems that bash cannot solve, |
||||
such as floating point arithmetic and manipulating dates: for those, you |
||||
must call out to an external tool. |
@ -0,0 +1,83 @@
|
||||
# Hello World |
||||
|
||||
Welcome to Hello World on Exercism's Bash Track. |
||||
If you need help running the tests or submitting your code, check out `HELP.md`. |
||||
|
||||
## Instructions |
||||
|
||||
The classical introductory exercise. Just say "Hello, World!". |
||||
|
||||
["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is |
||||
the traditional first program for beginning programming in a new language |
||||
or environment. |
||||
|
||||
The objectives are simple: |
||||
|
||||
- Write a function that returns the string "Hello, World!". |
||||
- Run the test suite and make sure that it succeeds. |
||||
- Submit your solution and check it at the website. |
||||
|
||||
If everything goes well, you will be ready to fetch your first real exercise. |
||||
|
||||
Unlike many other languages here, bash is a bit of a special snowflake. |
||||
If you are on a Mac or other unix-y platform, you almost definitely |
||||
already have bash. In fact, anything you type into the terminal is |
||||
likely going through bash. |
||||
|
||||
The downside to this is that there isn't much of a development |
||||
ecosystem around bash like there is for other languages, and there are |
||||
multiple versions of bash that can be frustratingly incompatible. Luckily |
||||
we shouldn't hit those differences for these basic examples, and if you |
||||
can get the tests to pass on your machine, we are doing great. |
||||
|
||||
## Installation |
||||
|
||||
As mentioned above, if you are on a unix-like OS (Mac OS X, Linux, Solaris, |
||||
etc), you probably already have bash. |
||||
|
||||
## Testing |
||||
|
||||
As there isn't much of a bash ecosystem, there also isn't really a de |
||||
facto leader in the bash testing area. For these examples we are using |
||||
[bats](https://github.com/bats-core/bats-core). You should be able to |
||||
install it from your favorite package manager, on OS X with homebrew |
||||
this would look something like this: |
||||
|
||||
``` |
||||
$ brew install bats-core |
||||
==> Downloading |
||||
https://github.com/bats-core/bats-core/archive/v1.2.0.tar.gz |
||||
==> Downloading from |
||||
https://codeload.github.com/bats-core/bats-core/tar.gz/v1.2.0 |
||||
######################################################################## |
||||
100.0% |
||||
==> ./install.sh /opt/boxen/homebrew/Cellar/bats/1.2.0 |
||||
🍺 /opt/boxen/homebrew/Cellar/bats/1.2.0: 10 files, 60K, built in 2 |
||||
seconds |
||||
``` |
||||
|
||||
## Source |
||||
|
||||
### Contributed to by |
||||
|
||||
- @adelcambre |
||||
- @bkhl |
||||
- @budmc29 |
||||
- @coreygo |
||||
- @glennj |
||||
- @guygastineau |
||||
- @IsaacG |
||||
- @kenden |
||||
- @kotp |
||||
- @kytrinyx |
||||
- @MattLewin |
||||
- @platinumthinker |
||||
- @quartzinquartz |
||||
- @rootulp |
||||
- @sjwarner-bp |
||||
- @Smarticles101 |
||||
- @ZapAnton |
||||
|
||||
### Based on |
||||
|
||||
This is an exercise to introduce users to using Exercism - http://en.wikipedia.org/wiki/%22Hello,_world!%22_program |
@ -0,0 +1,637 @@
|
||||
# This is the source code for bats-support and bats-assert, concatenated |
||||
# * https://github.com/bats-core/bats-support |
||||
# * https://github.com/bats-core/bats-assert |
||||
# |
||||
# Comments have been removed to save space. See the git repos for full source code. |
||||
|
||||
############################################################ |
||||
# |
||||
# bats-support - Supporting library for Bats test helpers |
||||
# |
||||
# Written in 2016 by Zoltan Tombol <zoltan dot tombol at gmail dot com> |
||||
# |
||||
# To the extent possible under law, the author(s) have dedicated all |
||||
# copyright and related and neighboring rights to this software to the |
||||
# public domain worldwide. This software is distributed without any |
||||
# warranty. |
||||
# |
||||
# You should have received a copy of the CC0 Public Domain Dedication |
||||
# along with this software. If not, see |
||||
# <http://creativecommons.org/publicdomain/zero/1.0/>. |
||||
# |
||||
|
||||
fail() { |
||||
(( $# == 0 )) && batslib_err || batslib_err "$@" |
||||
return 1 |
||||
} |
||||
|
||||
batslib_is_caller() { |
||||
local -i is_mode_direct=1 |
||||
|
||||
# Handle options. |
||||
while (( $# > 0 )); do |
||||
case "$1" in |
||||
-i|--indirect) is_mode_direct=0; shift ;; |
||||
--) shift; break ;; |
||||
*) break ;; |
||||
esac |
||||
done |
||||
|
||||
# Arguments. |
||||
local -r func="$1" |
||||
|
||||
# Check call stack. |
||||
if (( is_mode_direct )); then |
||||
[[ $func == "${FUNCNAME[2]}" ]] && return 0 |
||||
else |
||||
local -i depth |
||||
for (( depth=2; depth<${#FUNCNAME[@]}; ++depth )); do |
||||
[[ $func == "${FUNCNAME[$depth]}" ]] && return 0 |
||||
done |
||||
fi |
||||
|
||||
return 1 |
||||
} |
||||
|
||||
batslib_err() { |
||||
{ if (( $# > 0 )); then |
||||
echo "$@" |
||||
else |
||||
cat - |
||||
fi |
||||
} >&2 |
||||
} |
||||
|
||||
batslib_count_lines() { |
||||
local -i n_lines=0 |
||||
local line |
||||
while IFS='' read -r line || [[ -n $line ]]; do |
||||
(( ++n_lines )) |
||||
done < <(printf '%s' "$1") |
||||
echo "$n_lines" |
||||
} |
||||
|
||||
batslib_is_single_line() { |
||||
for string in "$@"; do |
||||
(( $(batslib_count_lines "$string") > 1 )) && return 1 |
||||
done |
||||
return 0 |
||||
} |
||||
|
||||
batslib_get_max_single_line_key_width() { |
||||
local -i max_len=-1 |
||||
while (( $# != 0 )); do |
||||
local -i key_len="${#1}" |
||||
batslib_is_single_line "$2" && (( key_len > max_len )) && max_len="$key_len" |
||||
shift 2 |
||||
done |
||||
echo "$max_len" |
||||
} |
||||
|
||||
batslib_print_kv_single() { |
||||
local -ir col_width="$1"; shift |
||||
while (( $# != 0 )); do |
||||
printf '%-*s : %s\n' "$col_width" "$1" "$2" |
||||
shift 2 |
||||
done |
||||
} |
||||
|
||||
batslib_print_kv_multi() { |
||||
while (( $# != 0 )); do |
||||
printf '%s (%d lines):\n' "$1" "$( batslib_count_lines "$2" )" |
||||
printf '%s\n' "$2" |
||||
shift 2 |
||||
done |
||||
} |
||||
|
||||
batslib_print_kv_single_or_multi() { |
||||
local -ir width="$1"; shift |
||||
local -a pairs=( "$@" ) |
||||
|
||||
local -a values=() |
||||
local -i i |
||||
for (( i=1; i < ${#pairs[@]}; i+=2 )); do |
||||
values+=( "${pairs[$i]}" ) |
||||
done |
||||
|
||||
if batslib_is_single_line "${values[@]}"; then |
||||
batslib_print_kv_single "$width" "${pairs[@]}" |
||||
else |
||||
local -i i |
||||
for (( i=1; i < ${#pairs[@]}; i+=2 )); do |
||||
pairs[$i]="$( batslib_prefix < <(printf '%s' "${pairs[$i]}") )" |
||||
done |
||||
batslib_print_kv_multi "${pairs[@]}" |
||||
fi |
||||
} |
||||
|
||||
batslib_prefix() { |
||||
local -r prefix="${1:- }" |
||||
local line |
||||
while IFS='' read -r line || [[ -n $line ]]; do |
||||
printf '%s%s\n' "$prefix" "$line" |
||||
done |
||||
} |
||||
|
||||
batslib_mark() { |
||||
local -r symbol="$1"; shift |
||||
# Sort line numbers. |
||||
set -- $( sort -nu <<< "$( printf '%d\n' "$@" )" ) |
||||
|
||||
local line |
||||
local -i idx=0 |
||||
while IFS='' read -r line || [[ -n $line ]]; do |
||||
if (( ${1:--1} == idx )); then |
||||
printf '%s\n' "${symbol}${line:${#symbol}}" |
||||
shift |
||||
else |
||||
printf '%s\n' "$line" |
||||
fi |
||||
(( ++idx )) |
||||
done |
||||
} |
||||
|
||||
batslib_decorate() { |
||||
echo |
||||
echo "-- $1 --" |
||||
cat - |
||||
echo '--' |
||||
echo |
||||
} |
||||
|
||||
############################################################ |
||||
|
||||
assert() { |
||||
if ! "$@"; then |
||||
batslib_print_kv_single 10 'expression' "$*" \ |
||||
| batslib_decorate 'assertion failed' \ |
||||
| fail |
||||
fi |
||||
} |
||||
|
||||
assert_equal() { |
||||
if [[ $1 != "$2" ]]; then |
||||
batslib_print_kv_single_or_multi 8 \ |
||||
'expected' "$2" \ |
||||
'actual' "$1" \ |
||||
| batslib_decorate 'values do not equal' \ |
||||
| fail |
||||
fi |
||||
} |
||||
|
||||
assert_failure() { |
||||
: "${output?}" |
||||
: "${status?}" |
||||
|
||||
(( $# > 0 )) && local -r expected="$1" |
||||
if (( status == 0 )); then |
||||
batslib_print_kv_single_or_multi 6 'output' "$output" \ |
||||
| batslib_decorate 'command succeeded, but it was expected to fail' \ |
||||
| fail |
||||
elif (( $# > 0 )) && (( status != expected )); then |
||||
{ local -ir width=8 |
||||
batslib_print_kv_single "$width" \ |
||||
'expected' "$expected" \ |
||||
'actual' "$status" |
||||
batslib_print_kv_single_or_multi "$width" \ |
||||
'output' "$output" |
||||
} \ |
||||
| batslib_decorate 'command failed as expected, but status differs' \ |
||||
| fail |
||||
fi |
||||
} |
||||
|
||||
assert_line() { |
||||
local -i is_match_line=0 |
||||
local -i is_mode_partial=0 |
||||
local -i is_mode_regexp=0 |
||||
: "${lines?}" |
||||
|
||||
# Handle options. |
||||
while (( $# > 0 )); do |
||||
case "$1" in |
||||
-n|--index) |
||||
if (( $# < 2 )) || ! [[ $2 =~ ^([0-9]|[1-9][0-9]+)$ ]]; then |
||||
echo "\`--index' requires an integer argument: \`$2'" \ |
||||
| batslib_decorate 'ERROR: assert_line' \ |
||||
| fail |
||||
return $? |
||||
fi |
||||
is_match_line=1 |
||||
local -ri idx="$2" |
||||
shift 2 |
||||
;; |
||||
-p|--partial) is_mode_partial=1; shift ;; |
||||
-e|--regexp) is_mode_regexp=1; shift ;; |
||||
--) shift; break ;; |
||||
*) break ;; |
||||
esac |
||||
done |
||||
|
||||
if (( is_mode_partial )) && (( is_mode_regexp )); then |
||||
echo "\`--partial' and \`--regexp' are mutually exclusive" \ |
||||
| batslib_decorate 'ERROR: assert_line' \ |
||||
| fail |
||||
return $? |
||||
fi |
||||
|
||||
# Arguments. |
||||
local -r expected="$1" |
||||
|
||||
if (( is_mode_regexp == 1 )) && [[ '' =~ $expected ]] || (( $? == 2 )); then |
||||
echo "Invalid extended regular expression: \`$expected'" \ |
||||
| batslib_decorate 'ERROR: assert_line' \ |
||||
| fail |
||||
return $? |
||||
fi |
||||
|
||||
# Matching. |
||||
if (( is_match_line )); then |
||||
# Specific line. |
||||
if (( is_mode_regexp )); then |
||||
if ! [[ ${lines[$idx]} =~ $expected ]]; then |
||||
batslib_print_kv_single 6 \ |
||||
'index' "$idx" \ |
||||
'regexp' "$expected" \ |
||||
'line' "${lines[$idx]}" \ |
||||
| batslib_decorate 'regular expression does not match line' \ |
||||
| fail |
||||
fi |
||||
elif (( is_mode_partial )); then |
||||
if [[ ${lines[$idx]} != *"$expected"* ]]; then |
||||
batslib_print_kv_single 9 \ |
||||
'index' "$idx" \ |
||||
'substring' "$expected" \ |
||||
'line' "${lines[$idx]}" \ |
||||
| batslib_decorate 'line does not contain substring' \ |
||||
| fail |
||||
fi |
||||
else |
||||
if [[ ${lines[$idx]} != "$expected" ]]; then |
||||
batslib_print_kv_single 8 \ |
||||
'index' "$idx" \ |
||||
'expected' "$expected" \ |
||||
'actual' "${lines[$idx]}" \ |
||||
| batslib_decorate 'line differs' \ |
||||
| fail |
||||
fi |
||||
fi |
||||
else |
||||
# Contained in output. |
||||
if (( is_mode_regexp )); then |
||||
local -i idx |
||||
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do |
||||
[[ ${lines[$idx]} =~ $expected ]] && return 0 |
||||
done |
||||
{ local -ar single=( 'regexp' "$expected" ) |
||||
local -ar may_be_multi=( 'output' "$output" ) |
||||
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )" |
||||
batslib_print_kv_single "$width" "${single[@]}" |
||||
batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}" |
||||
} \ |
||||
| batslib_decorate 'no output line matches regular expression' \ |
||||
| fail |
||||
elif (( is_mode_partial )); then |
||||
local -i idx |
||||
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do |
||||
[[ ${lines[$idx]} == *"$expected"* ]] && return 0 |
||||
done |
||||
{ local -ar single=( 'substring' "$expected" ) |
||||
local -ar may_be_multi=( 'output' "$output" ) |
||||
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )" |
||||
batslib_print_kv_single "$width" "${single[@]}" |
||||
batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}" |
||||
} \ |
||||
| batslib_decorate 'no output line contains substring' \ |
||||
| fail |
||||
else |
||||
local -i idx |
||||
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do |
||||
[[ ${lines[$idx]} == "$expected" ]] && return 0 |
||||
done |
||||
{ local -ar single=( 'line' "$expected" ) |
||||
local -ar may_be_multi=( 'output' "$output" ) |
||||
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )" |
||||
batslib_print_kv_single "$width" "${single[@]}" |
||||
batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}" |
||||
} \ |
||||
| batslib_decorate 'output does not contain line' \ |
||||
| fail |
||||
fi |
||||
fi |
||||
} |
||||
|
||||
assert_output() { |
||||
local -i is_mode_partial=0 |
||||
local -i is_mode_regexp=0 |
||||
local -i is_mode_nonempty=0 |
||||
local -i use_stdin=0 |
||||
: "${output?}" |
||||
|
||||
# Handle options. |
||||
if (( $# == 0 )); then |
||||
is_mode_nonempty=1 |
||||
fi |
||||
|
||||
while (( $# > 0 )); do |
||||
case "$1" in |
||||
-p|--partial) is_mode_partial=1; shift ;; |
||||
-e|--regexp) is_mode_regexp=1; shift ;; |
||||
-|--stdin) use_stdin=1; shift ;; |
||||
--) shift; break ;; |
||||
*) break ;; |
||||
esac |
||||
done |
||||
|
||||
if (( is_mode_partial )) && (( is_mode_regexp )); then |
||||
echo "\`--partial' and \`--regexp' are mutually exclusive" \ |
||||
| batslib_decorate 'ERROR: assert_output' \ |
||||
| fail |
||||
return $? |
||||
fi |
||||
|
||||
# Arguments. |
||||
local expected |
||||
if (( use_stdin )); then |
||||
expected="$(cat -)" |
||||
else |
||||
expected="${1-}" |
||||
fi |
||||
|
||||
# Matching. |
||||
if (( is_mode_nonempty )); then |
||||
if [ -z "$output" ]; then |
||||
echo 'expected non-empty output, but output was empty' \ |
||||
| batslib_decorate 'no output' \ |
||||
| fail |
||||
fi |
||||
elif (( is_mode_regexp )); then |
||||
if [[ '' =~ $expected ]] || (( $? == 2 )); then |
||||
echo "Invalid extended regular expression: \`$expected'" \ |
||||
| batslib_decorate 'ERROR: assert_output' \ |
||||
| fail |
||||
elif ! [[ $output =~ $expected ]]; then |
||||
batslib_print_kv_single_or_multi 6 \ |
||||
'regexp' "$expected" \ |
||||
'output' "$output" \ |
||||
| batslib_decorate 'regular expression does not match output' \ |
||||
| fail |
||||
fi |
||||
elif (( is_mode_partial )); then |
||||
if [[ $output != *"$expected"* ]]; then |
||||
batslib_print_kv_single_or_multi 9 \ |
||||
'substring' "$expected" \ |
||||
'output' "$output" \ |
||||
| batslib_decorate 'output does not contain substring' \ |
||||
| fail |
||||
fi |
||||
else |
||||
if [[ $output != "$expected" ]]; then |
||||
batslib_print_kv_single_or_multi 8 \ |
||||
'expected' "$expected" \ |
||||
'actual' "$output" \ |
||||
| batslib_decorate 'output differs' \ |
||||
| fail |
||||
fi |
||||
fi |
||||
} |
||||
|
||||
assert_success() { |
||||
: "${output?}" |
||||
: "${status?}" |
||||
|
||||
if (( status != 0 )); then |
||||
{ local -ir width=6 |
||||
batslib_print_kv_single "$width" 'status' "$status" |
||||
batslib_print_kv_single_or_multi "$width" 'output' "$output" |
||||
} \ |
||||
| batslib_decorate 'command failed' \ |
||||
| fail |
||||
fi |
||||
} |
||||
|
||||
refute() { |
||||
if "$@"; then |
||||
batslib_print_kv_single 10 'expression' "$*" \ |
||||
| batslib_decorate 'assertion succeeded, but it was expected to fail' \ |
||||
| fail |
||||
fi |
||||
} |
||||
|
||||
refute_line() { |
||||
local -i is_match_line=0 |
||||
local -i is_mode_partial=0 |
||||
local -i is_mode_regexp=0 |
||||
: "${lines?}" |
||||
|
||||
# Handle options. |
||||
while (( $# > 0 )); do |
||||
case "$1" in |
||||
-n|--index) |
||||
if (( $# < 2 )) || ! [[ $2 =~ ^([0-9]|[1-9][0-9]+)$ ]]; then |
||||
echo "\`--index' requires an integer argument: \`$2'" \ |
||||
| batslib_decorate 'ERROR: refute_line' \ |
||||
| fail |
||||
return $? |
||||
fi |
||||
is_match_line=1 |
||||
local -ri idx="$2" |
||||
shift 2 |
||||
;; |
||||
-p|--partial) is_mode_partial=1; shift ;; |
||||
-e|--regexp) is_mode_regexp=1; shift ;; |
||||
--) shift; break ;; |
||||
*) break ;; |
||||
esac |
||||
done |
||||
|
||||
if (( is_mode_partial )) && (( is_mode_regexp )); then |
||||
echo "\`--partial' and \`--regexp' are mutually exclusive" \ |
||||
| batslib_decorate 'ERROR: refute_line' \ |
||||
| fail |
||||
return $? |
||||
fi |
||||
|
||||
# Arguments. |
||||
local -r unexpected="$1" |
||||
|
||||
if (( is_mode_regexp == 1 )) && [[ '' =~ $unexpected ]] || (( $? == 2 )); then |
||||
echo "Invalid extended regular expression: \`$unexpected'" \ |
||||
| batslib_decorate 'ERROR: refute_line' \ |
||||
| fail |
||||
return $? |
||||
fi |
||||
|
||||
# Matching. |
||||
if (( is_match_line )); then |
||||
# Specific line. |
||||
if (( is_mode_regexp )); then |
||||
if [[ ${lines[$idx]} =~ $unexpected ]]; then |
||||
batslib_print_kv_single 6 \ |
||||
'index' "$idx" \ |
||||
'regexp' "$unexpected" \ |
||||
'line' "${lines[$idx]}" \ |
||||
| batslib_decorate 'regular expression should not match line' \ |
||||
| fail |
||||
fi |
||||
elif (( is_mode_partial )); then |
||||
if [[ ${lines[$idx]} == *"$unexpected"* ]]; then |
||||
batslib_print_kv_single 9 \ |
||||
'index' "$idx" \ |
||||
'substring' "$unexpected" \ |
||||
'line' "${lines[$idx]}" \ |
||||
| batslib_decorate 'line should not contain substring' \ |
||||
| fail |
||||
fi |
||||
else |
||||
if [[ ${lines[$idx]} == "$unexpected" ]]; then |
||||
batslib_print_kv_single 5 \ |
||||
'index' "$idx" \ |
||||
'line' "${lines[$idx]}" \ |
||||
| batslib_decorate 'line should differ' \ |
||||
| fail |
||||
fi |
||||
fi |
||||
else |
||||
# Line contained in output. |
||||
if (( is_mode_regexp )); then |
||||
local -i idx |
||||
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do |
||||
if [[ ${lines[$idx]} =~ $unexpected ]]; then |
||||
{ local -ar single=( 'regexp' "$unexpected" 'index' "$idx" ) |
||||
local -a may_be_multi=( 'output' "$output" ) |
||||
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )" |
||||
batslib_print_kv_single "$width" "${single[@]}" |
||||
if batslib_is_single_line "${may_be_multi[1]}"; then |
||||
batslib_print_kv_single "$width" "${may_be_multi[@]}" |
||||
else |
||||
may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" | batslib_prefix | batslib_mark '>' "$idx" )" |
||||
batslib_print_kv_multi "${may_be_multi[@]}" |
||||
fi |
||||
} \ |
||||
| batslib_decorate 'no line should match the regular expression' \ |
||||
| fail |
||||
return $? |
||||
fi |
||||
done |
||||
elif (( is_mode_partial )); then |
||||
local -i idx |
||||
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do |
||||
if [[ ${lines[$idx]} == *"$unexpected"* ]]; then |
||||
{ local -ar single=( 'substring' "$unexpected" 'index' "$idx" ) |
||||
local -a may_be_multi=( 'output' "$output" ) |
||||
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )" |
||||
batslib_print_kv_single "$width" "${single[@]}" |
||||
if batslib_is_single_line "${may_be_multi[1]}"; then |
||||
batslib_print_kv_single "$width" "${may_be_multi[@]}" |
||||
else |
||||
may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" | batslib_prefix | batslib_mark '>' "$idx" )" |
||||
batslib_print_kv_multi "${may_be_multi[@]}" |
||||
fi |
||||
} \ |
||||
| batslib_decorate 'no line should contain substring' \ |
||||
| fail |
||||
return $? |
||||
fi |
||||
done |
||||
else |
||||
local -i idx |
||||
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do |
||||
if [[ ${lines[$idx]} == "$unexpected" ]]; then |
||||
{ local -ar single=( 'line' "$unexpected" 'index' "$idx" ) |
||||
local -a may_be_multi=( 'output' "$output" ) |
||||
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )" |
||||
batslib_print_kv_single "$width" "${single[@]}" |
||||
if batslib_is_single_line "${may_be_multi[1]}"; then |
||||
batslib_print_kv_single "$width" "${may_be_multi[@]}" |
||||
else |
||||
may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" | batslib_prefix | batslib_mark '>' "$idx" )" |
||||
batslib_print_kv_multi "${may_be_multi[@]}" |
||||
fi |
||||
} \ |
||||
| batslib_decorate 'line should not be in output' \ |
||||
| fail |
||||
return $? |
||||
fi |
||||
done |
||||
fi |
||||
fi |
||||
} |
||||
|
||||
refute_output() { |
||||
local -i is_mode_partial=0 |
||||
local -i is_mode_regexp=0 |
||||
local -i is_mode_empty=0 |
||||
local -i use_stdin=0 |
||||
: "${output?}" |
||||
|
||||
# Handle options. |
||||
if (( $# == 0 )); then |
||||
is_mode_empty=1 |
||||
fi |
||||
|
||||
while (( $# > 0 )); do |
||||
case "$1" in |
||||
-p|--partial) is_mode_partial=1; shift ;; |
||||
-e|--regexp) is_mode_regexp=1; shift ;; |
||||
-|--stdin) use_stdin=1; shift ;; |
||||
--) shift; break ;; |
||||
*) break ;; |
||||
esac |
||||
done |
||||
|
||||
if (( is_mode_partial )) && (( is_mode_regexp )); then |
||||
echo "\`--partial' and \`--regexp' are mutually exclusive" \ |
||||
| batslib_decorate 'ERROR: refute_output' \ |
||||
| fail |
||||
return $? |
||||
fi |
||||
|
||||
# Arguments. |
||||
local unexpected |
||||
if (( use_stdin )); then |
||||
unexpected="$(cat -)" |
||||
else |
||||
unexpected="${1-}" |
||||
fi |
||||
|
||||
if (( is_mode_regexp == 1 )) && [[ '' =~ $unexpected ]] || (( $? == 2 )); then |
||||
echo "Invalid extended regular expression: \`$unexpected'" \ |
||||
| batslib_decorate 'ERROR: refute_output' \ |
||||
| fail |
||||
return $? |
||||
fi |
||||
|
||||
# Matching. |
||||
if (( is_mode_empty )); then |
||||
if [ -n "$output" ]; then |
||||
batslib_print_kv_single_or_multi 6 \ |
||||
'output' "$output" \ |
||||
| batslib_decorate 'output non-empty, but expected no output' \ |
||||
| fail |
||||
fi |
||||
elif (( is_mode_regexp )); then |
||||
if [[ $output =~ $unexpected ]]; then |
||||
batslib_print_kv_single_or_multi 6 \ |
||||
'regexp' "$unexpected" \ |
||||
'output' "$output" \ |
||||
| batslib_decorate 'regular expression should not match output' \ |
||||
| fail |
||||
fi |
||||
elif (( is_mode_partial )); then |
||||
if [[ $output == *"$unexpected"* ]]; then |
||||
batslib_print_kv_single_or_multi 9 \ |
||||
'substring' "$unexpected" \ |
||||
'output' "$output" \ |
||||
| batslib_decorate 'output should not contain substring' \ |
||||
| fail |
||||
fi |
||||
else |
||||
if [[ $output == "$unexpected" ]]; then |
||||
batslib_print_kv_single_or_multi 6 \ |
||||
'output' "$output" \ |
||||
| batslib_decorate 'output equals, but it was expected to differ' \ |
||||
| fail |
||||
fi |
||||
fi |
||||
} |
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bats |
||||
load bats-extra |
||||
|
||||
# local version: 1.1.0.0 |
||||
|
||||
@test "Say Hi!" { |
||||
run bash hello_world.sh |
||||
|
||||
# the program's exit status should be success (0) |
||||
assert_success |
||||
|
||||
# program's output should be the expected text |
||||
assert_output "Hello, World!" |
||||
} |
Loading…
Reference in new issue