├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── bin └── shove ├── example ├── basic.t ├── group-ex.t └── group.t ├── lib ├── shove.bashrc └── shove │ ├── t.shrc │ └── t.zshrc ├── shpec └── basic_shpec.sh ├── t ├── algebraic.t ├── basic.t ├── command.t ├── file.t ├── group-ex.t └── group.t └── tmp └── .keep /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | /tmp/ 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: sh 2 | script: make test 3 | os: 4 | - linux 5 | - osx 6 | notifications: 7 | slack: 8 | rooms: 9 | secure: 00NNL6SphnK5pCAjqRz9GzFICGb0IKfcZIEw94f6yGcS+uJXmacTnHGr084irxYuIiOSzk5Yrz7ai6HEUgYIubCmHNnVBuA4iuXQ/kbcH73fC8G4fZh+aphYXUvBRe3rOaUszAxXlmSJ0z6bQ9DqRZsixRYBLPVo55elI9W13RAfZ9ctvGlmyw8plo+jlww7xgBRoTB381YKGeGX1sEZkDBcHgOTGyIaHWsiAwUaVOWkRE5MgsIepZs0aTRsuZGwIzuZ5V5RCJx5ad1qSD8qR/kBCY6lDLr6f38X3/W9AGoQbyhG/rPjzL0xentYx3jRpsUrS8F+sxz2b0Lllv0zy5lT/E5KgemNDLa2C3s9EMXoWc0jA7QqTbDlbFYPnOueQXdn107IxX60WJiu2w3XEnrZJ5CMC1C+YLXV2gxmfTdmKtLirc+4dlXHI20Ydw/eji8vIA+HKu+7BZyqv6CDTrj2edXsQeCh2sWjADqqNvJ3K+JiwDtojNBjs0t/zoKHeI9ANFrtG10MyrsAeP++l79e/ma0x1DF/oRzHibpLaMtOSZ3624NfXEnw54MJ29bTLzNoPFZcy8Wo9f72z3oqv6tPjYLK1KHjPLZu9YvvsN8UX/oIA2Yc4an9BGFyhL5s+9PEu4IYqmEIjhxVjlZbasnBvyN8FUUbom4+PQRr+Q= 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.8.4 (2020-06-27) 2 | 3 | Bug Fix: ([#12](https://github.com/progrhyme/shove/pull/12)) 4 | 5 | - (zsh) `t_success` and `t_error` did not work properly because zshoption `shwordsplit` was not set 6 | 7 | ## 0.8.3 (2020-05-22) 8 | 9 | Feature: 10 | 11 | - export `SHOVE_SHELL` variable to detect running shell inside test scripts 12 | 13 | ## 0.8.2 (2016-09-25) 14 | 15 | Improve: 16 | 17 | - Fix problem of `readlink` to work with relative or nested links #9 18 | 19 | ## 0.8.1 (2016-09-19) 20 | 21 | Feature: 22 | 23 | - Add new grouping syntax `t::group "$msg" ({ ... })` which is compatible with 24 | the old one `T_SUB ((...))` #6 25 | 26 | Deprecate: 27 | 28 | - To use the old grouping syntax `T_SUB "$msg" (( ... ))` is now deprecated 29 | 30 | ## 0.8.0 (2016-09-19) 31 | 32 | Feature: 33 | 34 | - New testing functions #5 35 | - String: `t_present`, `t_blank` 36 | - File/directory: `t_exist`, `t_file`, `t_directory`, `t_symlink` 37 | - Algebraic: `t_eq`, `t_ne`, `t_gt`, `t_ge`, `t_lt`, `t_le` 38 | 39 | Bug Fix: 40 | 41 | - `t_is`, `t_isnt`: Add quote to arguments for separated strings #5 42 | 43 | ## 0.7.4 (2016-09-18) 44 | 45 | Enhance: 46 | 47 | - Support symlink for `bin/shove` by fetching its path using readlink #4 48 | 49 | Internal Change: 50 | 51 | - Move `lib/t.shrc` to `lib/shove/t.shrc` #4 52 | 53 | Change for Dependency: 54 | 55 | - Support new format of `clam.spec` for [clenv](https://github.com/progrhyme/clenv) 56 | v0.3 #4 57 | 58 | ## 0.7.3 (2016-08-28) 59 | 60 | Improve: 61 | 62 | - Check target file existence of `shove` command #3 BABAROT 63 | 64 | ## 0.7.2 (2016-05-4) 65 | 66 | Internal Change: 67 | 68 | - Add test task by [shpec](https://github.com/rylnd/shpec) 69 | - Remove unused variable to get running SHELL 70 | 71 | ## 0.7.1 (2016-04-26) 72 | 73 | Minor Improve: 74 | 75 | - Add indent to temporary test scripts according to grouping of tests. 76 | 77 | Minor Bug Fix: 78 | 79 | - Fix format option of `date` command to make temporary test scripts by minutes. 80 | 81 | ## 0.7.0 (2016-04-23) 82 | 83 | Feature: 84 | 85 | - Introduce special syntax `T_SUB (( ... ))` for grouping tests to reduce 86 | verbose writings and to make test codes more readable. 87 | 88 | ## 0.6.1 (2016-04-23) 89 | 90 | Feature: 91 | 92 | - Keep temporary test scripts for a while under working directory for troubleshooting. 93 | 94 | ## 0.6.0 (2016-04-22) 95 | 96 | Improve: 97 | 98 | - Add _ksh_ to test targets. 99 | - Don't use `local` keyword for variable declaration because it's not POSIX and 100 | not supported in _ksh_. 101 | 102 | ## 0.5.2 (2016-04-22) 103 | 104 | Change: 105 | 106 | - `shove` now exits 1 when test fails. 107 | 108 | Tiny Bug Fix: 109 | 110 | - "dash" was taken as "sh" at `t_init()`. (But no test uses the shell variable.) 111 | 112 | ## 0.5.1 (2016-04-22) 113 | 114 | Improve: 115 | 116 | - Quote argument string for compatibility. 117 | 118 | ## 0.5.0 (2016-04-21) 119 | 120 | Initial release. 121 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2020 IKEDA Kiyoshi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test shpec release 2 | 3 | BIN := bin/shove 4 | VERSION := $(shell $(BIN) -V) 5 | 6 | SHELLS := sh bash dash ksh zsh 7 | 8 | test: 9 | @set -e; \ 10 | for sh in $(SHELLS); do \ 11 | if which $$sh >/dev/null 2>&1; then \ 12 | $(BIN) -r t -v -s $$sh; \ 13 | else \ 14 | echo "$$sh is not found. skip."; \ 15 | fi; \ 16 | done 17 | 18 | shpec: 19 | @if ! which shpec >/dev/null 2>&1; then \ 20 | echo "shpec not found. quit."; \ 21 | exit 1; \ 22 | fi 23 | @set -e; \ 24 | for sh in $(SHELLS); do \ 25 | if which $$sh >/dev/null 2>&1; then \ 26 | echo "# shpec by $$sh"; \ 27 | $$sh `which shpec`; \ 28 | else \ 29 | echo "$$sh is not found. skip."; \ 30 | fi; \ 31 | done 32 | 33 | release: 34 | git commit -m $(VERSION) 35 | git tag -a v$(VERSION) -m $(VERSION) 36 | git push origin v$(VERSION) 37 | git push origin master 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/progrhyme/shove.svg?branch=master)](https://travis-ci.org/progrhyme/shove) 2 | # shove 3 | 4 | A test tool for shell scripts with [TAP](https://testanything.org/) outputs. 5 | 6 | The name **"shove"** comes from _"shell"_ and 7 | _"[prove](http://perldoc.perl.org/prove.html)"_ of Perl. 8 | 9 | ### Table of Contents 10 | 11 | * [Screenshots](#screenshots) 12 | * [Supported Shells](#supported-shells) 13 | * [Install](#install) 14 | * [Usage](#usage) 15 | * [Options](#options) 16 | * [How to write test codes](#how-to-write-test-codes) 17 | * [Basics](#basics) 18 | * [Grouping](#grouping) 19 | * [Authors](#authors) 20 | * [License](#license) 21 | 22 | # Screenshots 23 | 24 | Pass: 25 | 26 |
27 | shove-screenshot-pass_01 28 |
29 | 30 | Fail: 31 | 32 |
33 | shove-screenshot-fail_01 34 |
35 | 36 | # Supported Shells 37 | 38 | - _sh, bash, dash, ksh, zsh_ 39 | 40 | _ash_ is not tested, but hopefully supposed to work with **shove**. 41 | 42 | No plan to support _(t)csh_ or _fish_ because they are not POSIX compatible. 43 | 44 | # Install 45 | 46 | Just clone this repository or get tarballs from [releases](https://github.com/progrhyme/shove/releases) page. 47 | 48 | ``` 49 | # example snippet to install `shove` 50 | mkdir ~/src 51 | git clone https://github.com/progrhyme/shove.git ~/src/shove 52 | alias shove="$HOME/src/shove/bin/shove" 53 | shove -V 54 | ``` 55 | 56 | You can make a symlink of `bin/shove` in your favorite path; 57 | i.e. `/usr/local/bin/` or `$HOME/bin/` or any path. 58 | Or you can make an alias command like the snippet above. 59 | 60 | NOTE: 61 | Do not change the directory structure because `bin/shove` assumes 62 | its libraries exists in `../lib/` directory. 63 | 64 | # Usage 65 | 66 | ```sh 67 | shove TARGETS [OPTIONS] 68 | shove t/foo.t 69 | shove t/foo.t t/bar.t -s /bin/bash -v 70 | shove -r t/ -v 71 | 72 | # help 73 | shove -h|--help 74 | 75 | # version 76 | shove -V|--version 77 | ``` 78 | 79 | ## Options 80 | 81 | * `-s|--shell SHELL` : SHELL to execute tests. Default is `$SHELL`. 82 | * `-v|--verbose` : verbose output. 83 | * `-r|--recursive DIRECTORY` : Search test script files with extension `.t` 84 | under the directory 85 | 86 | # How to write test codes 87 | 88 | Many test functions get hints from 89 | [Test::More](http://perldoc.perl.org/Test/More.html) of Perl. 90 | 91 | There are some example test codes in [example](example) directory. 92 | 93 | ## Basics 94 | 95 | ```sh 96 | t_diag "Test for your shell scripts" # Log message visible on the test 97 | t_pass # Always Pass 98 | t_fail # Always Fail 99 | t_ok $exp "exp is true" # [ $exp ] 100 | t_ng $exp "exp is false" # [ ! $exp ] 101 | t_present $str "str is present" # [ -n "$str" ] 102 | t_blank $str "str is blank" # [ -z "$str" ] 103 | t_exist $path "path exists" # [ -e "$path" ] 104 | t_file $path "path is file" # [ -f "$path" ] 105 | t_directory $path "path is directory" # [ -d "$path" ] 106 | t_symlink $path "path is symlink" # [ -L "$path" ] 107 | t_is $a $b "a is b" # [ "$a" = "$b" ] 108 | t_isnt $a $b "a isn't b" # [ "$a" != "$b" ] 109 | t_eq $x $y "x == y" # [ $x -eq $y ] 110 | t_ne $x $y "x != y" # [ $x -ne $y ] 111 | t_gt $x $y "x > y" # [ $x -gt $y ] 112 | t_ge $x $y "x >= y" # [ $x -ge $y ] 113 | t_lt $x $y "x < y" # [ $x -lt $y ] 114 | t_le $x $y "x <= y" # [ $x -le $y ] 115 | t_success $cmd "cmd succeeds" # $cmd; [ $? -eq 0 ] 116 | t_error $cmd "cmd fails" # $cmd; [ $? -ne 0 ] 117 | ``` 118 | 119 | ## Grouping 120 | 121 | This feature works like `subtest` of 122 | [Test::More](http://perldoc.perl.org/Test/More.html). 123 | 124 | New special syntax is introduced in v0.8.1: 125 | 126 | ```sh 127 | t_ok $ok 128 | 129 | t::group "level1 group" ({ 130 | t_diag "Comment for level1 tests" 131 | t_ok $lv1_ok 132 | 133 | t::group "level2 group" ({ 134 | t_diag "Comment for level2 tests" 135 | t_ok $lv2_ok 136 | t_is $lv2_a $lv2_b 137 | }) 138 | }) 139 | ``` 140 | 141 | These codes are the same as following codes: 142 | 143 | ```sh 144 | t_ok $ok 145 | ( 146 | t_substart "level1 group" 147 | t_diag "Comment for level1 tests" 148 | t_ok $lv1_ok 149 | ( 150 | t_substart "level2 group" 151 | t_diag "Comment for level2 tests" 152 | t_ok $lv2_ok 153 | t_is $lv2_a $lv2_b 154 | t_subclose 155 | ) 156 | t_subend "level2 group" 157 | t_subclose 158 | ) 159 | t_subend "level1 group" 160 | ``` 161 | 162 | Tests in group are run in subshell. 163 | So you can run them in different context from main tests context. 164 | 165 | If you want test groups A and B not affect to each other, you have to put them in 166 | different groups. 167 | 168 | **CAUTION:** 169 | 170 | - **The old grouping syntax `T_SUB (( ... ))` will be unsupported in the future 171 | release.** 172 | 173 | # Authors 174 | 175 | IKEDA Kiyoshi 176 | 177 | # License 178 | 179 | The MIT License (MIT) 180 | 181 | Copyright (c) 2016-2020 IKEDA Kiyoshi 182 | -------------------------------------------------------------------------------- /bin/shove: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | 5 | version="0.8.4" 6 | 7 | current_dir="$(pwd)" 8 | 9 | bin_path="$0" 10 | while [[ -L "$bin_path" ]]; do 11 | cd "$(dirname $bin_path)" 12 | bin_path="$(readlink ${bin_path##*/})" 13 | done 14 | 15 | bin_dir="$(cd "$(dirname ${bin_path})" && pwd)" 16 | lib_dir="$(cd "${bin_dir}/../lib" && pwd)" 17 | . "${lib_dir}/shove.bashrc" 18 | 19 | cd "$current_dir" 20 | 21 | [[ ${SHOVE_DEBUG:-} ]] && set -x 22 | 23 | mkdir -p $SHOVE_WORKDIR 24 | 25 | targets=() 26 | 27 | # ============================================================ 28 | # Parse Arguments 29 | 30 | for opt in "$@"; do 31 | case "${1:-}" in 32 | "-s" | "--shell" ) 33 | if [[ -z $2 || "$2" =~ ^-+ ]]; then 34 | help 35 | else 36 | SHOVE_SHELL=$2 37 | shift 2 38 | fi 39 | ;; 40 | "-r" | "--recurse" ) 41 | if [[ -z $2 || "$2" =~ ^-+ ]]; then 42 | help 43 | else 44 | targets+=($(find $2 -type f -name '*.t')) 45 | shift 2 46 | fi 47 | ;; 48 | "-v" | "--verbose" ) 49 | SHOVE_VERBOSE=1 50 | shift 51 | ;; 52 | "-h" | "--help" ) 53 | help 54 | ;; 55 | "-V" | "--version" ) 56 | echo $version 57 | exit 0 58 | ;; 59 | * ) 60 | if [[ ${1:-} ]]; then 61 | targets+=($1) 62 | shift 63 | fi 64 | ;; 65 | esac 66 | done 67 | 68 | export SHOVE_SHELL=${SHOVE_SHELL:-$SHELL} 69 | SHOVE_SHELL_CMD=$SHOVE_SHELL 70 | 71 | if [ $SHOVE_DEBUG ]; then 72 | SHOVE_SHELL_CMD="$SHOVE_SHELL -x" 73 | fi 74 | 75 | # ============================================================ 76 | # Main Entry 77 | 78 | purge_tmp_files 79 | 80 | cat <&1 81 | Run tests by $SHOVE_SHELL_CMD 82 | ------------------------- 83 | EOS 84 | 85 | t_cnt=0 86 | for tgt in ${targets[@]}; do 87 | t_cnt=$((t_cnt + 1)) 88 | test_file $tgt 89 | done 90 | 91 | final_report 92 | 93 | exit $? 94 | 95 | : <<'__EOF__' 96 | 97 | =encoding utf8 98 | 99 | =head1 NAME 100 | 101 | B - A test tool for shell scripts 102 | 103 | =head1 SYNOPSYS 104 | 105 | shove TARGETS [OPTIONS] 106 | shove t/foo.t 107 | shove t/bar.t t/bar.t -s /bin/sh -v 108 | shove -r t/ -v 109 | 110 | Help: 111 | 112 | shove -h|--help 113 | 114 | Show version: 115 | 116 | shove -V|--version 117 | 118 | =head1 DESCRIPTION 119 | 120 | This script runs target test scripts. 121 | 122 | =head1 AUTHORS 123 | 124 | IKEDA Kiyoshi Eprogrhyme@gmail.comE 125 | 126 | =head1 LICENSE 127 | 128 | The MIT License (MIT) 129 | 130 | Copyright (c) 2016-2020 IKEDA Kiyoshi 131 | 132 | =cut 133 | 134 | __EOF__ 135 | 136 | -------------------------------------------------------------------------------- /example/basic.t: -------------------------------------------------------------------------------- 1 | t_pass 2 | t_fail 3 | t_ok "foo" 4 | t_ok "-z 'foo'" 5 | t_ng "-f 'no-such-file'" 6 | t_ng "" 7 | t_is 1 1 8 | t_is 1 2 9 | t_is 1 a 10 | t_isnt 1 a 11 | t_isnt 1 2 12 | t_isnt "a" "a" 13 | t_success true 14 | t_success "echo 'foo'" 15 | t_error false 16 | t_error "echo 'foo' | grep 'bar'" 17 | -------------------------------------------------------------------------------- /example/group-ex.t: -------------------------------------------------------------------------------- 1 | t_ok ok 2 | t_ng ng 3 | T_SUB "child group" (( 4 | t_ok c1 5 | t_ng c2 6 | t_success foo "command 'foo' fails" 7 | T_SUB "grand child" (( 8 | t_ok gc1 9 | t_ng gc2 10 | )) 11 | )) 12 | -------------------------------------------------------------------------------- /example/group.t: -------------------------------------------------------------------------------- 1 | t_ok ok 2 | t_ng ng 3 | ( 4 | t_substart "start child" 5 | t_ok c1 6 | t_ng c2 7 | t_success foo "command 'foo' fails" 8 | ( 9 | t_substart "grand child" 10 | t_ok gc1 11 | t_ng gc2 12 | t_subclose 13 | ) 14 | t_subend "grand child" 15 | t_subclose 16 | ) 17 | t_subend "end child" 18 | -------------------------------------------------------------------------------- /lib/shove.bashrc: -------------------------------------------------------------------------------- 1 | SHOVE_SHELL= 2 | SHOVE_SHELL_CMD= 3 | SHOVE_WORKDIR=${SHOVE_WORK_DIR:-"${HOME}/.shove"} 4 | SHOVE_TMPFILE=${SHOVE_WORKDIR}/t_script.$(date +%Y%m%d%H%M).sh 5 | SHOVE_KEEPDAYS=${SHOVE_KEEPDAYS:-3} 6 | SHOVE_VERBOSE= 7 | SHOVE_DEBUG=${SHOVE_DEBUG:-} 8 | 9 | T_TOTAL=0 10 | T_PASS=0 11 | T_FAIL=0 12 | 13 | LF=$(printf '\\\012_') 14 | LF=${LF%_} 15 | 16 | help() { 17 | pod2text $0 18 | exit 1 19 | } 20 | 21 | # indent 22 | _lv=0 23 | _ws() { 24 | if [ $_lv -gt 0 ]; then 25 | printf '%*s' $((_lv * 2)) 26 | fi 27 | } 28 | 29 | _add() { 30 | echo "$(_ws)$1" >> $tmp 31 | } 32 | 33 | purge_tmp_files() { 34 | purge_targets=($(find $SHOVE_WORKDIR -type f -mtime +${SHOVE_KEEPDAYS})) 35 | if [[ -z "${purge_targets:-}" ]]; then 36 | return 37 | fi 38 | echo -n "# Purge ${#purge_targets[@]} files..." 39 | for pt in ${purge_targets[@]}; do 40 | rm -f $pt 41 | done 42 | echo "done." 43 | } 44 | 45 | test_file() { 46 | if [[ ! -f $1 ]]; then 47 | echo "$1: Is not a regular file" >&2 48 | exit 1 49 | fi 50 | _t=$1 51 | tmp=$SHOVE_TMPFILE.${t_cnt} 52 | dat="${tmp}.dat" 53 | 54 | ## create tmp test script 55 | : > $tmp 56 | case "$SHOVE_SHELL" in 57 | *zsh ) _add ". ${lib_dir}/shove/t.zshrc";; 58 | * ) _add ". ${lib_dir}/shove/t.shrc";; 59 | esac 60 | _add "t_init" 61 | if [[ $SHOVE_VERBOSE ]]; then 62 | _add "__t_verbose=1" 63 | fi 64 | cat $_t | while read line; do 65 | if [[ "$line" =~ ^[[:space:]]*t::group[[:space:]]*.*\(\{$ ]]; then 66 | #echo "# '$line' matches group beginning." 67 | _item="$(echo $line | sed -e 's/^t::group //' | sed -e 's/ ({$//')" 68 | subtests+=("${_item}") 69 | _add '(' 70 | : $((_lv += 1)) 71 | _add "t_substart ${_item}" 72 | elif [[ "$line" =~ ^[[:space:]]*T_SUB[[:space:]]*.*\(\($ ]]; then 73 | #echo "# '$line' matches group beginning." 74 | _item="$(echo $line | sed -e 's/^T_SUB //' | sed -e 's/ (($//')" 75 | subtests+=("${_item}") 76 | _add '(' 77 | : $((_lv += 1)) 78 | _add "t_substart ${_item}" 79 | elif [[ "$line" =~ ^[[:space:]]*[\}\)]\)$ ]]; then 80 | #echo "# '$line' matches group ending." 81 | declare -i num=${#subtests[@]} 82 | last=$((num - 1)) 83 | _item="${subtests[$last]}" 84 | subtests=("${subtests[@]:0:$last}") 85 | echo "$(_ws)t_subclose" >> $tmp 86 | : $((_lv -= 1)) 87 | _add ')' 88 | _add "t_subend ${_item}" 89 | else 90 | _add "$line" 91 | fi 92 | done 93 | _add "echo 1..\$__t_total" 94 | _add "t_report $dat" 95 | 96 | # exec tmp test script 97 | echo "$_t ..." 98 | set +e 99 | $SHOVE_SHELL_CMD $tmp 100 | ret=$? 101 | set -e 102 | 103 | data=($(cat $dat)) 104 | T_TOTAL=$((T_TOTAL + ${data[0]})) 105 | T_PASS=$((T_PASS + ${data[1]})) 106 | T_FAIL=$((T_FAIL + ${data[2]})) 107 | 108 | if [[ $ret = 0 ]]; then 109 | echo ok 110 | rm -f $tmp 111 | else 112 | printf "\033[0;31mnot ok\033[0;39m\n" 113 | cat <&1 114 | ---- 115 | # To reproduce this, run this: 116 | # $SHOVE_SHELL [-x] $tmp 117 | # Add '-x' to look into it. 118 | EOS 119 | fi 120 | 121 | rm -f $dat 122 | } 123 | 124 | final_report() { 125 | cat <&1 126 | 127 | Test Summary Report 128 | ------------------- 129 | EOS 130 | if [[ $T_FAIL = 0 ]]; then 131 | printf "\033[0;32mAll tests successful.\033[0;39m\n" 132 | else 133 | printf "\033[0;31mSome tests failing.\033[0;39m\n" 134 | fi 135 | 136 | echo "Files=${t_cnt}, Tests=${T_TOTAL}, Successes=${T_PASS}, Failures=${T_FAIL}" 137 | if [[ $T_FAIL = 0 ]]; then 138 | echo "Result: PASS" 139 | return 0 140 | else 141 | echo "Result: FAIL" 142 | return 1 143 | fi 144 | } 145 | -------------------------------------------------------------------------------- /lib/shove/t.shrc: -------------------------------------------------------------------------------- 1 | # sh 2 | 3 | __t_idx=1 4 | __t_total=0 5 | __t_ok=0 6 | __t_ng=0 7 | __t_level=0 8 | __t_verbose="" 9 | __t_tmpfile="./.__t_tmp.dat" 10 | 11 | _t_incr() { 12 | _var=$1 13 | _cur_var=$(($_var)) 14 | eval ": $(($_var += 1))" 15 | unset _var _cur_var 16 | } 17 | 18 | _t_either() { 19 | _t_result=$1 20 | _t_incr __t_idx 21 | _t_incr __t_total 22 | _t_incr $_t_result 23 | unset _t_result 24 | } 25 | 26 | _t_incr_level() { 27 | : $((__t_level += 1)) 28 | } 29 | 30 | _t_decr_level() { 31 | : $((__t_level -= 1)) 32 | } 33 | 34 | _t_put() { 35 | if [ $__t_level -gt 0 -a -z "$__t_verbose" ]; then 36 | return 37 | fi 38 | if [ $__t_level -gt 0 ]; then 39 | printf '%*s' $((__t_level * 2)) 40 | fi 41 | printf "$1\n" 42 | } 43 | 44 | t_init() { 45 | __t_idx=1 46 | __t_total=0 47 | __t_ok=0 48 | __t_ng=0 49 | } 50 | 51 | t_diag() { 52 | _t_put "# $1" 53 | } 54 | 55 | t_pass() { 56 | if [ "$__t_verbose" ]; then 57 | _t_put "ok $__t_idx - ${1:-pass}" 58 | fi 59 | _t_either __t_ok 60 | return 0 61 | } 62 | 63 | t_fail() { 64 | _t_put "\033[0;31mnot ok $__t_idx - ${1:-fail}\033[0;39m" 65 | _t_either __t_ng 66 | return 1 67 | } 68 | 69 | _t_pass_or_fail() { 70 | _sbj="$1" 71 | _diag="$2" 72 | if eval "$_sbj"; then 73 | t_pass "$2" 74 | else 75 | t_fail "$2" 76 | fi 77 | } 78 | 79 | _t_single() { 80 | _sbj="$1" 81 | _diag="${2:-}" 82 | _type=$3 83 | if [ -z "$_diag" ]; then 84 | case "$_type" in 85 | "ok" ) _diag="ok $_sbj";; 86 | "ng" ) _diag="ng $_sbj";; 87 | "present" ) _diag="$_sbj is present";; 88 | "blank" ) _diag="$_sbj is blank";; 89 | "exist" ) _diag="$_sbj exists";; 90 | "file" ) _diag="$_sbj is file";; 91 | "directory" ) _diag="$_sbj is directory";; 92 | "symlink" ) _diag="$_sbj is symlink";; 93 | * ) echo "Unknown type: ${_type}" >&2; exit 1;; 94 | esac 95 | fi 96 | 97 | case "$_type" in 98 | "ok" ) _t_pass_or_fail "[ $_sbj ]" "$_diag" ;; 99 | "ng" ) _t_pass_or_fail "[ ! $_sbj ]" "$_diag" ;; 100 | "present" ) _t_pass_or_fail "[ -n '$_sbj' ]" "$_diag" ;; 101 | "blank" ) _t_pass_or_fail "[ -z '$_sbj' ]" "$_diag" ;; 102 | "exist" ) _t_pass_or_fail "[ -e '$_sbj' ]" "$_diag" ;; 103 | "file" ) _t_pass_or_fail "[ -f '$_sbj' ]" "$_diag" ;; 104 | "directory" ) _t_pass_or_fail "[ -d '$_sbj' ]" "$_diag" ;; 105 | "symlink" ) _t_pass_or_fail "[ -L '$_sbj' ]" "$_diag" ;; 106 | * ) echo "Unknown type: ${_type}" >&2; exit 1;; 107 | esac 108 | unset _sbj _diag _type 109 | } 110 | 111 | t_ok() { 112 | _t_single "$1" "${2:-}" ok 113 | } 114 | 115 | t_ng() { 116 | _t_single "$1" "${2:-}" ng 117 | } 118 | 119 | t_present() { 120 | _t_single "$1" "${2:-}" present 121 | } 122 | 123 | t_blank() { 124 | _t_single "$1" "${2:-}" blank 125 | } 126 | 127 | t_exist() { 128 | _t_single "$1" "${2:-}" exist 129 | } 130 | 131 | t_file() { 132 | _t_single "$1" "${2:-}" file 133 | } 134 | 135 | t_directory() { 136 | _t_single "$1" "${2:-}" directory 137 | } 138 | 139 | t_symlink() { 140 | _t_single "$1" "${2:-}" symlink 141 | } 142 | 143 | _t_pair() { 144 | _lhs="$1" 145 | _rhs="$2" 146 | _diag="${3:-}" 147 | _type=$4 148 | if [ -z "$_diag" ]; then 149 | case "$_type" in 150 | "is" ) _diag="$_lhs is $_rhs";; 151 | "isnt" ) _diag="$_lhs isn't $_rhs";; 152 | "eq" ) _diag="$_lhs == $_rhs";; 153 | "ne" ) _diag="$_lhs != $_rhs";; 154 | "gt" ) _diag="$_lhs > $_rhs";; 155 | "ge" ) _diag="$_lhs >= $_rhs";; 156 | "lt" ) _diag="$_lhs < $_rhs";; 157 | "le" ) _diag="$_lhs <= $_rhs";; 158 | * ) echo "Unknown type: ${_type}" >&2; exit 1;; 159 | esac 160 | fi 161 | 162 | case "$_type" in 163 | "is" ) _t_pass_or_fail "[ '$_lhs' = '$_rhs' ]" "$_diag" ;; 164 | "isnt" ) _t_pass_or_fail "[ '$_lhs' != '$_rhs' ]" "$_diag" ;; 165 | "eq" ) _t_pass_or_fail "[ $_lhs -eq $_rhs ]" "$_diag" ;; 166 | "ne" ) _t_pass_or_fail "[ $_lhs -ne $_rhs ]" "$_diag" ;; 167 | "gt" ) _t_pass_or_fail "[ $_lhs -gt $_rhs ]" "$_diag" ;; 168 | "ge" ) _t_pass_or_fail "[ $_lhs -ge $_rhs ]" "$_diag" ;; 169 | "lt" ) _t_pass_or_fail "[ $_lhs -lt $_rhs ]" "$_diag" ;; 170 | "le" ) _t_pass_or_fail "[ $_lhs -le $_rhs ]" "$_diag" ;; 171 | * ) echo "Unknown type: ${_type}" >&2; exit 1;; 172 | esac 173 | unset _lhs _rhs _diag _type 174 | } 175 | 176 | t_is() { 177 | _t_pair "$1" "$2" "${3:-}" is 178 | } 179 | 180 | t_isnt() { 181 | _t_pair "$1" "$2" "${3:-}" isnt 182 | } 183 | 184 | t_eq() { 185 | _t_pair "$1" "$2" "${3:-}" eq 186 | } 187 | 188 | t_ne() { 189 | _t_pair "$1" "$2" "${3:-}" ne 190 | } 191 | 192 | t_gt() { 193 | _t_pair "$1" "$2" "${3:-}" gt 194 | } 195 | 196 | t_ge() { 197 | _t_pair "$1" "$2" "${3:-}" ge 198 | } 199 | 200 | t_lt() { 201 | _t_pair "$1" "$2" "${3:-}" lt 202 | } 203 | 204 | t_le() { 205 | _t_pair "$1" "$2" "${3:-}" le 206 | } 207 | 208 | _t_try() { 209 | _cmd="$1" 210 | _type=$2 211 | _diag="$3" 212 | _fail="" 213 | $_cmd > $__t_tmpfile 2>&1 214 | _ret=$? 215 | if [ "$_type" = "success" ]; then 216 | if [ $_ret -ne 0 ]; then 217 | _fail=1 218 | fi 219 | elif [ $_ret -eq 0 ]; then 220 | _fail=1 221 | fi 222 | if [ "$_fail" ]; then 223 | t_fail "$_diag" 224 | cat $__t_tmpfile | while read _t_line; do 225 | _t_put "\033[0;31m# ${_t_line}\033[0;39m" 226 | done 227 | else 228 | t_pass "$_diag" 229 | fi 230 | rm -f $__t_tmpfile 231 | unset _cmd _type _diag _fail _ret 232 | } 233 | 234 | t_success() { 235 | _cmd="$1" 236 | _diag="${2:-}" 237 | if [ -z "$_diag" ]; then 238 | _diag="$1 success" 239 | fi 240 | _t_try "$_cmd" "success" "$_diag" 241 | unset _cmd _diag 242 | } 243 | 244 | t_error() { 245 | _cmd="$1" 246 | _diag="${2:-}" 247 | if [ -z "$_diag" ]; then 248 | _diag="$1 error" 249 | fi 250 | _t_try "$_cmd" "error" "$_diag" 251 | unset _cmd _diag 252 | } 253 | 254 | t_substart() { 255 | t_init 256 | _t_incr_level 257 | t_diag "${1:-substart}" 258 | } 259 | 260 | t_subend() { 261 | t_is $? 0 "${1:-subend}" 262 | } 263 | 264 | t_subclose() { 265 | _t_put "1..$__t_total" 266 | t_report 267 | } 268 | 269 | t_report() { 270 | if [ "${1:-}" ]; then 271 | printf "$__t_total\t$__t_ok\t$__t_ng\n" > $1 272 | fi 273 | return $__t_ng 274 | } 275 | -------------------------------------------------------------------------------- /lib/shove/t.zshrc: -------------------------------------------------------------------------------- 1 | # zsh 2 | 3 | __t_idx=1 4 | __t_total=0 5 | __t_ok=0 6 | __t_ng=0 7 | __t_level=0 8 | __t_verbose="" 9 | __t_tmpfile="./.__t_tmp.dat" 10 | 11 | _t_incr() { 12 | _var=$1 13 | _cur_var=$(($_var)) 14 | eval ": $(($_var += 1))" 15 | unset _var _cur_var 16 | } 17 | 18 | _t_either() { 19 | _t_result=$1 20 | _t_incr __t_idx 21 | _t_incr __t_total 22 | _t_incr $_t_result 23 | unset _t_result 24 | } 25 | 26 | _t_incr_level() { 27 | : $((__t_level += 1)) 28 | } 29 | 30 | _t_decr_level() { 31 | : $((__t_level -= 1)) 32 | } 33 | 34 | _t_put() { 35 | if [ $__t_level -gt 0 -a -z "$__t_verbose" ]; then 36 | return 37 | fi 38 | if [ $__t_level -gt 0 ]; then 39 | printf '%*s' $((__t_level * 2)) 40 | fi 41 | printf "$1\n" 42 | } 43 | 44 | t_init() { 45 | __t_idx=1 46 | __t_total=0 47 | __t_ok=0 48 | __t_ng=0 49 | } 50 | 51 | t_diag() { 52 | _t_put "# $1" 53 | } 54 | 55 | t_pass() { 56 | if [ "$__t_verbose" ]; then 57 | _t_put "ok $__t_idx - ${1:-pass}" 58 | fi 59 | _t_either __t_ok 60 | return 0 61 | } 62 | 63 | t_fail() { 64 | _t_put "\033[0;31mnot ok $__t_idx - ${1:-fail}\033[0;39m" 65 | _t_either __t_ng 66 | return 1 67 | } 68 | 69 | _t_pass_or_fail() { 70 | _sbj="$1" 71 | _diag="$2" 72 | if eval "$_sbj"; then 73 | t_pass "$2" 74 | else 75 | t_fail "$2" 76 | fi 77 | } 78 | 79 | _t_single() { 80 | _sbj="$1" 81 | _diag="${2:-}" 82 | _type=$3 83 | if [ -z "$_diag" ]; then 84 | case "$_type" in 85 | "ok" ) _diag="ok $_sbj";; 86 | "ng" ) _diag="ng $_sbj";; 87 | "present" ) _diag="$_sbj is present";; 88 | "blank" ) _diag="$_sbj is blank";; 89 | "exist" ) _diag="$_sbj exists";; 90 | "file" ) _diag="$_sbj is file";; 91 | "directory" ) _diag="$_sbj is directory";; 92 | "symlink" ) _diag="$_sbj is symlink";; 93 | * ) echo "Unknown type: ${_type}" >&2; exit 1;; 94 | esac 95 | fi 96 | 97 | case "$_type" in 98 | "ok" ) _t_pass_or_fail "[ $_sbj ]" "$_diag" ;; 99 | "ng" ) _t_pass_or_fail "[ ! $_sbj ]" "$_diag" ;; 100 | "present" ) _t_pass_or_fail "[ -n '$_sbj' ]" "$_diag" ;; 101 | "blank" ) _t_pass_or_fail "[ -z '$_sbj' ]" "$_diag" ;; 102 | "exist" ) _t_pass_or_fail "[ -e '$_sbj' ]" "$_diag" ;; 103 | "file" ) _t_pass_or_fail "[ -f '$_sbj' ]" "$_diag" ;; 104 | "directory" ) _t_pass_or_fail "[ -d '$_sbj' ]" "$_diag" ;; 105 | "symlink" ) _t_pass_or_fail "[ -L '$_sbj' ]" "$_diag" ;; 106 | * ) echo "Unknown type: ${_type}" >&2; exit 1;; 107 | esac 108 | unset _sbj _diag _type 109 | } 110 | 111 | t_ok() { 112 | _t_single "$1" "${2:-}" ok 113 | } 114 | 115 | t_ng() { 116 | _t_single "$1" "${2:-}" ng 117 | } 118 | 119 | t_present() { 120 | _t_single "$1" "${2:-}" present 121 | } 122 | 123 | t_blank() { 124 | _t_single "$1" "${2:-}" blank 125 | } 126 | 127 | t_exist() { 128 | _t_single "$1" "${2:-}" exist 129 | } 130 | 131 | t_file() { 132 | _t_single "$1" "${2:-}" file 133 | } 134 | 135 | t_directory() { 136 | _t_single "$1" "${2:-}" directory 137 | } 138 | 139 | t_symlink() { 140 | _t_single "$1" "${2:-}" symlink 141 | } 142 | 143 | _t_pair() { 144 | _lhs="$1" 145 | _rhs="$2" 146 | _diag="${3:-}" 147 | _type=$4 148 | if [ -z "$_diag" ]; then 149 | case "$_type" in 150 | "is" ) _diag="$_lhs is $_rhs";; 151 | "isnt" ) _diag="$_lhs isn't $_rhs";; 152 | "eq" ) _diag="$_lhs == $_rhs";; 153 | "ne" ) _diag="$_lhs != $_rhs";; 154 | "gt" ) _diag="$_lhs > $_rhs";; 155 | "ge" ) _diag="$_lhs >= $_rhs";; 156 | "lt" ) _diag="$_lhs < $_rhs";; 157 | "le" ) _diag="$_lhs <= $_rhs";; 158 | * ) echo "Unknown type: ${_type}" >&2; exit 1;; 159 | esac 160 | fi 161 | 162 | case "$_type" in 163 | "is" ) _t_pass_or_fail "[ '$_lhs' = '$_rhs' ]" "$_diag" ;; 164 | "isnt" ) _t_pass_or_fail "[ '$_lhs' != '$_rhs' ]" "$_diag" ;; 165 | "eq" ) _t_pass_or_fail "[ $_lhs -eq $_rhs ]" "$_diag" ;; 166 | "ne" ) _t_pass_or_fail "[ $_lhs -ne $_rhs ]" "$_diag" ;; 167 | "gt" ) _t_pass_or_fail "[ $_lhs -gt $_rhs ]" "$_diag" ;; 168 | "ge" ) _t_pass_or_fail "[ $_lhs -ge $_rhs ]" "$_diag" ;; 169 | "lt" ) _t_pass_or_fail "[ $_lhs -lt $_rhs ]" "$_diag" ;; 170 | "le" ) _t_pass_or_fail "[ $_lhs -le $_rhs ]" "$_diag" ;; 171 | * ) echo "Unknown type: ${_type}" >&2; exit 1;; 172 | esac 173 | unset _lhs _rhs _diag _type 174 | } 175 | 176 | t_is() { 177 | _t_pair "$1" "$2" "${3:-}" is 178 | } 179 | 180 | t_isnt() { 181 | _t_pair "$1" "$2" "${3:-}" isnt 182 | } 183 | 184 | t_eq() { 185 | _t_pair "$1" "$2" "${3:-}" eq 186 | } 187 | 188 | t_ne() { 189 | _t_pair "$1" "$2" "${3:-}" ne 190 | } 191 | 192 | t_gt() { 193 | _t_pair "$1" "$2" "${3:-}" gt 194 | } 195 | 196 | t_ge() { 197 | _t_pair "$1" "$2" "${3:-}" ge 198 | } 199 | 200 | t_lt() { 201 | _t_pair "$1" "$2" "${3:-}" lt 202 | } 203 | 204 | t_le() { 205 | _t_pair "$1" "$2" "${3:-}" le 206 | } 207 | 208 | _t_try() { 209 | local _cmd="$1" 210 | local _type=$2 211 | local _diag="$3" 212 | local _fail="" 213 | local opt_shwordsplit=$(setopt | grep shwordsplit || true) 214 | if [[ -z "$opt_shwordsplit" ]]; then 215 | setopt shwordsplit 216 | fi 217 | $_cmd > $__t_tmpfile 2>&1 218 | local _ret=$? 219 | if [[ -z "$opt_shwordsplit" ]]; then 220 | unsetopt shwordsplit 221 | fi 222 | if [ "$_type" = "success" ]; then 223 | if [ $_ret -ne 0 ]; then 224 | _fail=1 225 | fi 226 | elif [ $_ret -eq 0 ]; then 227 | _fail=1 228 | fi 229 | if [ "$_fail" ]; then 230 | t_fail "$_diag" 231 | cat $__t_tmpfile | while read _t_line; do 232 | _t_put "\033[0;31m# ${_t_line}\033[0;39m" 233 | done 234 | else 235 | t_pass "$_diag" 236 | fi 237 | rm -f $__t_tmpfile 238 | } 239 | 240 | t_success() { 241 | _cmd="$1" 242 | _diag="${2:-}" 243 | if [ -z "$_diag" ]; then 244 | _diag="$1 success" 245 | fi 246 | _t_try "$_cmd" "success" "$_diag" 247 | unset _cmd _diag 248 | } 249 | 250 | t_error() { 251 | _cmd="$1" 252 | _diag="${2:-}" 253 | if [ -z "$_diag" ]; then 254 | _diag="$1 error" 255 | fi 256 | _t_try "$_cmd" "error" "$_diag" 257 | unset _cmd _diag 258 | } 259 | 260 | t_substart() { 261 | t_init 262 | _t_incr_level 263 | t_diag "${1:-substart}" 264 | } 265 | 266 | t_subend() { 267 | t_is $? 0 "${1:-subend}" 268 | } 269 | 270 | t_subclose() { 271 | _t_put "1..$__t_total" 272 | t_report 273 | } 274 | 275 | t_report() { 276 | if [ "${1:-}" ]; then 277 | printf "$__t_total\t$__t_ok\t$__t_ng\n" > $1 278 | fi 279 | return $__t_ng 280 | } 281 | -------------------------------------------------------------------------------- /shpec/basic_shpec.sh: -------------------------------------------------------------------------------- 1 | . lib/shove/t.shrc 2 | 3 | test_equal() { 4 | sbj="$1" 5 | it "$sbj = $2" 6 | _sbj=$(($sbj)) 7 | assert equal $_sbj $2 8 | end 9 | unset sbj 10 | } 11 | 12 | should_pass() { 13 | it "$1" 14 | assert equal $__t_ok 1 15 | assert equal $__t_ng 0 16 | end 17 | } 18 | 19 | should_fail() { 20 | it "$1" 21 | assert equal $__t_ok 0 22 | assert equal $__t_ng 1 23 | end 24 | } 25 | 26 | describe "t_init" 27 | t_init 28 | test_equal __t_idx 1 29 | for var in total ok ng level; do 30 | test_equal __t_${var} 0 31 | done 32 | unset var 33 | end 34 | 35 | describe "t_pass" 36 | t_init 37 | t_pass 38 | test_equal __t_idx 2 39 | test_equal __t_total 1 40 | test_equal __t_ok 1 41 | test_equal __t_ng 0 42 | end 43 | 44 | describe "t_fail" 45 | t_init 46 | t_fail >/dev/null 47 | test_equal __t_idx 2 48 | test_equal __t_total 1 49 | test_equal __t_ok 0 50 | test_equal __t_ng 1 51 | end 52 | 53 | describe "t_ok" 54 | t_init 55 | t_ok "ok" 56 | should_pass "ok is ok" 57 | t_init 58 | t_ok "" >/dev/null 2>&1 59 | should_fail " is not ok" 60 | end 61 | 62 | describe "t_ng" 63 | t_init 64 | t_ng "ng" >/dev/null 2>&1 65 | should_fail "ng is not ng" 66 | t_init 67 | t_ng "" 68 | should_pass " is ng" 69 | end 70 | 71 | describe "t_is" 72 | t_init 73 | t_is 1 1 74 | should_pass "1 is 1" 75 | t_init 76 | t_is "aaa" "aaa" 77 | should_pass "aaa is aaa" 78 | t_init 79 | t_is 1 0 >/dev/null 2>&1 80 | should_fail "1 is not 0" 81 | t_init 82 | t_is "aaa" "aab" >/dev/null 2>&1 83 | should_fail "aaa is not aab" 84 | end 85 | 86 | describe "t_isnt" 87 | t_init 88 | t_isnt 1 1 >/dev/null 2>&1 89 | should_fail "1 is 1" 90 | t_init 91 | t_isnt "aaa" "aaa" >/dev/null 2>&1 92 | should_fail "aaa is aaa" 93 | t_init 94 | t_isnt 1 0 95 | should_pass "1 isn't 0" 96 | t_init 97 | t_isnt "aaa" "aab" 98 | should_pass "aaa isn't aab" 99 | end 100 | 101 | describe "t_success" 102 | t_init 103 | t_success true 104 | should_pass "true succeeds" 105 | t_init 106 | t_success false >/dev/null 2>&1 107 | should_fail "false fails" 108 | end 109 | 110 | describe "t_error" 111 | t_init 112 | t_error true >/dev/null 2>&1 113 | should_fail "true doesn't fail" 114 | t_init 115 | t_error false 116 | should_pass "false fails" 117 | end 118 | -------------------------------------------------------------------------------- /t/algebraic.t: -------------------------------------------------------------------------------- 1 | t_eq 1 1 2 | t_ne 1 2 3 | t_gt 2 1 4 | t_ge 2 2 5 | t_ge 3 2 6 | t_lt 1 2 7 | t_le 1 2 8 | t_le 2 2 9 | 10 | # vim:set ft=sh : 11 | -------------------------------------------------------------------------------- /t/basic.t: -------------------------------------------------------------------------------- 1 | t_pass 2 | t_ok "foo" "'foo' is, ok." 3 | t_ok "-e ." ". exists" 4 | t_ng "" "blank, is ng." 5 | t_ng "-f ." ". is not file" 6 | t_present "foo bar" "'foo bar' is, ok." 7 | t_blank "" "blank, is blank." 8 | t_is 1 1 9 | t_is a a 10 | t_is "a b" "a b" "a eq b" 11 | t_isnt 1 a "1 isnt a" 12 | t_isnt 1 2 13 | t_isnt "a" "b" "'a' isn't 'b'" 14 | t_isnt "a b" "ab" 15 | t_success true "true/ succeeds" 16 | t_error false 17 | 18 | # vim:set ft=sh : 19 | -------------------------------------------------------------------------------- /t/command.t: -------------------------------------------------------------------------------- 1 | t_success true 2 | t_success "echo ok" 3 | t_error false 4 | t_error "no-such-command arg1 arg2" 5 | -------------------------------------------------------------------------------- /t/file.t: -------------------------------------------------------------------------------- 1 | t_exist . 2 | t_file $0 3 | t_directory . 4 | 5 | T_SUB "Test symlink" (( 6 | tmpdir=tmp/file-test 7 | mkdir $tmpdir 8 | touch $tmpdir/testfile 9 | ln -s $tmpdir/testfile $tmpdir/testlink 10 | t_symlink $tmpdir/testlink 11 | rm -rf $tmpdir 12 | )) 13 | 14 | # vim:set ft=sh : 15 | -------------------------------------------------------------------------------- /t/group-ex.t: -------------------------------------------------------------------------------- 1 | t_ok ok 2 | 3 | T_SUB "child group 1" (( 4 | t_ok c1 5 | 6 | T_SUB "grand child 1" (( 7 | t_ok gc1 8 | )) 9 | 10 | t::group "grand child 2" ({ 11 | t_ok gc2 12 | }) 13 | )) 14 | 15 | t::group "child child 2" ({ 16 | t_ok c2 17 | }) 18 | 19 | # vim:set ft=sh : 20 | -------------------------------------------------------------------------------- /t/group.t: -------------------------------------------------------------------------------- 1 | t_ok ok 2 | ( 3 | t_substart "child group" 4 | t_ok c1 5 | ( 6 | t_substart "grand child" 7 | t_ok gc1 8 | t_subclose 9 | ) 10 | t_subend "grand child" 11 | t_subclose 12 | ) 13 | t_subend "child group" 14 | -------------------------------------------------------------------------------- /tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/progrhyme/shove/f7d70036c7edf5405ad5e3336981fcf360a29426/tmp/.keep --------------------------------------------------------------------------------