| #!/bin/sh |
| |
| # SUSv3 compliant sort tests. |
| # Public Domain, David Leonard 2022 |
| |
| . ./testing.sh |
| |
| # name cmd expected ./input stdin |
| testing "" "tsort" "a\n" "" "a a\n" |
| testing "" "tsort -" "a\n" "" "a a\n" |
| testing "" "tsort input" "a\n" "a a\n" "" |
| testing "tsort input (w/o eol)" "tsort input" "a\n" "a a" "" |
| testing "" "tsort /dev/null" "" "" "" |
| |
| testing "tsort empty" tsort "" "" "" |
| testing "tsort blank" tsort "" "" "\n" |
| testing "tsort blanks" tsort "" "" "\n\n \t\n " |
| |
| # simple inputs having exactly one solution |
| testing "tsort 1-edge" tsort "a\nb\n" "" "a b\n" |
| testing "tsort 2-edge" tsort "a\nb\nc\n" "" "a b b c\n" |
| |
| |
| # The following test helper accommodates future variable output because, as |
| # tsort is allowed to emit any total ordering that satisfies its input, |
| # should the implementation changes, these tests will remain valid. |
| # |
| # The idea is to verify that: |
| # - each input word is present EXACTLY ONCE in tsort's output |
| # - for each input pair 'a b', the occurrence of 'a' APPEARS BEFORE 'b' |
| # - the exit code is 0 |
| |
| tsort_test () { |
| fail= |
| name="$1"; shift |
| args="$*" |
| if [ $VERBOSE ]; then |
| echo "============" |
| echo "echo \"$args\" | tsort >actual" |
| fi |
| echo "$args" | tsort >actual |
| ec=$? |
| if [ $ec -ne 0 ]; then |
| fail "tsort exit $ec, expected 0" |
| fi |
| while [ $# -ne 0 ]; do |
| a=$1; shift |
| b=$1; shift |
| aline=$(grep -nxF "$a" <actual | cut -d: -f1) |
| bline=$(grep -nxF "$b" <actual | cut -d: -f1) |
| case $aline in |
| "") fail "word $a missing from output ($args)";; |
| *" "*) fail "word $a duplicated ($args)";; |
| esac |
| case $bline in |
| "") fail "word $b missing from output ($args)";; |
| *" "*) fail "word $b duplicated ($args)";; |
| esac |
| if [ $aline -gt $bline ]; then |
| fail "$a appears after $b ($args)" |
| fi |
| done |
| if [ $fail ] && [ $VERBOSE ]; then |
| echo "exit $ec, actual:" |
| cat actual |
| fi |
| rm actual |
| report "$name" |
| } |
| |
| # Test that erroneous input causes an unsuccessful exit code |
| # we don't test the output error message |
| tsort_test_err () { |
| fail= |
| name="$1"; shift |
| echo "$*" | tsort >/dev/null 2>/dev/null |
| ec=$? |
| if [ $ec -eq 0 ]; then |
| fail "$name: unexpected exit 0 ($*)" |
| fi |
| report "$name" |
| } |
| |
| fail () { |
| [ $VERBOSE ] && echo "ERROR: $*" |
| fail=1 |
| } |
| |
| report () { |
| if [ $fail ]; then |
| FAILCOUNT=$(($FAILCOUNT + 1)) |
| echo "FAIL: $*" |
| else |
| echo "PASS: $*" |
| fi |
| } |
| |
| tsort_test "tsort empty2" |
| tsort_test "tsort singleton" a a |
| tsort_test "tsort simple" a b b c |
| tsort_test "tsort 2singleton" a a b b |
| tsort_test "tsort medium" a b a b b c |
| tsort_test "tsort std.example" a b c c d e g g f g e f h h |
| tsort_test "tsort prefixes" a aa aa aaa aaaa aaaaa a aaaaa |
| |
| tsort_test_err "tsort odd" a |
| tsort_test_err "tsort odd2" a b c |
| tsort_test_err "tsort cycle" a b b a |
| |
| exit $FAILCOUNT |