From be733ea5935fcb719063d9066f68892cbe1424a2 Mon Sep 17 00:00:00 2001 From: Victor Payno Date: Fri, 1 Sep 2023 18:38:18 -0700 Subject: [PATCH 1/6] awk/luhn: download exercise --- awk/luhn/.exercism/config.json | 19 + awk/luhn/.exercism/metadata.json | 1 + awk/luhn/HELP.md | 99 +++++ awk/luhn/README.md | 79 ++++ awk/luhn/bats-extra.bash | 637 +++++++++++++++++++++++++++++++ awk/luhn/luhn.awk | 4 + awk/luhn/test-luhn.bats | 156 ++++++++ 7 files changed, 995 insertions(+) create mode 100644 awk/luhn/.exercism/config.json create mode 100644 awk/luhn/.exercism/metadata.json create mode 100644 awk/luhn/HELP.md create mode 100644 awk/luhn/README.md create mode 100644 awk/luhn/bats-extra.bash create mode 100644 awk/luhn/luhn.awk create mode 100644 awk/luhn/test-luhn.bats diff --git a/awk/luhn/.exercism/config.json b/awk/luhn/.exercism/config.json new file mode 100644 index 00000000..10a7788c --- /dev/null +++ b/awk/luhn/.exercism/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "glennj" + ], + "files": { + "solution": [ + "luhn.awk" + ], + "test": [ + "test-luhn.bats" + ], + "example": [ + ".meta/example.awk" + ] + }, + "blurb": "Given a number determine whether or not it is valid per the Luhn formula.", + "source": "The Luhn Algorithm on Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Luhn_algorithm" +} diff --git a/awk/luhn/.exercism/metadata.json b/awk/luhn/.exercism/metadata.json new file mode 100644 index 00000000..9291a5b9 --- /dev/null +++ b/awk/luhn/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"awk","exercise":"luhn","id":"09b7d064ae9e4eb6a98b19e7e5d7d222","url":"https://exercism.org/tracks/awk/exercises/luhn","handle":"vpayno","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/awk/luhn/HELP.md b/awk/luhn/HELP.md new file mode 100644 index 00000000..a672b11e --- /dev/null +++ b/awk/luhn/HELP.md @@ -0,0 +1,99 @@ +# Help + +## Running the tests + +Each exercise contains a test file. +Run the tests using the `bats` program. +```bash +bats test-hello-world.bats +``` + +`bats` will need to be installed. +See the [Testing on the Bash track][bash] page for instructions to install `bats` for your system. + +### bats is implemented in bash + +The bats file is a bash script, with some special functions recognized by the `bats` command. +You'll see some tests that look like +```sh +gawk -f some-exercise.awk <<< "some,input,here" +``` +That `<<<` syntax is a bash [Here String][here-string]. +It sends the string on the right-hand side into the standard input of the program on the left-hand side. +It is ([approximately][so]) the same as +```sh +echo "some,input,here" | gawk -f some-exercise.awk +``` + +## Help for assert functions + +The tests use functions from the [bats-assert][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. + +## Overriding skips + +To run all tests, including the ones with `skip` annotations, you can run: +```bash +BATS_RUN_SKIPPED=true bats test-some-exercise.bats +``` + +It can be convenient to use a wrapper function to save on typing: in `bash` you can do: +```bash +bats() { + BATS_RUN_SKIPPED=true command bats *.bats +} +``` +Then run tests with just: +```bash +bats +``` + +[bash]: https://exercism.org/docs/tracks/bash/tests +[bats-assert]: https://github.com/bats-core/bats-assert +[here-string]: https://www.gnu.org/software/bash/manual/bash.html#Here-Strings +[so]: https://unix.stackexchange.com/a/80372/4667 + +## Submitting your solution + +You can submit your solution using the `exercism submit luhn.awk` 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 [AWK track's documentation](https://exercism.org/docs/tracks/awk) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Places to look for help for AWK questions: + +* [Stack Overflow `awk` tag][so]. +* check the Resources section of the [Stack Overflow `awk` tag into page][so-info]. +* raise an issue at the [exercism/awk][github] Github repository. +* IRC: `irc://irc.liberachat.net/#awk`, `irc://irc.liberachat.net/#exercism` + * see [Libera.chat][libera] if you're unfamiliar with IRC. + + +[so]: https://stackoverflow.com/tags/awk +[so-info]: https://stackoverflow.com/tags/awk/info +[github]: https://github.com/exercism/awk +[libera]: https://libera.chat \ No newline at end of file diff --git a/awk/luhn/README.md b/awk/luhn/README.md new file mode 100644 index 00000000..d2a226ab --- /dev/null +++ b/awk/luhn/README.md @@ -0,0 +1,79 @@ +# Luhn + +Welcome to Luhn on Exercism's AWK Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Given a number determine whether or not it is valid per the Luhn formula. + +The [Luhn algorithm][luhn] is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers and Canadian Social Insurance Numbers. + +The task is to check if a given string is valid. + +## Validating a Number + +Strings of length 1 or less are not valid. +Spaces are allowed in the input, but they should be stripped before checking. +All other non-digit characters are disallowed. + +### Example 1: valid credit card number + +```text +4539 3195 0343 6467 +``` + +The first step of the Luhn algorithm is to double every second digit, starting from the right. +We will be doubling + +```text +4_3_ 3_9_ 0_4_ 6_6_ +``` + +If doubling the number results in a number greater than 9 then subtract 9 from the product. +The results of our doubling: + +```text +8569 6195 0383 3437 +``` + +Then sum all of the digits: + +```text +8+5+6+9+6+1+9+5+0+3+8+3+3+4+3+7 = 80 +``` + +If the sum is evenly divisible by 10, then the number is valid. +This number is valid! + +### Example 2: invalid credit card number + +```text +8273 1232 7352 0569 +``` + +Double the second digits, starting from the right + +```text +7253 2262 5312 0539 +``` + +Sum the digits + +```text +7+2+5+3+2+2+6+2+5+3+1+2+0+5+3+9 = 57 +``` + +57 is not evenly divisible by 10, so this number is not valid. + +[luhn]: https://en.wikipedia.org/wiki/Luhn_algorithm + +## Source + +### Created by + +- @glennj + +### Based on + +The Luhn Algorithm on Wikipedia - https://en.wikipedia.org/wiki/Luhn_algorithm \ No newline at end of file diff --git a/awk/luhn/bats-extra.bash b/awk/luhn/bats-extra.bash new file mode 100644 index 00000000..54d48070 --- /dev/null +++ b/awk/luhn/bats-extra.bash @@ -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 +# +# 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 +# . +# + +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 +} diff --git a/awk/luhn/luhn.awk b/awk/luhn/luhn.awk new file mode 100644 index 00000000..bca5f438 --- /dev/null +++ b/awk/luhn/luhn.awk @@ -0,0 +1,4 @@ +BEGIN { + print "Implement this solution" > "/dev/stderr" + exit 1 +} diff --git a/awk/luhn/test-luhn.bats b/awk/luhn/test-luhn.bats new file mode 100644 index 00000000..ff360686 --- /dev/null +++ b/awk/luhn/test-luhn.bats @@ -0,0 +1,156 @@ +#!/usr/bin/env bats +load bats-extra + +@test "single digit strings can not be valid" { + #[[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "1" + assert_success + assert_output "false" +} + +@test "a single zero is invalid" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "0" + assert_success + assert_output "false" +} + +@test "a simple valid SIN that remains valid if reversed" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "059" + assert_success + assert_output "true" +} + +@test "a simple valid SIN that becomes invalid if reversed" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "59" + assert_success + assert_output "true" +} + +@test "a valid Canadian SIN" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "055 444 285" + assert_success + assert_output "true" +} + +@test "invalid Canadian SIN" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "055 444 286" + assert_success + assert_output "false" +} + +@test "invalid credit card" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "8273 1232 7352 0569" + assert_success + assert_output "false" +} + +@test "invalid long number with an even remainder" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "1 2345 6789 1234 5678 9012" + assert_success + assert_output "false" +} + +@test "invalid long number with a remainder divisible by 5" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "1 2345 6789 1234 5678 9013" + assert_success + assert_output "false" +} + +@test "valid number with an even number of digits" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "095 245 88" + assert_success + assert_output "true" +} + +@test "valid number with an odd number of spaces" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "234 567 891 234" + assert_success + assert_output "true" +} + +@test "valid strings with a non-digit included become invalid" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "055a 444 285" + assert_success + assert_output "false" +} + +@test "valid strings with punctuation included become invalid" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "055-444-285" + assert_success + assert_output "false" +} + +@test "valid strings with symbols included become invalid" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "055£ 444$ 285" + assert_success + assert_output "false" +} + +@test "single zero with space is invalid" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< " 0" + assert_success + assert_output "false" +} + +@test "more than a single zero is valid" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "0000 0" + assert_success + assert_output "true" +} + +@test "input digit 9 is correctly converted to output digit 9" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "091" + assert_success + assert_output "true" +} + +@test "very long input is valid" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "9999999999 9999999999 9999999999 9999999999" + assert_success + assert_output "true" +} + +@test "valid luhn with an odd number of digits and non zero first digit" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "109" + assert_success + assert_output "true" +} + +@test "using ascii value for non-doubled non-digit isn't allowed" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "055b 444 285" + assert_success + assert_output "false" +} + +@test "using ascii value for doubled non-digit isn't allowed" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< ":9" + assert_success + assert_output "false" +} + +@test "non-numeric, non-space char in the middle with a sum that's divisible by 10 isn't allowed" { + [[ $BATS_RUN_SKIPPED == "true" ]] || skip + run gawk -f luhn.awk <<< "59%59" + assert_success + assert_output "false" +} From 442f59b0d03921014e7aa4a3485ea0ac55e2d27a Mon Sep 17 00:00:00 2001 From: Victor Payno Date: Fri, 1 Sep 2023 22:41:23 -0700 Subject: [PATCH 2/6] awk/luhn: 1st iteration --- README.md | 2 +- awk/README.md | 1 + awk/luhn/README.md | 9 +- awk/luhn/awkunit.awk | 1 + awk/luhn/luhn.awk | 77 +++++++++++- awk/luhn/luhn_test.awk | 125 ++++++++++++++++++++ awk/luhn/run-tests-awk.txt | 236 +++++++++++++++++++++++++++++++++++++ awk/luhn/test-cases.awk | 34 ++++++ 8 files changed, 481 insertions(+), 4 deletions(-) create mode 120000 awk/luhn/awkunit.awk create mode 100644 awk/luhn/luhn_test.awk create mode 100644 awk/luhn/run-tests-awk.txt create mode 100644 awk/luhn/test-cases.awk diff --git a/README.md b/README.md index 3f1408b3..ba0412ac 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Exercism Workspace | June | Summer-of-Sexps | Common-Lisp (5/5) | | July | Jurassic | C (5/5), C++ (5/5), Fortran (0/5) | | August | Apps | Dart (5/5), Java (0/5), Kotlin (0/5) | -| September | Slimline | Awk (2/5), Bash\* (5/5), jq (0/5), Perl (0/5) | +| September | Slimline | Awk (3/5), Bash\* (5/5), jq (0/5), Perl (0/5) | | October | Object-Oriented | | | November | Nibbly | | | December | Diversions | | diff --git a/awk/README.md b/awk/README.md index f6cf53a9..dcc315d9 100644 --- a/awk/README.md +++ b/awk/README.md @@ -19,3 +19,4 @@ - [reverse-string](./reverse-string/README.md) - [gigasecond](./gigasecond/README.md) - [darts](./darts/README.md) +- [luhn](./luhn/README.md) diff --git a/awk/luhn/README.md b/awk/luhn/README.md index d2a226ab..7f26fff7 100644 --- a/awk/luhn/README.md +++ b/awk/luhn/README.md @@ -76,4 +76,11 @@ Sum the digits ### Based on -The Luhn Algorithm on Wikipedia - https://en.wikipedia.org/wiki/Luhn_algorithm \ No newline at end of file +The Luhn Algorithm on Wikipedia - https://en.wikipedia.org/wiki/Luhn_algorithm + +### My Solution + +- [my solution](./luhn.awk) +- [awkunit tests](./luhn_test.awk) +- [test cases](./test-cases.awk) +- [run-tests](./run-tests-awk.txt) diff --git a/awk/luhn/awkunit.awk b/awk/luhn/awkunit.awk new file mode 120000 index 00000000..38a08adf --- /dev/null +++ b/awk/luhn/awkunit.awk @@ -0,0 +1 @@ +../.lib/awkunit.awk \ No newline at end of file diff --git a/awk/luhn/luhn.awk b/awk/luhn/luhn.awk index bca5f438..3fc2e4d6 100644 --- a/awk/luhn/luhn.awk +++ b/awk/luhn/luhn.awk @@ -1,4 +1,77 @@ +#!/usr/bin/gawk --lint --file + +function reverse_string(forward) { + reversed = "" + + split(forward, chars, "") + + for (i = 1; i <= length(chars); i++) { + reversed = chars[i] reversed + } + + return reversed +} + +function is_valid(input) { + if (length(input) <= 1) { + return "false" + } + + if (match(input, /^[ 0-9]+$/)) { + return "true" + } + + return "false" +} + +function luhn(input) { + if(is_valid(input) == "false") { + return "false" + } + + _ = gsub(/ /, "", input) + + if (input == 0 && length(input) == 1) { + return "false" + } + + _ = split(reverse_string(input), numbers, "") + + for (i = 1; i <= length(input); i++) { + digit = numbers[i] + + if(i % 2 != 0) { + continue + } + + new_digit = digit * 2 + + if(new_digit > 9) { + new_digit -= 9 + } + + numbers[i] = new_digit + } + + sum = 0 + for (i = 1; i <= length(input); i++) { + digit = numbers[i] + sum += digit + } + + if (sum % 10 == 0) { + return "true" + } + + return "false" +} + BEGIN { - print "Implement this solution" > "/dev/stderr" - exit 1 +} + +{ + print luhn($0) +} + +END { } diff --git a/awk/luhn/luhn_test.awk b/awk/luhn/luhn_test.awk new file mode 100644 index 00000000..721898fb --- /dev/null +++ b/awk/luhn/luhn_test.awk @@ -0,0 +1,125 @@ +#!/usr/bin/gawk --lint --file + +@include "awkunit" +@include "test-cases" +@include "luhn" + +passed = 0 +testCount = 0 + +function _debugTestPre() { + printf "Test %s:\n", (passed + 1) + printf " input -> [%s]\n", input +} + +function _debugTestPost() { + passed = passed + 1 + printf " output -> [%s]\n", got + printf " result -> passed\n\n" +} + +function test_reverse_string() { + input = "0123456789" + want = "9876543210" + + _debugTestPre() + got = reverse_string(input) + + assertEquals(got, want) + _debugTestPost() +} + +function test_is_valid_empty() { + input = "" + want = "false" + + _debugTestPre() + got = is_valid(input) + + assertEquals(got, want) + _debugTestPost() +} + +function test_is_valid_valid() { + input = "123 456" + want = "true" + + _debugTestPre() + got = is_valid(input) + + assertEquals(got, want) + _debugTestPost() +} + +function test_is_valid_not_valid() { + input = "abc 456" + want = "false" + + _debugTestPre() + got = is_valid(input) + + assertEquals(got, want) + _debugTestPost() +} + +function testLuhn_empty() { + input = "" + want = "false" + + # _ = split(input, a, " ") + + _debugTestPre() + got = luhn(input) + + assertEquals(got, want) + _debugTestPost() +} + +function casesLuhn() { + printf "Running %d test cases\n\n", length(cases) + caseNum = 0 + + # Associative arrays don't preserve insert order. + for (key in cases) { + input = key + want = cases[key] + + # _ = split(input, a, " ") + + _debugTestPre() + got = luhn(input) + + assertEquals(got, want) + _debugTestPost() + } +} + +BEGIN { + exit 0 +} + +END { + cmd = "grep --no-filename --count ^function\\ test *_test.awk" + cmd | getline testCount + + printf "\nRunning %d tests...\n\n", testCount + + testCount = testCount + length(cases) + + test_reverse_string() + + test_is_valid_empty() + test_is_valid_valid() + test_is_valid_not_valid() + + # running tests with a lot of duplication + testLuhn_empty() + + # running tests with reduced duplication + casesLuhn() + + print "\n" passed " out of " testCount " tests passed!" + + # add exit here to keep it from looping + exit 0 +} diff --git a/awk/luhn/run-tests-awk.txt b/awk/luhn/run-tests-awk.txt new file mode 100644 index 00000000..25f6e720 --- /dev/null +++ b/awk/luhn/run-tests-awk.txt @@ -0,0 +1,236 @@ +Running automated test file(s): + + +=============================================================================== + +AWKLIBPATH=../.lib + +awkunit.awk +awkunit.so + +gawk --lint --file=./awkunit.awk < /dev/null > /dev/null +gawk: ./awkunit.awk:3: warning: `load' is a gawk extension +gawk: warning: function `assertEquals' defined but never called directly +gawk: warning: function `assert' defined but never called directly +gawk: ./awkunit.awk:26: warning: reference to uninitialized variable `_assert_exit' + +real 0m0.005s +user 0m0.004s +sys 0m0.001s + +gawk --lint --file=./luhn.awk < /dev/null > /dev/null + +real 0m0.004s +user 0m0.001s +sys 0m0.003s + +gawk --lint --file=./test-cases.awk < /dev/null > /dev/null + +real 0m0.003s +user 0m0.001s +sys 0m0.002s + +exit 0 + +=============================================================================== + +Running: bats ./test-luhn.bats +1..22 +ok 1 single digit strings can not be valid +ok 2 a single zero is invalid # skip +ok 3 a simple valid SIN that remains valid if reversed # skip +ok 4 a simple valid SIN that becomes invalid if reversed # skip +ok 5 a valid Canadian SIN # skip +ok 6 invalid Canadian SIN # skip +ok 7 invalid credit card # skip +ok 8 invalid long number with an even remainder # skip +ok 9 invalid long number with a remainder divisible by 5 # skip +ok 10 valid number with an even number of digits # skip +ok 11 valid number with an odd number of spaces # skip +ok 12 valid strings with a non-digit included become invalid # skip +ok 13 valid strings with punctuation included become invalid # skip +ok 14 valid strings with symbols included become invalid # skip +ok 15 single zero with space is invalid # skip +ok 16 more than a single zero is valid # skip +ok 17 input digit 9 is correctly converted to output digit 9 # skip +ok 18 very long input is valid # skip +ok 19 valid luhn with an odd number of digits and non zero first digit # skip +ok 20 using ascii value for non-doubled non-digit isn't allowed # skip +ok 21 using ascii value for doubled non-digit isn't allowed # skip +ok 22 non-numeric, non-space char in the middle with a sum that's divisible by 10 isn't allowed # skip + +real 0m0.709s +user 0m0.431s +sys 0m0.303s + +exit 0 + +=============================================================================== + +AWKLIBPATH=../.lib + +awkunit.awk +awkunit.so + +Running: gawk --file ./luhn_test.awk && printf \n%s\n Tests Passed! || printf \n%s\n Tests Failed! + +Running 5 tests... + +Test 1: + input -> [0123456789] + output -> [9876543210] + result -> passed + +Test 2: + input -> [] + output -> [false] + result -> passed + +Test 3: + input -> [123 456] + output -> [true] + result -> passed + +Test 4: + input -> [abc 456] + output -> [false] + result -> passed + +Test 5: + input -> [] + output -> [false] + result -> passed + +Running 22 test cases + +Test 6: + input -> [1 2345 6789 1234 5678 9012] + output -> [false] + result -> passed + +Test 7: + input -> [1 2345 6789 1234 5678 9013] + output -> [false] + result -> passed + +Test 8: + input -> [ 0] + output -> [false] + result -> passed + +Test 9: + input -> [59%59] + output -> [false] + result -> passed + +Test 10: + input -> [055 444 285] + output -> [true] + result -> passed + +Test 11: + input -> [055£ 444$ 285] + output -> [false] + result -> passed + +Test 12: + input -> [0000 0] + output -> [true] + result -> passed + +Test 13: + input -> [095 245 88] + output -> [true] + result -> passed + +Test 14: + input -> [055 444 286] + output -> [false] + result -> passed + +Test 15: + input -> [091] + output -> [true] + result -> passed + +Test 16: + input -> [234 567 891 234] + output -> [true] + result -> passed + +Test 17: + input -> [055-444-285] + output -> [false] + result -> passed + +Test 18: + input -> [:9] + output -> [false] + result -> passed + +Test 19: + input -> [055b 444 285] + output -> [false] + result -> passed + +Test 20: + input -> [8273 1232 7352 0569] + output -> [false] + result -> passed + +Test 21: + input -> [9999999999 9999999999 9999999999 9999999999] + output -> [true] + result -> passed + +Test 22: + input -> [059] + output -> [true] + result -> passed + +Test 23: + input -> [055a 444 285] + output -> [false] + result -> passed + +Test 24: + input -> [0] + output -> [false] + result -> passed + +Test 25: + input -> [1] + output -> [false] + result -> passed + +Test 26: + input -> [59] + output -> [true] + result -> passed + +Test 27: + input -> [109] + output -> [true] + result -> passed + + +27 out of 27 tests passed! + +real 0m0.009s +user 0m0.005s +sys 0m0.004s + +Tests Passed! + +exit 0 + +=============================================================================== + +Running: misspell . + +real 0m0.034s +user 0m0.034s +sys 0m0.016s + +=============================================================================== + diff --git a/awk/luhn/test-cases.awk b/awk/luhn/test-cases.awk new file mode 100644 index 00000000..a7f615e2 --- /dev/null +++ b/awk/luhn/test-cases.awk @@ -0,0 +1,34 @@ +#!/usr/bin/gawk --lint --file +# test-cases.awk + +# key: input +# value: output + +BEGIN { + cases["1"]="false" + cases["0"]="false" + cases["055 444 286"]="false" + cases["8273 1232 7352 0569"]="false" + cases["1 2345 6789 1234 5678 9012"]="false" + cases["1 2345 6789 1234 5678 9013"]="false" + cases["055a 444 285"]="false" + cases["055-444-285"]="false" + cases["055£ 444$ 285"]="false" + cases[" 0"]="false" + cases["055b 444 285"]="false" + cases[":9"]="false" + cases["59%59"]="false" + + cases["059"]="true" + cases["59"]="true" + cases["055 444 285"]="true" + cases["095 245 88"]="true" + cases["234 567 891 234"]="true" + cases["0000 0"]="true" + cases["091"]="true" + cases["9999999999 9999999999 9999999999 9999999999"]="true" + cases["109"]="true" + + # add exit here to keep it from waiting for input + exit 0 +} From abfada87c88cdfec4715132cd829ef28d18158d5 Mon Sep 17 00:00:00 2001 From: Victor Payno Date: Fri, 1 Sep 2023 22:47:49 -0700 Subject: [PATCH 3/6] awk/luhn: 2nd iteration --- awk/luhn/luhn.awk | 9 ++--- awk/luhn/run-tests-awk.txt | 74 +++++++++++++++++++------------------- 2 files changed, 40 insertions(+), 43 deletions(-) diff --git a/awk/luhn/luhn.awk b/awk/luhn/luhn.awk index 3fc2e4d6..718f2f76 100644 --- a/awk/luhn/luhn.awk +++ b/awk/luhn/luhn.awk @@ -37,10 +37,12 @@ function luhn(input) { _ = split(reverse_string(input), numbers, "") + sum = 0 for (i = 1; i <= length(input); i++) { digit = numbers[i] if(i % 2 != 0) { + sum += digit continue } @@ -51,12 +53,7 @@ function luhn(input) { } numbers[i] = new_digit - } - - sum = 0 - for (i = 1; i <= length(input); i++) { - digit = numbers[i] - sum += digit + sum += new_digit } if (sum % 10 == 0) { diff --git a/awk/luhn/run-tests-awk.txt b/awk/luhn/run-tests-awk.txt index 25f6e720..2edeaf0a 100644 --- a/awk/luhn/run-tests-awk.txt +++ b/awk/luhn/run-tests-awk.txt @@ -14,21 +14,21 @@ gawk: warning: function `assertEquals' defined but never called directly gawk: warning: function `assert' defined but never called directly gawk: ./awkunit.awk:26: warning: reference to uninitialized variable `_assert_exit' -real 0m0.005s -user 0m0.004s -sys 0m0.001s +real 0m0.003s +user 0m0.000s +sys 0m0.003s gawk --lint --file=./luhn.awk < /dev/null > /dev/null real 0m0.004s -user 0m0.001s -sys 0m0.003s +user 0m0.002s +sys 0m0.002s gawk --lint --file=./test-cases.awk < /dev/null > /dev/null real 0m0.003s -user 0m0.001s -sys 0m0.002s +user 0m0.002s +sys 0m0.001s exit 0 @@ -37,31 +37,31 @@ exit 0 Running: bats ./test-luhn.bats 1..22 ok 1 single digit strings can not be valid -ok 2 a single zero is invalid # skip -ok 3 a simple valid SIN that remains valid if reversed # skip -ok 4 a simple valid SIN that becomes invalid if reversed # skip -ok 5 a valid Canadian SIN # skip -ok 6 invalid Canadian SIN # skip -ok 7 invalid credit card # skip -ok 8 invalid long number with an even remainder # skip -ok 9 invalid long number with a remainder divisible by 5 # skip -ok 10 valid number with an even number of digits # skip -ok 11 valid number with an odd number of spaces # skip -ok 12 valid strings with a non-digit included become invalid # skip -ok 13 valid strings with punctuation included become invalid # skip -ok 14 valid strings with symbols included become invalid # skip -ok 15 single zero with space is invalid # skip -ok 16 more than a single zero is valid # skip -ok 17 input digit 9 is correctly converted to output digit 9 # skip -ok 18 very long input is valid # skip -ok 19 valid luhn with an odd number of digits and non zero first digit # skip -ok 20 using ascii value for non-doubled non-digit isn't allowed # skip -ok 21 using ascii value for doubled non-digit isn't allowed # skip -ok 22 non-numeric, non-space char in the middle with a sum that's divisible by 10 isn't allowed # skip - -real 0m0.709s -user 0m0.431s -sys 0m0.303s +ok 2 a single zero is invalid +ok 3 a simple valid SIN that remains valid if reversed +ok 4 a simple valid SIN that becomes invalid if reversed +ok 5 a valid Canadian SIN +ok 6 invalid Canadian SIN +ok 7 invalid credit card +ok 8 invalid long number with an even remainder +ok 9 invalid long number with a remainder divisible by 5 +ok 10 valid number with an even number of digits +ok 11 valid number with an odd number of spaces +ok 12 valid strings with a non-digit included become invalid +ok 13 valid strings with punctuation included become invalid +ok 14 valid strings with symbols included become invalid +ok 15 single zero with space is invalid +ok 16 more than a single zero is valid +ok 17 input digit 9 is correctly converted to output digit 9 +ok 18 very long input is valid +ok 19 valid luhn with an odd number of digits and non zero first digit +ok 20 using ascii value for non-doubled non-digit isn't allowed +ok 21 using ascii value for doubled non-digit isn't allowed +ok 22 non-numeric, non-space char in the middle with a sum that's divisible by 10 isn't allowed + +real 0m0.808s +user 0m0.540s +sys 0m0.297s exit 0 @@ -216,8 +216,8 @@ Test 27: 27 out of 27 tests passed! -real 0m0.009s -user 0m0.005s +real 0m0.006s +user 0m0.003s sys 0m0.004s Tests Passed! @@ -228,9 +228,9 @@ exit 0 Running: misspell . -real 0m0.034s -user 0m0.034s -sys 0m0.016s +real 0m0.028s +user 0m0.032s +sys 0m0.013s =============================================================================== From 0c0a57c75fb818046ccfaab75d3e5828ab4b03dc Mon Sep 17 00:00:00 2001 From: Victor Payno Date: Fri, 1 Sep 2023 22:50:58 -0700 Subject: [PATCH 4/6] ci(awk): don't skip bats tests --- .github/citools/awk/awk-bats | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/citools/awk/awk-bats b/.github/citools/awk/awk-bats index 58894017..9a7fc970 100755 --- a/.github/citools/awk/awk-bats +++ b/.github/citools/awk/awk-bats @@ -2,6 +2,8 @@ declare -i retval=0 +export BATS_RUN_SKIPPED=true + for tf in ./*.bats; do echo Running: bats "${tf}" time bats "${tf}" || ((retval++)) From e52e13687b4d23264b6286dd5b20fde3d55e6e07 Mon Sep 17 00:00:00 2001 From: Victor Payno Date: Fri, 1 Sep 2023 22:53:03 -0700 Subject: [PATCH 5/6] awk: update run-tests output after enabling all bats tests --- awk/darts/run-tests-awk.txt | 54 ++++++++++++++-------------- awk/gigasecond/run-tests-awk.txt | 36 +++++++++---------- awk/hello-world/run-tests-awk.txt | 30 ++++++++-------- awk/reverse-string/run-tests-awk.txt | 40 ++++++++++----------- awk/two-fer/run-tests-awk.txt | 32 ++++++++--------- 5 files changed, 96 insertions(+), 96 deletions(-) diff --git a/awk/darts/run-tests-awk.txt b/awk/darts/run-tests-awk.txt index 4b32616a..5b410bfc 100644 --- a/awk/darts/run-tests-awk.txt +++ b/awk/darts/run-tests-awk.txt @@ -14,9 +14,9 @@ gawk: warning: function `assertEquals' defined but never called directly gawk: warning: function `assert' defined but never called directly gawk: ./awkunit.awk:26: warning: reference to uninitialized variable `_assert_exit' -real 0m0.003s -user 0m0.003s -sys 0m0.000s +real 0m0.006s +user 0m0.002s +sys 0m0.004s gawk --lint --file=./darts.awk < /dev/null > /dev/null @@ -27,8 +27,8 @@ sys 0m0.001s gawk --lint --file=./test-cases.awk < /dev/null > /dev/null real 0m0.004s -user 0m0.001s -sys 0m0.003s +user 0m0.003s +sys 0m0.001s exit 0 @@ -37,22 +37,22 @@ exit 0 Running: bats ./test-darts.bats 1..13 ok 1 Missed target -ok 2 On the outer circle # skip -ok 3 On the middle circle # skip -ok 4 On the inner circle # skip -ok 5 Exactly on centre # skip -ok 6 Near the centre # skip -ok 7 Just within the inner circle # skip -ok 8 Just outside the inner circle # skip -ok 9 Just within the middle circle # skip -ok 10 Just outside the middle circle # skip -ok 11 Just within the outer circle # skip -ok 12 Just outside the outer circle # skip -ok 13 Asymmetric position between the inner and middle circles # skip - -real 0m0.448s -user 0m0.270s -sys 0m0.202s +ok 2 On the outer circle +ok 3 On the middle circle +ok 4 On the inner circle +ok 5 Exactly on centre +ok 6 Near the centre +ok 7 Just within the inner circle +ok 8 Just outside the inner circle +ok 9 Just within the middle circle +ok 10 Just outside the middle circle +ok 11 Just within the outer circle +ok 12 Just outside the outer circle +ok 13 Asymmetric position between the inner and middle circles + +real 0m0.546s +user 0m0.361s +sys 0m0.213s exit 0 @@ -162,9 +162,9 @@ Test 18: 18 out of 18 tests passed! -real 0m0.008s -user 0m0.002s -sys 0m0.006s +real 0m0.007s +user 0m0.005s +sys 0m0.003s Tests Passed! @@ -174,9 +174,9 @@ exit 0 Running: misspell . -real 0m0.039s -user 0m0.045s -sys 0m0.014s +real 0m0.028s +user 0m0.026s +sys 0m0.017s =============================================================================== diff --git a/awk/gigasecond/run-tests-awk.txt b/awk/gigasecond/run-tests-awk.txt index 07e4a84a..939f9f87 100644 --- a/awk/gigasecond/run-tests-awk.txt +++ b/awk/gigasecond/run-tests-awk.txt @@ -14,23 +14,23 @@ gawk: warning: function `assertEquals' defined but never called directly gawk: warning: function `assert' defined but never called directly gawk: ./awkunit.awk:26: warning: reference to uninitialized variable `_assert_exit' -real 0m0.003s -user 0m0.002s -sys 0m0.001s +real 0m0.004s +user 0m0.000s +sys 0m0.003s gawk --lint --file=./gigasecond.awk < /dev/null > /dev/null gawk: ./gigasecond.awk:21: warning: `mktime' is a gawk extension gawk: ./gigasecond.awk:25: warning: `strftime' is a gawk extension -real 0m0.004s +real 0m0.005s user 0m0.001s sys 0m0.003s gawk --lint --file=./test-cases.awk < /dev/null > /dev/null real 0m0.003s -user 0m0.003s -sys 0m0.000s +user 0m0.001s +sys 0m0.002s exit 0 @@ -39,14 +39,14 @@ exit 0 Running: bats ./test-gigasecond.bats 1..5 ok 1 date only specificaion of time -ok 2 second test for date only specification of time # skip -ok 3 third test for date only specification of time # skip -ok 4 full time specified # skip -ok 5 full time with day roll-over # skip +ok 2 second test for date only specification of time +ok 3 third test for date only specification of time +ok 4 full time specified +ok 5 full time with day roll-over -real 0m0.226s -user 0m0.136s -sys 0m0.108s +real 0m0.216s +user 0m0.145s +sys 0m0.086s exit 0 @@ -101,9 +101,9 @@ Test 7: 7 out of 7 tests passed! -real 0m0.003s +real 0m0.008s user 0m0.002s -sys 0m0.002s +sys 0m0.006s Tests Passed! @@ -113,9 +113,9 @@ exit 0 Running: misspell . -real 0m0.025s -user 0m0.030s -sys 0m0.010s +real 0m0.036s +user 0m0.042s +sys 0m0.013s =============================================================================== diff --git a/awk/hello-world/run-tests-awk.txt b/awk/hello-world/run-tests-awk.txt index ab335c5b..43e328f3 100644 --- a/awk/hello-world/run-tests-awk.txt +++ b/awk/hello-world/run-tests-awk.txt @@ -14,22 +14,22 @@ gawk: warning: function `assertEquals' defined but never called directly gawk: warning: function `assert' defined but never called directly gawk: ./awkunit.awk:26: warning: reference to uninitialized variable `_assert_exit' -real 0m0.002s -user 0m0.001s -sys 0m0.001s +real 0m0.003s +user 0m0.002s +sys 0m0.000s gawk --lint --file=./hello-world.awk < /dev/null > /dev/null real 0m0.002s -user 0m0.001s -sys 0m0.001s +user 0m0.002s +sys 0m0.000s gawk --lint --file=./test-cases.awk < /dev/null > /dev/null gawk: ./test-cases.awk:10: warning: subscript of array `cases' is null string real 0m0.002s -user 0m0.000s -sys 0m0.002s +user 0m0.001s +sys 0m0.001s exit 0 @@ -39,9 +39,9 @@ Running: bats ./test-hello-world.bats 1..1 ok 1 Say Hi! -real 0m0.084s -user 0m0.050s -sys 0m0.049s +real 0m0.112s +user 0m0.071s +sys 0m0.059s exit 0 @@ -67,8 +67,8 @@ Test 1: 1 out of 2 tests passed! real 0m0.005s -user 0m0.002s -sys 0m0.003s +user 0m0.003s +sys 0m0.002s Tests Passed! @@ -78,9 +78,9 @@ exit 0 Running: misspell . -real 0m0.035s -user 0m0.036s -sys 0m0.013s +real 0m0.025s +user 0m0.027s +sys 0m0.011s =============================================================================== diff --git a/awk/reverse-string/run-tests-awk.txt b/awk/reverse-string/run-tests-awk.txt index 0058d0ca..7e808582 100644 --- a/awk/reverse-string/run-tests-awk.txt +++ b/awk/reverse-string/run-tests-awk.txt @@ -15,21 +15,21 @@ gawk: warning: function `assert' defined but never called directly gawk: ./awkunit.awk:26: warning: reference to uninitialized variable `_assert_exit' real 0m0.004s -user 0m0.002s -sys 0m0.001s +user 0m0.001s +sys 0m0.003s gawk --lint --file=./reverse-string.awk < /dev/null > /dev/null -real 0m0.003s +real 0m0.002s user 0m0.000s -sys 0m0.003s +sys 0m0.002s gawk --lint --file=./test-cases.awk < /dev/null > /dev/null gawk: ./test-cases.awk:8: warning: subscript of array `cases' is null string -real 0m0.004s +real 0m0.003s user 0m0.001s -sys 0m0.002s +sys 0m0.001s exit 0 @@ -38,15 +38,15 @@ exit 0 Running: bats ./test-reverse-string.bats 1..6 ok 1 an empty string -ok 2 a word # skip -ok 3 a capitalised word # skip -ok 4 a sentence with punctuation # skip -ok 5 a palindrome # skip -ok 6 an even-sized word # skip +ok 2 a word +ok 3 a capitalised word +ok 4 a sentence with punctuation +ok 5 a palindrome +ok 6 an even-sized word -real 0m0.267s -user 0m0.153s -sys 0m0.141s +real 0m0.269s +user 0m0.177s +sys 0m0.112s exit 0 @@ -111,9 +111,9 @@ Test 9: 9 out of 9 tests passed! -real 0m0.006s -user 0m0.003s -sys 0m0.003s +real 0m0.004s +user 0m0.004s +sys 0m0.001s Tests Passed! @@ -123,9 +123,9 @@ exit 0 Running: misspell . -real 0m0.035s -user 0m0.040s -sys 0m0.014s +real 0m0.029s +user 0m0.033s +sys 0m0.011s =============================================================================== diff --git a/awk/two-fer/run-tests-awk.txt b/awk/two-fer/run-tests-awk.txt index 81d723b2..b4b87f57 100644 --- a/awk/two-fer/run-tests-awk.txt +++ b/awk/two-fer/run-tests-awk.txt @@ -14,9 +14,9 @@ gawk: warning: function `assertEquals' defined but never called directly gawk: warning: function `assert' defined but never called directly gawk: ./awkunit.awk:26: warning: reference to uninitialized variable `_assert_exit' -real 0m0.003s -user 0m0.001s -sys 0m0.001s +real 0m0.002s +user 0m0.002s +sys 0m0.000s gawk --lint --file=./test-cases.awk < /dev/null > /dev/null gawk: ./test-cases.awk:8: warning: subscript of array `cases' is null string @@ -28,8 +28,8 @@ sys 0m0.001s gawk --lint --file=./two-fer.awk < /dev/null > /dev/null gawk: ./two-fer.awk:16: warning: reference to uninitialized field `$0' -real 0m0.001s -user 0m0.001s +real 0m0.002s +user 0m0.002s sys 0m0.000s exit 0 @@ -39,13 +39,13 @@ exit 0 Running: bats ./test-two-fer.bats 1..4 ok 1 no file given -ok 2 empty file given # skip -ok 3 a name given # skip -ok 4 name with a space # skip +ok 2 empty file given +ok 3 a name given +ok 4 name with a space -real 0m0.200s -user 0m0.111s -sys 0m0.104s +real 0m0.209s +user 0m0.129s +sys 0m0.102s exit 0 @@ -81,9 +81,9 @@ Test 6: result -> passed -real 0m0.008s -user 0m0.001s -sys 0m0.008s +real 0m0.006s +user 0m0.004s +sys 0m0.002s Tests Passed! @@ -93,8 +93,8 @@ exit 0 Running: misspell . -real 0m0.037s -user 0m0.042s +real 0m0.031s +user 0m0.024s sys 0m0.019s =============================================================================== From 9e45ef3e275a63f1409e9930f48ed6249271e370 Mon Sep 17 00:00:00 2001 From: Victor Payno Date: Fri, 1 Sep 2023 23:02:58 -0700 Subject: [PATCH 6/6] awk: add submit script --- awk/submit_files | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100755 awk/submit_files diff --git a/awk/submit_files b/awk/submit_files new file mode 100755 index 00000000..86d62b61 --- /dev/null +++ b/awk/submit_files @@ -0,0 +1,19 @@ +#!/bin/bash + +if [[ ! -d .exercism ]]; then + printf "ERROR: Run from inside a project directory.\n\n" + exit 1 +fi + +declare package_name_kebab + +get_awk_package_name() { + # these are kebab-case + basename "${PWD}" +} # get_awk_package_name() + +package_name_kebab="$(get_awk_package_name)" + +echo Running: exercism submit "${package_name_kebab}.awk" "${package_name_kebab}_test.awk" test-cases.awk run-tests-awk.txt +time exercism submit "${package_name_kebab}.awk" "${package_name_kebab}_test.awk" test-cases.awk run-tests-awk.txt +printf "\n"