#!/usr/bin/env bash # # Test individual functions in mo and make sure they are performing their # tasks correctly. This can be used to help determine what needs to get # fixed when making mo work on another version of bash, or another shell # entirely. # # Functions are tested from the most primitive to the most advanced. # Errors, once found, halt the program. This way we can more easily # diagnose what's not working and fix those low-level functions first. PARENT_PID=$$ cd "$(dirname "$0")" || exit 1 rm -f diagnostic.test rm -f diagnostic.partial # Load mo's functions # shellcheck disable=SC1091 . ./mo fail() { echo "$1" kill $PARENT_PID exit 1 } # No dependencies echo -n "moIndirect ... " ( a() { local V V="a" b echo -n "$V" } b() { local V V="b" c V echo -n "$V" } c() { local "$1" && moIndirect "$1" c } [[ "$(a)" != "ca" ]] && fail "Did not assign or scope bled '$RESULT'" ) echo "ok" echo -n "moIndirectArray ... " ( a() { local V V=( "a" ) b echo -n "${#V[@]}" } b() { local V V=( "b" "b" ) c V echo -n "${#V[@]}" } c() { local "$1" && moIndirectArray "$1" c c c } [[ "$(a)" != "31" ]] && fail "Did not assign or scope bled '$RESULT'" ) echo "ok" echo -n "moIsArray ... " ( export TEST_NUM=1 moIsArray TEST_NUM && fail "Wrongly said number was an array" ) ( export TEST_ARR=() moIsArray TEST_ARR || fail "Wrongly said array was not an array" ) ( export TEST_EMPTY="" moIsArray TEST_EMPTY && fail "Wrongly said string was an array" ) ( unset TEST_UNSET moIsArray TEST_UNSET && fail "Wrongly said undefined was an array" ) echo "ok" echo -n "moIsFunction ... " ( aa() { echo "hi"; } moIsFunction aa || fail "Did not find a function" moIsFunction dd && fail "Wrongly found a function" ) echo "ok" echo -n "moFindString ... " ( moFindString POS "abcdefg" "ab" [[ "$POS" == "0" ]] || fail "Did not find at beginning of string" moFindString POS "abcdefg" "fg" [[ "$POS" == "5" ]] || fail "Did not find at end of string" moFindString POS "abcdefg" "de" [[ "$POS" == "3" ]] || fail "Did not find at middle of string" moFindString POS "abcdefg" "CD" [[ "$POS" == "-1" ]] || fail "Did not correctly return a miss" ) echo "ok" echo -n "moFullTagName ... " ( moFullTagName TAG "abc" "def" [[ "$TAG" == "abc.def" ]] || fail "Did not work with a context" moFullTagName TAG "" "one" [[ "$TAG" == "one" ]] || fail "Did not work without a context" ) echo "ok" echo -n "moLoadFile ... " ( # TODO - find a way to test reading from stdin that is not painful. touch diagnostic.test moLoadFile RESULT diagnostic.test [[ "${#RESULT}" == "0" ]] || fail "Did not read from empty file '$RESULT'" echo "abc" >> diagnostic.test moLoadFile RESULT diagnostic.test [[ "${#RESULT}" == "4" ]] || fail "Did not read from file '$RESULT'" echo "" >> diagnostic.test moLoadFile RESULT diagnostic.test [[ "${#RESULT}" == "5" ]] || fail "Trimmed newline from file '$RESULT'" rm diagnostic.test ) echo "ok" echo -n "moStandaloneDenied ... " ( moStandaloneDenied RESULT before tag after > diagnostic.test [[ "$(cat diagnostic.test)" == "before" ]] || fail "Did not output content before tag '$(cat diagnostic.test)'" [[ "$RESULT" == "after" ]] || fail "Did not set the remaining content '$RESULT'" rm diagnostic.test ) echo "ok" echo -n "moTest ... " # shellcheck disable=SC2034 ( aa() { echo "hi"; } bb="bb" cc=3 dd=( dd ) xx=() unset yy zz="" moTest aa || fail "Did not detect a function" moTest bb || fail "Did not detect a non-empty string" moTest cc || fail "Did not detect a number" moTest dd || fail "Did not detect a populated array" moTest xx && fail "Erroneously flagged an empty array" moTest yy && fail "Erroneously flagged an undefined value" moTest zz && fail "Erroneously flagged an empty string" MO_FALSE_IF_EMPTY=true moTest zz && fail "Erroneously flagged an empty value as non-false when empty should be false" ) echo "ok" echo -n "moTrimChars ... " ( moTrimChars RESULT "abcdabc" true true a b c [[ "$RESULT" == "d" ]] || fail "Did not trim multiple characters '$RESULT'" moTrimChars RESULT "abc" true false a c [[ "$RESULT" == "bc" ]] || fail "Did not trim only from the front '$RESULT'" moTrimChars RESULT "abc" false true a c [[ "$RESULT" == "ab" ]] || fail "Did not trim only from the end '$RESULT'" ) echo "ok" echo -n "moGetContent ... " ( # TODO - find a way to test reading from stdin that is not painful. # Until then, mock it moLoadFile() { local "$1" && moIndirect "$1" "STDIN"; } moGetContent RESULT a [[ "$RESULT" == "{{>a}}" ]] || fail "Did not construct 1 partial correctly '$RESULT'" moGetContent RESULT a b c [[ "$RESULT" == "{{>a}}{{>b}}{{>c}}" ]] || fail "Did not construct 3 partials correctly '$RESULT'" moGetContent RESULT [[ "$RESULT" == "STDIN" ]] || fail "Did not call moLoadFile correctly" ) echo "ok" echo -n "moIndentLines ... " ( CR=$'\r' LF=$'\n' # shellcheck disable=SC2034 CRLF="$CR$LF" # CAUTION # This must have a dot at the end of the input string # That is part of how moPartial calls this function for NEWLINE in "CR" "LF" "CRLF"; do NL="${!NEWLINE}" moIndentLines RESULT "" "has${NL}${NEWLINE}${NL}." printf -v QUOTED '%q' "$RESULT" [[ "$RESULT" == "has${NL}${NEWLINE}${NL}" ]] || fail "Should not have changed string $QUOTED" moIndentLines RESULT "" "without${NL}trailing${NL}${NEWLINE}." printf -v QUOTED '%q' "$RESULT" [[ "$RESULT" == "without${NL}trailing${NL}${NEWLINE}" ]] || fail "Should not have changed string $QUOTED" moIndentLines RESULT "_-_" "has${NL}${NL}${NEWLINE}${NL}." printf -v QUOTED '%q' "$RESULT" [[ "$RESULT" == "_-_has${NL}${NL}_-_${NEWLINE}${NL}" ]] || fail "Should have indented $QUOTED" moIndentLines RESULT "_-_" "without${NL}${NL}trailing${NL}${NEWLINE}." printf -v QUOTED '%q' "$RESULT" [[ "$RESULT" == "_-_without${NL}${NL}_-_trailing${NL}_-_${NEWLINE}" ]] || fail "Should have indented $QUOTED" done ) echo "ok" echo -n "moIsStandalone ... " ( CR=$'\r' LF=$'\n' TAB=$'\t' moIsStandalone RESULT "" "" false && fail "Needs newline before or beginning of content flag" moIsStandalone RESULT "" "" true || fail "Has beginning of content flag and no other content" [[ "$RESULT" == "0 0" ]] || fail "Wrong returned value for no content '$RESULT'" moIsStandalone RESULT "moo" "cow" false && fail "Needs newlines when there is content" moIsStandalone RESULT "moo$CR$LF$TAB $TAB " " $TAB $TAB$CR${LF}pasture" false || fail "Has newlines and content but did not flag" [[ "$RESULT" == "5 6" ]] || fail "Wrong returned value when there was whitespace '$RESULT'" ) echo "ok" echo -n "moSplit ... " ( moSplit RESULT "abc-def-ghi" "-" [[ "${#RESULT[@]}" == "2" ]] || fail "Returned wrong number of elements with one delimiter ${#RESULT[@]}" [[ "${RESULT[0]}" == "abc" ]] || fail "Returned wrong left hand string with one delimiter '${RESULT[0]}'" [[ "${RESULT[1]}" == "def-ghi" ]] || fail "Returned wrong right hand string with one delimiter '${RESULT[1]}'" moSplit RESULT "abc-def-ghi" "-" "g" [[ "${#RESULT[@]}" == "3" ]] || fail "Returned wrong number of elements with two delimiters ${#RESULT[@]}" [[ "${RESULT[0]}" == "abc" ]] || fail "Returned wrong left hand string with two delimiters '${RESULT[0]}'" [[ "${RESULT[1]}" == "def-" ]] || fail "Returned wrong middle string with two delimiters '${RESULT[1]}'" [[ "${RESULT[2]}" == "hi" ]] || fail "Returned wrong right hand string with two delimiters '${RESULT[2]}'" ) echo "ok" echo -n "moTrimWhitespace ... " ( CR=$'\r' LF=$'\n' TAB=$'\t' moTrimWhitespace RESULT "ab cd" printf -v QUOTED '%q' "$RESULT" [[ "${RESULT}" == "ab cd" ]] || fail "Trimmed a string that did not need trimming $QUOTED" moTrimWhitespace RESULT "$CR$LF$TAB ab $CR$LF$TAB cd $CR$LF$TAB $CR$LF$TAB" printf -v QUOTED '%q' "$RESULT" [[ "${RESULT}" == "ab $CR$LF$TAB cd" ]] || fail "Did not fully trim a string $QUOTED" ) echo "ok" echo -n "moStandaloneAllowed ... " ( # Mock moIsStandalone to make things simpler moIsStandalone() { return 1; } moStandaloneAllowed RESULT before tag after > diagnostic.test [[ "$(cat diagnostic.test)" == "before" ]] || fail "Did not output content before tag when not standalone '$(cat diagnostic.test)'" [[ "$RESULT" == "after" ]] || fail "Did not set the remaining content when not standalone '$RESULT'" moIsStandalone() { local "$1" && moIndirect "$1" "3 5"; return 0; } moStandaloneAllowed RESULT before tag afterwards > diagnostic.test [[ "$(cat diagnostic.test)" == "bef" ]] || fail "Did not output content before tag when standalone '$(cat diagnostic.test)'" [[ "$RESULT" == "wards" ]] || fail "Did not set the remaining content when standalone '$RESULT'" rm diagnostic.test ) echo "ok" echo -n "moFindEndTag ... " ( LF=$'\n' moFindEndTag RESULT "moo{{ / cow }}pasture" "cow" [[ "${#RESULT[@]}" == "3" ]] || fail "(simple) Wrong number of elements in the array ${#RESULT[@]}" [[ "${RESULT[0]}" == "moo" ]] || fail "(simple) Wrong left-hand '${RESULT[0]}'" [[ "${RESULT[1]}" == "{{ / cow }}" ]] || fail "(simple) Wrong middle '${RESULT[1]}'" [[ "${RESULT[2]}" == "pasture" ]] || fail "(simple) Wrong right-hand '${RESULT[2]}'" moFindEndTag RESULT "moo$LF {{/cow}} $LF pasture" "cow" [[ "${#RESULT[@]}" == "3" ]] || fail "(standalone) Wrong number of elements in the array ${#RESULT[@]}" [[ "${RESULT[0]}" == "moo$LF" ]] || fail "(standalone) Wrong left-hand '${RESULT[0]}'" [[ "${RESULT[1]}" == " {{/cow}} $LF" ]] || fail "(standalone) Wrong middle '${RESULT[1]}'" [[ "${RESULT[2]}" == " pasture" ]] || fail "(standalone) Wrong right-hand '${RESULT[2]}'" moFindEndTag RESULT "aa{{#bb}}cc{{/bb}}dd{{^bb}}ee{{/bb}}ff{{/bb}}gg" "bb" [[ "${#RESULT[@]}" == "3" ]] || fail "(recursive) Wrong number of elements in the array ${#RESULT[@]}" [[ "${RESULT[0]}" == "aa{{#bb}}cc{{/bb}}dd{{^bb}}ee{{/bb}}ff" ]] || fail "(recursive) Wrong left-hand '${RESULT[0]}'" [[ "${RESULT[1]}" == "{{/bb}}" ]] || fail "(recursive) Wrong middle '${RESULT[1]}'" [[ "${RESULT[2]}" == "gg" ]] || fail "(recursive) Wrong right-hand '${RESULT[2]}'" moFindEndTag RESULT "aa{{#bb}}cc{{/dd}}ee" "dd" [[ "${#RESULT[@]}" == "3" ]] || fail "(unbalanced) Wrong number of elements in the array ${#RESULT[@]}" [[ "${RESULT[0]}" == "aa{{#bb}}cc{{/dd}}ee" ]] || fail "(unbalanced) Wrong left-hand '${RESULT[0]}'" [[ "${RESULT[1]}" == "" ]] || fail "(unbalanced) Wrong middle '${RESULT[1]}'" [[ "${RESULT[2]}" == "" ]] || fail "(unbalanced) Wrong right-hand '${RESULT[2]}'" ) echo "ok" echo -n "moLoop ... " ( moParse() { echo "parse[$1] context[$2] flag[$3]"; } moLoop "content" "prefix" a b c > diagnostic.test ( echo "parse[content] context[prefix.a] flag[false]" echo "parse[content] context[prefix.b] flag[false]" echo "parse[content] context[prefix.c] flag[false]" ) | diff -q diagnostic.test - || fail "Result was not as expected '$(cat diagnostic.test)'" rm diagnostic.test ) echo "ok" echo -n "moPartial ... " ( NL=$'\n' moParse() { echo "parse[$1] context[$2] flag[$3]"; } echo "partial" > diagnostic.partial moPartial RESULT "line$NL" ">diagnostic.partial" " ${NL}line2" false "moo" > diagnostic.test [[ "$RESULT" == "line2" ]] || fail "Did not consume newline for standalone '$RESULT'" printf -v QUOTED '%q' "$(cat diagnostic.test)" [[ "$(cat diagnostic.test)" == "line${NL}parse[partial${NL}] context[moo] flag[true]" ]] || fail "Did not parse right standalone content $QUOTED" moPartial RESULT "line" ">diagnostic.partial" "line2" false "moo" > diagnostic.test [[ "$RESULT" == "line2" ]] || fail "Did not preserve content for non-standalone '$RESULT'" printf -v QUOTED '%q' "$(cat diagnostic.test)" [[ "$(cat diagnostic.test)" == "lineparse[partial${NL}] context[moo] flag[true]" ]] || fail "Did not parse right non-standalone content $QUOTED" rm diagnostic.test diagnostic.partial ) echo "ok" echo -n "moShow ... " # shellcheck disable=SC2034 ( aa() { echo "this is aa"; } bb="BB" cc=( zero one two ) [[ "$(moShow aa)" == "this is aa" ]] || fail "Did not load function" [[ "$(moShow bb)" == "BB" ]] || fail "Did not show variable" [[ "$(moShow cc.1)" == "one" ]] || fail "Did not show value from indexed array" ) echo "ok" echo -n "moParse ... skipped (tested by specs)" echo "" echo "All diagnostic tests pass"