#!/data/data/com.termux/files/usr/bin/bash
# shellcheck disable=SC2016

# Title:         tudo_tests
# Description:   A script to run automated tests for the tudo command types.
# Homepage:      https://github.com/agnostic-apollo/tudo
# SPDX-License-Identifier: MIT
# Usage:         Run "tudo_tests --help" for detailed list of usages.
# Bash version:  4.1 or higher



if [ -z "${BASH_VERSION:-}" ]; then
    echo "The 'tudo_tests' script must be run from a 'bash' shell."; return 64 2>/dev/null|| exit 64 # EX__USAGE
fi



TUDO_TESTS_HELP="$(cat<<'TUDO_TESTS_HELP_EOF'
tudo_tests is a script that run tests for the tudo script.


Usage:
  tudo_tests [command_options]
  tudo_tests [command_options] <su|asu|path|script>
  tudo_tests [command_options] <su|asu|path|script> <shell> <test_number>


Available command_options:
  [ -h | --help ]    Display this help screen.
  [ --help-extra ]   Display more help about how tudo_tests command
                     works.
  [ -q | --quiet ]   Set log level to 'OFF'.
  [ -v | -vv | -vvv | -vvvvv ]  Set log level to 'DEBUG', 'VERBOSE',
                                'VVERBOSE' and 'VVVERBOSE'.
  [ --only-bash-tests ] Run only bash shell tests.


Setting log level '>= DEBUG' will fail test validation for tests that
match the output, its mainly for debugging.
TUDO_TESTS_HELP_EOF
)"

TUDO_TESTS_HELP_EXTRA="$(cat<<'TUDO_TESTS_HELP_EXTRA'


### Install and Usage Instructions For Termux In Android:

# Install tudo and tudo_tests scripts and set ownership and executable permission
curl -L 'https://github.com/agnostic-apollo/tudo/raw/master/tudo' -o "${TERMUX__PREFIX:-$PREFIX}/bin/tudo"; chmod +x "${TERMUX__PREFIX:-$PREFIX}/bin/tudo";
curl -L 'https://github.com/agnostic-apollo/tudo/raw/master/tests/tudo_tests' -o ~/tudo_tests; chmod +x ~/tudo_tests;
or
cat "/sdcard/Download/tudo" > "${TERMUX__PREFIX:-$PREFIX}/bin/tudo"; chmod +x "${TERMUX__PREFIX:-$PREFIX}/bin/tudo";
cat "/sdcard/Download/tudo_tests" > ~/tudo_tests; chmod +x ~/tudo_tests;

export termux_bin_path="${TERMUX__PREFIX:-$PREFIX}/bin"; export owner="$(stat -c "%u" "$termux_bin_path")"; chown "$owner:$owner" "$termux_bin_path/tudo" && chmod 700 "$termux_bin_path/tudo"; chown "$owner:$owner" ~/tudo_tests && chmod 700 ~/tudo_tests;


# Install shells used by tudo_tests script
pkg install bash zsh dash fish python ruby nodejs perl lua52 lua53 lua54 php rlwrap


# Install termux_tasker_basic_bash_test and termux_tasker_basic_python_test script and set permissions
mkdir -p ~/.termux/tasker
chmod 700 -R ~/.termux

curl -L 'https://github.com/termux/termux-tasker/raw/master/templates/scripts/termux_tasker_basic_bash_test' -o ~/.termux/tasker/termux_tasker_basic_bash_test
curl -L 'https://github.com/termux/termux-tasker/raw/master/templates/scripts/termux_tasker_basic_python_test' -o ~/.termux/tasker/termux_tasker_basic_python_test
or
cat "/sdcard/Download/termux_tasker_basic_bash_test" > ~/.termux/tasker/termux_tasker_basic_bash_test
cat "/sdcard/Download/termux_tasker_basic_python_test" > ~/.termux/tasker/termux_tasker_basic_python_test

chmod 700 ~/.termux/tasker/termux_tasker_basic_bash_test
chmod 700 ~/.termux/tasker/termux_tasker_basic_python_test


# Install yt-dlp
pkg install ffmpeg python
python3 -m pip install -U yt-dlp

# Fix shebang, must be run on install and on each update,
# otherwise will get "bad interpreter: /usr/bin/env" errors when running with root shell, plugin or TermuxCommand,
# because termux-exec doesn't work for those cases and LD_PRELOAD isn't set,
# but its not required for usage with tudo since it sets the LD_PRELOAD
termux-fix-shebang "${TERMUX__PREFIX:-$PREFIX}/bin/yt-dlp"
#
# Update yt-dlp
python3 -m pip install -U yt-dlp


# Install bandcamp-dl
pip3 install bandcamp-downloader
#
# Update bandcamp-dl
pkg install git
pip install git+https://github.com/iheanyi/bandcamp-dl --upgrade



# Following are not required for the tests currently

# Install pry, the ruby interactive shell alternative
gem install pry

# Install python2
pkg install python2

# Install ksh
pkg intsall loksh



# Follow instructions in `RC File Variables` section of README.md to fix `rc` files.
sed -i'' -E 's/^(PS1=.*)$/\(\[ -z "\$PS1" \] \|\| \[\[ "\$PS1" == '\''\\s-\\v\\\$ '\'' \]\]\) \&\& \1/' "${TERMUX__PREFIX:-$PREFIX}/etc/bash.bashrc"
sed -i'' -E 's/^(PS1=.*)$/\(\[ -z "\$PS1" \] \|\| \[\[ "\$PS1" == '\''%m%# '\'' \]\]\) \&\& \1/' "${TERMUX__PREFIX:-$PREFIX}/etc/zshrc"



# Finally run tests

# Run all tests
bash ~/tudo_tests -vv

# Run only script command type tests
bash ~/tudo_tests -vv script

# Run only script command type bash shell test 1
bash ~/tudo_tests -vv script bash 1

# Run only script command type bash shell test 1 with tudo log level 'VERBOSE'
TUDO__LOG_LEVEL=3 bash ~/tudo_tests -vv script bash 1

# For some tests **sometimes** where *-stdin-string option is used to pass a string to an interactive shell using stdin,
# the stdout may be returned in an unsynchronized manner which fails the validation
# If that happens, just rerun the test and it should ideally work
# This is also the reason why su and asu tests use matches instead of equality checks, some script type tests still use exact matches

TUDO_TESTS_HELP_EXTRA
)"



### Set Default Variables Start

TUDO_TESTS_MAX_LOG_LEVEL=5 # Default: `5` (VVVERBOSE=5)
# shellcheck disable=SC2153
TUDO_TESTS_LOG_LEVEL="$TUDO_TESTS__LOG_LEVEL"
{ [[ ! "$TUDO_TESTS_LOG_LEVEL" =~ ^[0-9]+$ ]] || [[ "$TUDO_TESTS_LOG_LEVEL" -gt "$TUDO_TESTS_MAX_LOG_LEVEL" ]]; } && \
TUDO_TESTS_LOG_LEVEL=1 # Default: `1` (OFF=0, NORMAL=1, DEBUG=2, VERBOSE=3, VVERBOSE=4 and VVVERBOSE=5)
TUDO_TESTS_LOG_ARGS="${TUDO_TESTS__LOG_ARGS:-0}" # Default: `0` (Export or manually set to `1` if you want to debug arguments received)

TUDO_TESTS_COMMAND_TYPE="" # Default: ``
TUDO_TESTS_NOOP_COMMAND=0 # Default: `0`
TUDO_TESTS_ONLY_BASH_TESTS=0 # Default: `0`
TUDO_TESTS_PREVIOUS_TEMP_TEST_SHELL="" # Default: ``
TUDO_TESTS_PREVIOUS_TEST_SHELL="" # Default: ``
TUDO_TESTS_PREVIOUS_TEST_NUMBER="" # Default: ``
TUDO_TESTS_CURRENT_TEST_SHELL="" # Default: ``
TUDO_TESTS_CURRENT_TEST_NUMBER="" # Default: ``
TUDO_TESTS_USER_TEST_SHELL="" # Default: ``
TUDO_TESTS_USER_TEST_NUMBER="" # Default: ``

TUDO_TESTS_TEMP_DIRECTORY_SUFFIX="" # Default: ``

declare -ga TUDO_TESTS_DIRECTORIES=()

# Set regexes for validation
VALID_NUMBER_REGEX='^[0-9]+$'
VALID_ABSOLUTE_PATH_REGEX='^(/[^/]+)+$'

### Set Default Variables



function tudo_tests_log() { local log_level="${1}"; shift; if [[ $TUDO_TESTS_LOG_LEVEL -ge $log_level ]]; then echo "tudo-tests:" "$@"; fi }
function tudo_tests_log_no_tag() { local log_level="${1}"; shift; if [[ $TUDO_TESTS_LOG_LEVEL -ge $log_level ]]; then "$@"; fi }
function tudo_tests_log_literal() { local log_level="${1}"; shift; if [[ $TUDO_TESTS_LOG_LEVEL -ge $log_level ]]; then echo -e "tudo-tests:" "$@"; fi }
function tudo_tests_log_errors() { echo "tudo-tests:" "$@" 1>&2; }
function tudo_tests_log_args() { if [[ $TUDO_TESTS_LOG_ARGS == "1" ]]; then echo "tudo-tests:" "$@"; fi }
function tudo_tests_log_arg_errors() { echo "tudo-tests:" "$@" 1>&2; }

# stdin in closed for some tests as a patch to SuperSU automatic redirection of stderr to stdout when running in interactive mode
function close_stdin () {  if [ -t 0 ]; then exec <&-; fi }
function reopen_stdin () {  if [[ "$TUDO_TESTS_TTY_PATH" == "/dev/"* ]]; then exec <"$TUDO_TESTS_TTY_PATH"; fi }



##
# `tudo_tests_main` [`<argument...>`]
##
tudo_tests_main() {

    local return_value

    # Find the tudo script path
    TUDO_SCRIPT_PATH="$(command -v tudo)"
    return_value=$?
    if [ $return_value -ne 0 ] || [[ ! "$TUDO_SCRIPT_PATH" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        tudo_log_errors "Failure while finding TUDO_SCRIPT_PATH"
        tudo_log_errors "TUDO_SCRIPT_PATH='$TUDO_SCRIPT_PATH'"
        if [ $return_value -eq 0 ]; then
            return_value=1
        fi
        return $return_value
    fi

    # Source the tudo script
    if [ ! -x "$TUDO_SCRIPT_PATH" ]; then
        tudo_tests_log_errors "The TUDO_SCRIPT_PATH '$TUDO_SCRIPT_PATH' found is not executable"
        return 1
    else
        # shellcheck source=tudo
        source "$TUDO_SCRIPT_PATH" || return $?
        tudo_set_termux_env_variables || return $?
        tudo_set_tudo_default_variables || return $?
    fi

    local -a TUDO_TESTS_REQUIRED_VARIABLES_ARRAY=(
        TERMUX_ROOTFS
        TERMUX_PREFIX
        TERMUX_HOME
        TERMUX_LD_LIBRARY_PATH
    )

    local var

    for var in "${TUDO_TESTS_REQUIRED_VARIABLES_ARRAY[@]}"; do
        # If var is not set
        if [ -z "${!var}" ]; then
            tudo_tests_log_errors "The required variable '$var' for tudo_tests is not set"
            return 1
        fi
    done


    # Set pre required variables to be used by this script
    tudo_tests_set_pre_required_variables || return $?


    # Process the command arguments passed to the script
    tudo_tests_process_script_arguments "$@" || return $?

    [ "$TUDO_TESTS_NOOP_COMMAND" = "1" ] && return 0

    tudo_tests_run || return $?

}

tudo_tests_run() {

    local return_value

    # Set required variables to be used by this script
    tudo_tests_set_required_variables || return $?


    cd "$TUDO_TESTS_WORKING_DIR"

    local tests_start_time
    local tests_end_time
    tests_start_time="$(date "+%s")" || return $?

    # Run tests
    if [ -z "$TUDO_TESTS_COMMAND_TYPE" ]; then
        tudo_tests_log 1 "Running 'tudo' tests"
        tudo_tests_log 5 $'\n\n'; tudo_tests_run_su_tests || return $?
        tudo_tests_log 5 $'\n\n'; tudo_tests_run_asu_tests || return $?
        tudo_tests_log 5 $'\n\n'; tudo_tests_run_path_tests || return $?
        tudo_tests_log 5 $'\n\n'; tudo_tests_run_script_tests || return $?
    elif [[ "$TUDO_TESTS_COMMAND_TYPE" != *,* ]] && [[ ",su,asu,path,script," == *",$TUDO_TESTS_COMMAND_TYPE,"* ]]; then
        tudo_tests_run_"${TUDO_TESTS_COMMAND_TYPE,,}"_tests || return $?
    else
        tudo_tests_log_errors "Unknown tests command type $TUDO_TESTS_COMMAND_TYPE"
        tudo_tests_show_help
        return 1
    fi

    tests_end_time=$(($(date "+%s") - tests_start_time)) || return $?
    tudo_tests_log 5 $'\n\n'
    tudo_tests_log 1 "All 'tudo' tests successful in \
$((tests_end_time / 3600 )) hours $(((tests_end_time % 3600) / 60)) minutes $((tests_end_time % 60)) seconds"

    return 0

}



tudo_tests_set_pre_required_variables() {

    local return_value

    # Find android sdk/os version
    # Termux app exports ANDROID__BUILD_VERSION_SDK for `>= v0.119.0`
    if [[ ! "$ANDROID__BUILD_VERSION_SDK" =~ $VALID_NUMBER_REGEX ]]; then
        ANDROID__BUILD_VERSION_SDK="$(unset LD_LIBRARY_PATH; unset LD_PRELOAD; getprop "ro.build.version.sdk")"
        return_value=$?
        if [ $return_value -ne 0 ] || [[ ! "$ANDROID__BUILD_VERSION_SDK" =~ $VALID_NUMBER_REGEX ]]; then
            tudo_tests_log_errors "Failure while finding 'ro.build.version.sdk' property"
            tudo_tests_log_errors "ANDROID__BUILD_VERSION_SDK='$ANDROID__BUILD_VERSION_SDK'"
            if [ $return_value -eq 0 ]; then
                return_value=1
            fi
            return $return_value
        fi
    fi

    tudo_tests_log 5 "ANDROID__BUILD_VERSION_SDK='$ANDROID__BUILD_VERSION_SDK'"



    # Set LD_LIBRARY_PATH for all external commands that may be run
    # If on Android `< 7`
    if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ]; then
        # Set only termux library paths
        LD_LIBRARY_PATH="$TERMUX_LD_LIBRARY_PATH"
    else
        # Do not set termux or android library paths
        LD_LIBRARY_PATH=""
    fi

    tudo_tests_log 5 "LD_LIBRARY_PATH='$LD_LIBRARY_PATH'"

    return 0

}

tudo_tests_set_required_variables() {

    local return_value

    if [ -t 0 ]; then
        TUDO_TESTS_TTY_PATH="$(tty 2>/dev/null)"
    fi


    # Set `SU_BIN_PATH` as its used in `ANDROID_PATH` when `tudo_set_path_priority_variables()` is called.
    tudo_set_su_variables || return $?


    # Set TUDO_TESTS_WORKING_DIR to use for tests
    TUDO_TESTS_WORKING_DIR="$TERMUX_HOME"

    # Generate unique suffix to use for tudo_tests directories
    TUDO_TESTS_TEMP_DIRECTORY_SUFFIX="$(mktemp -d --dry-run tudo.XXXXXX)"
    return_value=$?
    if [ $return_value -ne 0 ] || [[ ! "$TUDO_TESTS_TEMP_DIRECTORY_SUFFIX" =~  ^tudo\.......$ ]]; then
        tudo_tests_log_errors "Failure while running mktemp to create TUDO_TESTS_TEMP_DIRECTORY_SUFFIX"
        tudo_tests_log_errors "TUDO_TESTS_TEMP_DIRECTORY_SUFFIX='$TUDO_TESTS_TEMP_DIRECTORY_SUFFIX'"
        if [ $return_value -eq 0 ]; then
            return_value=1
        fi
        return $return_value
    fi

    TUDO_SHELL_HOME="$TUDO_TESTS_WORKING_DIR/.shell_home.$TUDO_TESTS_TEMP_DIRECTORY_SUFFIX"
    TUDO_POST_SHELL_HOME="$TUDO_TESTS_WORKING_DIR/.post_shell_home.$TUDO_TESTS_TEMP_DIRECTORY_SUFFIX"

    export TUDO__SHELL_HOME="$TUDO_SHELL_HOME"
    export TUDO__POST_SHELL_HOME="$TUDO_POST_SHELL_HOME"

    TUDO_SHELL_HOME_BASENAME="${TUDO_SHELL_HOME##*/}" # Strip longest match of */ from start
    TUDO_POST_SHELL_HOME_BASENAME="${TUDO_POST_SHELL_HOME##*/}" # Strip longest match of */ from start

    TUDO_TESTS_DIRECTORIES+=("$TUDO_SHELL_HOME")
    TUDO_TESTS_DIRECTORIES+=("$TUDO_POST_SHELL_HOME")



    if [[ -z "$TERMUX_EXEC__PROC_SELF_EXE" ]]; then
        PROC_SELF_EXE_COMMAND='readlink -f /proc/$$/exe'
        PROC_SELF_EXE_COMMAND_FISH='readlink -f /proc/$fish_pid/exe'
    else
        PROC_SELF_EXE_COMMAND='echo "$TERMUX_EXEC__PROC_SELF_EXE"'
        PROC_SELF_EXE_COMMAND_FISH='echo "$TERMUX_EXEC__PROC_SELF_EXE"'
    fi



    # Set traps to run commands before exiting tudo_tests
    trap 'tudo_tests_cleanup' EXIT
    trap 'tudo_tests_cleanup TERM' TERM
    trap 'tudo_tests_cleanup INT' INT
    trap 'tudo_tests_cleanup HUP' HUP
    trap 'tudo_tests_cleanup QUIT' QUIT

    return 0

}



tudo_tests_run_su_tests() {

    local return_value

    TUDO_TESTS_COMMAND_TYPE="su"
    tudo_tests_log 2 "Start '$TUDO_TESTS_COMMAND_TYPE' tests"



    # Run bash tests

    set_tudo_tests_current_test_shell "bash"
    shell="bash"

    run_tudo_test 1 && \
    output="$(tudo --dry-run --shell-stdin-string='cd "$HOME"; pwd; exit;' su)"
    validate_tudo_test 0 $? "$output" ""

    run_tudo_test 2 && \
    output="$(tudo --shell-stdin-string='cd "$HOME"; pwd; exit;' su)"
    validate_tudo_test 0 $? "$output" "*" "$TUDO_SHELL_HOME" "*"


    # If on Android `< 7`
    if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ]; then
        tudo_set_path_priority_variables "1"
        run_tudo_test 3 && \
        output="$(tudo --shell-stdin-string='echo "PATH=$PATH; LD_LIBRARY_PATH=$LD_LIBRARY_PATH; LD_PRELOAD=$LD_PRELOAD;"; exit;' su)"
        validate_tudo_test 0 $? "$output" "*" "PATH=$TERMUX_BIN:$TERMUX_BIN_APPLETS:$ANDROID_PATH; LD_LIBRARY_PATH=$TERMUX_LD_LIBRARY_PATH; LD_PRELOAD=$TERMUX_LD_PRELOAD;" "*"

        tudo_set_path_priority_variables "0"
        run_tudo_test 4 && \
        output="$(tudo -T --shell-stdin-string='echo "PATH=$PATH; LD_LIBRARY_PATH=$LD_LIBRARY_PATH; LD_PRELOAD=$LD_PRELOAD;"; exit;' su)"
        validate_tudo_test 0 $? "$output" "*" "PATH=$TERMUX_BIN; LD_LIBRARY_PATH=$TERMUX_LD_LIBRARY_PATH; LD_PRELOAD=$TERMUX_LD_PRELOAD;" "*"

        tudo_set_path_priority_variables "1"
        run_tudo_test 5 && \
        output="$(tudo -TT --shell-stdin-string='echo "PATH=$PATH; LD_LIBRARY_PATH=$LD_LIBRARY_PATH; LD_PRELOAD=$LD_PRELOAD;"; exit;' su)"
        validate_tudo_test 0 $? "$output" "*" "PATH=$TERMUX_BIN:$TERMUX_BIN_APPLETS; LD_LIBRARY_PATH=$TERMUX_LD_LIBRARY_PATH; LD_PRELOAD=$TERMUX_LD_PRELOAD;" "*"
    else
        tudo_set_path_priority_variables "1"
        run_tudo_test 3 && \
        output="$(tudo --shell-stdin-string='echo "PATH=$PATH; LD_LIBRARY_PATH=$LD_LIBRARY_PATH; LD_PRELOAD=$LD_PRELOAD;"; exit;' su)"
        validate_tudo_test 0 $? "$output" "*" "PATH=$TERMUX_BIN:$TERMUX_BIN_APPLETS:$ANDROID_PATH; LD_LIBRARY_PATH=; LD_PRELOAD=$TERMUX_LD_PRELOAD;" "*"

        tudo_set_path_priority_variables "0"
        run_tudo_test 4 && \
        output="$(tudo -T --shell-stdin-string='echo "PATH=$PATH; LD_LIBRARY_PATH=$LD_LIBRARY_PATH; LD_PRELOAD=$LD_PRELOAD;"; exit;' su)"
        validate_tudo_test 0 $? "$output" "*" "PATH=$TERMUX_BIN; LD_LIBRARY_PATH=; LD_PRELOAD=$TERMUX_LD_PRELOAD;" "*"

        tudo_set_path_priority_variables "1"
        run_tudo_test 5 && \
        output="$(tudo -TT --shell-stdin-string='echo "PATH=$PATH; LD_LIBRARY_PATH=$LD_LIBRARY_PATH; LD_PRELOAD=$LD_PRELOAD;"; exit;' su)"
        validate_tudo_test 0 $? "$output" "*" "PATH=$TERMUX_BIN:$TERMUX_BIN_APPLETS; LD_LIBRARY_PATH=; LD_PRELOAD=$TERMUX_LD_PRELOAD;" "*"
    fi


    tudo_tests_log 5 $'\n\n'
    tudo_tests_log 2 "End '$TUDO_TESTS_COMMAND_TYPE' tests"

    return 0

}

tudo_tests_run_asu_tests() {

    local return_value

    TUDO_TESTS_COMMAND_TYPE="asu"
    tudo_tests_log 2 "Start '$TUDO_TESTS_COMMAND_TYPE' tests"



    # Run bash tests

    set_tudo_tests_current_test_shell "bash"
    shell="bash"

    run_tudo_test 1 && \
    output="$(tudo --dry-run --shell-stdin-string='cd "$HOME"; pwd; exit;' asu)"
    validate_tudo_test 0 $? "$output" ""

    run_tudo_test 2 && \
    output="$(tudo --shell-stdin-string='cd "$HOME"; pwd; exit;' asu)"
    validate_tudo_test 0 $? "$output" "*" "$TUDO_SHELL_HOME" "*"


    # If on Android `< 7`
    if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ]; then
        tudo_set_path_priority_variables "1"
        run_tudo_test 3 && \
        output="$(tudo --shell-stdin-string='echo "PATH=$PATH; LD_LIBRARY_PATH=$LD_LIBRARY_PATH; LD_PRELOAD=$LD_PRELOAD;"; exit;' asu)"
        validate_tudo_test 0 $? "$output" "*" "PATH=$ANDROID_PATH:$TERMUX_BIN:$TERMUX_BIN_APPLETS; LD_LIBRARY_PATH=$TERMUX_LD_LIBRARY_PATH; LD_PRELOAD=;" "*"

        tudo_set_path_priority_variables "0"
        run_tudo_test 4 && \
        output="$(tudo -A --shell-stdin-string='echo "PATH=$PATH; LD_LIBRARY_PATH=$LD_LIBRARY_PATH; LD_PRELOAD=$LD_PRELOAD;"; exit;' asu)"
        validate_tudo_test 0 $? "$output" "*" "PATH=$SYS_BIN; LD_LIBRARY_PATH=; LD_PRELOAD=;" "*"

        tudo_set_path_priority_variables "1"
        run_tudo_test 5 && \
        output="$(tudo -AA --shell-stdin-string='echo "PATH=$PATH; LD_LIBRARY_PATH=$LD_LIBRARY_PATH; LD_PRELOAD=$LD_PRELOAD;"; exit;' asu)"
        validate_tudo_test 0 $? "$output" "*" "PATH=$ANDROID_PATH; LD_LIBRARY_PATH=; LD_PRELOAD=;" "*"
    else
        tudo_set_path_priority_variables "1"
        run_tudo_test 3 && \
        output="$(tudo --shell-stdin-string='echo "PATH=$PATH; LD_LIBRARY_PATH=$LD_LIBRARY_PATH; LD_PRELOAD=$LD_PRELOAD;"; exit;' asu)"
        validate_tudo_test 0 $? "$output" "*" "PATH=$ANDROID_PATH:$TERMUX_BIN:$TERMUX_BIN_APPLETS; LD_LIBRARY_PATH=; LD_PRELOAD=;" "*"

        tudo_set_path_priority_variables "0"
        run_tudo_test 4 && \
        output="$(tudo -A --shell-stdin-string='echo "PATH=$PATH; LD_LIBRARY_PATH=$LD_LIBRARY_PATH; LD_PRELOAD=$LD_PRELOAD;"; exit;' asu)"
        validate_tudo_test 0 $? "$output" "*" "PATH=$SYS_BIN; LD_LIBRARY_PATH=; LD_PRELOAD=;" "*"

        tudo_set_path_priority_variables "1"
        run_tudo_test 5 && \
        output="$(tudo -AA --shell-stdin-string='echo "PATH=$PATH; LD_LIBRARY_PATH=$LD_LIBRARY_PATH; LD_PRELOAD=$LD_PRELOAD;"; exit;' asu)"
        validate_tudo_test 0 $? "$output" "*" "PATH=$ANDROID_PATH; LD_LIBRARY_PATH=; LD_PRELOAD=;" "*"
    fi


    tudo_tests_log 5 $'\n\n'
    tudo_tests_log 2 "End '$TUDO_TESTS_COMMAND_TYPE' tests"

    return 0
}

tudo_tests_run_path_tests() {

    local return_value

    TUDO_TESTS_COMMAND_TYPE="path"
    tudo_tests_log 2 "Start '$TUDO_TESTS_COMMAND_TYPE' tests"



    # Run bash tests

    set_tudo_tests_current_test_shell "bash"
    shell="bash"

    if [ -x "$TERMUX_HOME/.termux/tasker/termux_tasker_basic_bash_test" ]; then
        run_tudo_test 1 && \
        output="$(tudo "$TERMUX_HOME/.termux/tasker/termux_tasker_basic_bash_test" "$shell" "shell")"
        validate_tudo_test 0 $? "$output" "\$1=\`$shell\`"$'\n'"\$2=\`shell\`"

        run_tudo_test 2 && \
        output="$(tudo '~/.termux/tasker/termux_tasker_basic_bash_test' "$shell" "shell")"
        validate_tudo_test 0 $? "$output" "\$1=\`$shell\`"$'\n'"\$2=\`shell\`"

        run_tudo_test 3 && \
        output="$(cd "$TERMUX_HOME"; tudo './.termux/tasker/termux_tasker_basic_bash_test' "$shell" "shell")"
        validate_tudo_test 0 $? "$output" "\$1=\`$shell\`"$'\n'"\$2=\`shell\`"

        run_tudo_test 4 && \
        output="$(cd "$TERMUX_HOME/.termux/tasker"; tudo './termux_tasker_basic_bash_test' "$shell" "shell")"
        validate_tudo_test 0 $? "$output" "\$1=\`$shell\`"$'\n'"\$2=\`shell\`"

        run_tudo_test 5 && \
        output="$(cd "$TERMUX_HOME/.termux/tasker"; tudo '../tasker/termux_tasker_basic_bash_test' "$shell" "shell")"
        validate_tudo_test 0 $? "$output" "\$1=\`$shell\`"$'\n'"\$2=\`shell\`"
    else
        skip_tudo_test 1
        skip_tudo_test 2
        skip_tudo_test 3
        skip_tudo_test 4
        skip_tudo_test 5
    fi



    run_tudo_test 6 && \
    output="$(tudo ps -e -o cmd | grep "$TERMUX_PREFIX/bin/ps")"
    validate_tudo_test 0 $? "$output" "*" "$TERMUX_PREFIX/bin/ps -e -o cmd" "*"



    run_tudo_test 7 && \
    output="$(tudo getprop "ro.build.version.sdk")"
    validate_tudo_test 0 $? "$output" "$ANDROID__BUILD_VERSION_SDK"



    run_tudo_test 8 && \
    output="$(tudo -r echo "$COMMA_ALTERNATIVE")"
    validate_tudo_test 0 $? "$output" ","



    tudo_tests_log 5 $'\n\n'
    tudo_tests_log 2 "End '$TUDO_TESTS_COMMAND_TYPE' tests"

    return 0

}

tudo_tests_run_script_tests() {

    local return_value

    TUDO_TESTS_COMMAND_TYPE="script"
    tudo_tests_log 2 "Start '$TUDO_TESTS_COMMAND_TYPE' tests"



    ### Run bash tests

    set_tudo_tests_current_test_shell "bash"
    shell="bash"


    run_tudo_test 1 && \
    output="$(tudo -s --dry-run 'cd "$HOME"; pwd;')"
    validate_tudo_test 0 $? "$output" ""

    run_tudo_test 2 && \
    output="$(tudo -s 'cd "$HOME"; pwd;')"
    validate_tudo_test 0 $? "$output" "$TUDO_SHELL_HOME"

    run_tudo_test 3 && \
    output="$(cd "$TUDO_TESTS_WORKING_DIR"; tudo -s --shell-home="./$TUDO_SHELL_HOME_BASENAME" 'cd "$HOME"; pwd;')"
    validate_tudo_test 0 $? "$output" "$TUDO_SHELL_HOME"

    run_tudo_test 4 && \
    output="$(cd "$TUDO_TESTS_WORKING_DIR"; tudo -s --shell-home="$TUDO_SHELL_HOME_BASENAME" 'cd "$HOME"; pwd;')"
    validate_tudo_test 0 $? "$output" "$TUDO_SHELL_HOME"

    run_tudo_test 5 && \
    output="$(tudo -si --post-shell-home="$TUDO_POST_SHELL_HOME" --post-shell-stdin-string='exit' --post-shell-pre-commands='cd "$HOME"; pwd;')"
    validate_tudo_test 0 $? "$output" "" "$TUDO_POST_SHELL_HOME" "*"



    run_tudo_test 6 && \
    output="$(tudo -s "$PROC_SELF_EXE_COMMAND")"
    validate_tudo_test 0 $? "$output" "$TERMUX_PREFIX/bin/bash"

    run_tudo_test 7 && \
    output="$(tudo -s --shell="$TERMUX_PREFIX/bin/bash" "$PROC_SELF_EXE_COMMAND")"
    validate_tudo_test 0 $? "$output" "$TERMUX_PREFIX/bin/bash"

    run_tudo_test 8 && \
    output="$(tudo -si --post-shell-stdin-string="$PROC_SELF_EXE_COMMAND; exit;")"
    validate_tudo_test 0 $? "$output" "$TERMUX_PREFIX/bin/bash"

    run_tudo_test 9 && \
    output="$(tudo -si --post-shell="$TERMUX_PREFIX/bin/bash" --post-shell-stdin-string="$PROC_SELF_EXE_COMMAND; exit;")"
    validate_tudo_test 0 $? "$output" "$TERMUX_PREFIX/bin/bash"



    run_tudo_test 10 && \
    output="$(tudo -s --shell="$shell" <(cat <<'TUDO_EOF'
echo "Hi, $1 $2."
TUDO_EOF
) "$shell" "shell"
    )"
    validate_tudo_test 0 $? "$output" "Hi, $shell shell."



    run_tudo_test 11 && \
    output="$(tudo -s --shell="$shell" --shell-stdin-string="$shell" '
echo '\''What is your name?'\''
read name
echo "Hi, $name."
'
    )"
    validate_tudo_test 0 $? "$output" "What is your name?"$'\n'"Hi, $shell."



    run_tudo_test 12 && \
    output="$(tudo -sd --shell="$shell" '
echo '\''What is your name?'\''
read name
echo "Hi, $name."
'
    )"
    validate_tudo_test 0 $? "$output" "What is your name?"$'\n'"Hi, ."



    run_tudo_test 13 && \
    output="$(tudo -so --shell="$shell" --shell-stdin-string="$shell" '
echo '\''What is your name?'\''
read name
echo "Hi, $name." 1>&2
'
    )"
    validate_tudo_test 0 $? "$output" "What is your name?"$'\n'"Hi, $shell."



    run_tudo_test 14 && \
    output="$(tudo -sf 'echo "Running $1 $2 script: $(basename "$0")"' "$shell" "shell")"
    validate_tudo_test 0 $? "$output" "Running $shell shell script: tudo_script__core_script"


    run_tudo_test 15 && \
    output="$(tudo -sf --script-name="tudo_script__core_script_custom" 'echo "Running $1 $2 script: $(basename "$0")"' "$shell" "shell")"
    validate_tudo_test 0 $? "$output" "Running $shell shell script: tudo_script__core_script_custom"



    if [ -x "$TERMUX_HOME/.termux/tasker/termux_tasker_basic_bash_test" ]; then
        run_tudo_test 16 && \
        output="$(tudo -sF '~/.termux/tasker/termux_tasker_basic_bash_test' "$shell" "shell")"
        validate_tudo_test 0 $? "$output" "\$1=\`$shell\`"$'\n'"\$2=\`shell\`"
    else
        skip_tudo_test 16
    fi


    if [ -x "$TERMUX_PREFIX/bin/tasker_config_utils" ]; then
        run_tudo_test 17 && \
        output="$(tudo -s --script-name="tasker_config_utils" <(cat "$TERMUX_PREFIX/bin/tasker_config_utils") --help 1>/dev/null)"
        validate_tudo_test 0 $? "$output"
    else
        skip_tudo_test 17
    fi


    if [ -x "$TERMUX_PREFIX/bin/tasker_config_utils" ]; then
        run_tudo_test 18 && \
        output="$(tudo -sf --script-name="tasker_config_utils" <(cat "$TERMUX_PREFIX/bin/tasker_config_utils") --help 1>/dev/null)"
        validate_tudo_test 0 $? "$output"
    else
        skip_tudo_test 18
    fi





    run_tudo_test 19 && \
    output="$(tudo -s --shell-pre-commands='
export VARIABLE_1="VARIABLE_VALUE_1"
export VARIABLE_2="VARIABLE_VALUE_2"
' '
echo "Hi, $1 $2."
echo "VARIABLE_1=\`$VARIABLE_1\`"
echo "VARIABLE_2=\`$VARIABLE_2\`"
' "$shell" "shell"
    )"
    validate_tudo_test 0 $? "$output" "Hi, $shell shell."$'\n'"VARIABLE_1=\`VARIABLE_VALUE_1\`"$'\n'"VARIABLE_2=\`VARIABLE_VALUE_2\`"



    run_tudo_test 20 && \
    output="$(tudo -si --post-shell-stdin-string='exit' --shell-pre-commands='echo "Start script"' --shell-post-commands='echo "Exited script"' --post-shell-pre-commands='echo "Starting interactive shell"' --post-shell-post-commands='echo "Exited interactive shell"' 'echo "Hi, $1 $2."' "$shell" "shell")"
    validate_tudo_test 0 $? "$output" "Start script"$'\n'"Hi, $shell shell."$'\n'"Exited script"$'\n'"Starting interactive shell"$'\n'"Exited interactive shell"





    tudo_test_temp_work_dir="$TUDO_TESTS_WORKING_DIR/work_dir.$TUDO_TESTS_TEMP_DIRECTORY_SUFFIX"
    TUDO_TESTS_DIRECTORIES+=("$tudo_test_temp_work_dir")

    run_tudo_test 21 && \
    output="$(tudo -s --work-dir="$tudo_test_temp_work_dir" 'pwd' 2>&1)"
    return_value=$?
    validate_tudo_test 0 $return_value "$output" "$tudo_test_temp_work_dir"

    run_tudo_test 22 && \
    output="$(tudo -s --work-dir='~/work_dir.'"$TUDO_TESTS_TEMP_DIRECTORY_SUFFIX" 'pwd' 2>&1)"
    return_value=$?
    validate_tudo_test 0 $return_value "$output" "$tudo_test_temp_work_dir"

    run_tudo_test 23 && \
    output="$(cd "$TUDO_TESTS_WORKING_DIR"; tudo -s --work-dir="./work_dir.$TUDO_TESTS_TEMP_DIRECTORY_SUFFIX" 'pwd' 2>&1)"
    return_value=$?
    validate_tudo_test 0 $return_value "$output" "$tudo_test_temp_work_dir"

    run_tudo_test 24 && \
    output="$(cd "$TUDO_TESTS_WORKING_DIR"; tudo -s --work-dir="work_dir.$TUDO_TESTS_TEMP_DIRECTORY_SUFFIX" 'pwd' 2>&1)"
    return_value=$?
    validate_tudo_test 0 $return_value "$output" "$tudo_test_temp_work_dir"

    run_tudo_test 25 && \
    output="$(tudo -s --work-dir="/" 'pwd' 2>&1)"
    return_value=$?
    validate_tudo_test 0 $return_value "$output" "/"

    run_tudo_test 26 && \
    output="$(tudo -s --work-dir="/system" 'pwd' 2>&1)"
    return_value=$?
    validate_tudo_test 0 $return_value "$output" "/system"





    # Redirect stderr to stdout, same as `--script-redirect=0`
    close_stdin
    run_tudo_test 27 && \
    tudo_tests_run_subshell_command stdout stderr tudo -so --shell="$shell" 'echo stdout; echo stderr 1>&2'
    return_value=$?
    reopen_stdin
    validate_tudo_test 0 $return_value "$stdout" "stdout"$'\n'"stderr"
    validate_tudo_test 0 $return_value "$stderr" ""

    # Redirect stdout to stderr, same as `--script-redirect=1`
    close_stdin
    run_tudo_test 28 && \
    tudo_tests_run_subshell_command stdout stderr tudo -sO --shell="$shell" 'echo stdout; echo stderr 1>&2'
    return_value=$?
    reopen_stdin
    validate_tudo_test 0 $return_value "$stdout" ""
    validate_tudo_test 0 $return_value "$stderr" "stdout"$'\n'"stderr"

    # Redirect redirect stdout to /dev/null
    close_stdin
    run_tudo_test 29 && \
    tudo_tests_run_subshell_command stdout stderr tudo -s --script-redirect=2 --shell="$shell" 'echo stdout; echo stderr 1>&2'
    return_value=$?
    reopen_stdin
    validate_tudo_test 0 $return_value "$stdout" ""
    validate_tudo_test 0 $return_value "$stderr" "stderr"

    # Redirect stderr to /dev/null for core_script, same as `--script-redirect=3`
    close_stdin
    run_tudo_test 30 && \
    tudo_tests_run_subshell_command stdout stderr tudo -sn --shell="$shell" 'echo stdout; echo stderr 1>&2'
    return_value=$?
    reopen_stdin
    validate_tudo_test 0 $return_value "$stdout" "stdout"
    validate_tudo_test 0 $return_value "$stderr" ""

    # Redirect both stdout and stderr to /dev/null, same as `--script-redirect=4`
    close_stdin
    run_tudo_test 31 && \
    tudo_tests_run_subshell_command stdout stderr tudo -sN --shell="$shell" 'echo stdout; echo stderr 1>&2'
    return_value=$?
    reopen_stdin
    validate_tudo_test 0 $return_value "$stdout" ""
    validate_tudo_test 0 $return_value "$stderr" ""

    # Redirect stderr to stdout and redirect stdout to stderr
    close_stdin
    run_tudo_test 32 && \
    tudo_tests_run_subshell_command stdout stderr tudo -s --script-redirect=5 --shell="$shell" 'echo stdout; echo stderr 1>&2'
    return_value=$?
    reopen_stdin
    validate_tudo_test 0 $return_value "$stdout" "stderr"
    validate_tudo_test 0 $return_value "$stderr" "stdout"

    # Redirect stderr to stdout and redirect stdout to /dev/null
    close_stdin
    run_tudo_test 33 && \
    tudo_tests_run_subshell_command stdout stderr tudo -s --script-redirect=6 --shell="$shell" 'echo stdout; echo stderr 1>&2'
    return_value=$?
    reopen_stdin
    validate_tudo_test 0 $return_value "$stdout" "stderr"
    validate_tudo_test 0 $return_value "$stderr" ""



    close_stdin
    run_tudo_test 34 && \
    tudo_tests_run_subshell_command stdout stderr tudo -sie --post-shell-stdin-string='exit' --shell="$shell" <(cat <<'TUDO_EOF'
# If argument count is not 2
if [ $# -ne 2 ]; then
        echo "Invalid argument count '$#' to 'termux_tasker_basic_bash_test'" 1>&2
        echo "$*" 1>&2
        exit 1
fi

echo "\$1=\`$1\`"
echo "\$2=\`$2\`"

exit 0
TUDO_EOF
) "$shell"
    return_value=$?
    reopen_stdin
    validate_tudo_test 1 $return_value "$stdout" ""
    validate_tudo_test 1 $return_value "$stderr" "Invalid argument count '1' to 'termux_tasker_basic_bash_test'"$'\n'"$shell"





    run_tudo_test 35 && \
    output="$(tudo -s --shell=bas 'echo "Hi, $1 $2."' "$shell" "shell" 2>&1)"
    validate_tudo_test 1 $? "$output" "" "The TUDO_SHELL 'bas' is not supported. It must be one of" "*"



    run_tudo_test 36 && \
    output="$(tudo -si --post-shell=bas 'echo "Hi, $1 $2."' "$shell" "shell" 2>&1)"
    validate_tudo_test 1 $? "$output" "" "The TUDO_POST_SHELL 'bas' is not supported. It must be one of" "*"



    run_tudo_test 37 && \
    output="$(tudo -s --shell-home='~/.config' 'echo "Hi, $1 $2."' "$shell" "shell" 2>&1)"
    validate_tudo_test 1 $? "$output" "" "The '$TERMUX_HOME/.config' cannot be used as TUDO_SHELL_HOME" "*"



    run_tudo_test 38 && \
    output="$(tudo -s --shell-home='$PREFIX/' 'echo "Hi, $1 $2."' "$shell" "shell" 2>&1)"
    validate_tudo_test 1 $? "$output" "" "The '$TERMUX_PREFIX' cannot be used as TUDO_SHELL_HOME" "*"



    run_tudo_test 39 && \
    output="$(tudo -s --shell-home='$PREFIX/home' 'echo "Hi, $1 $2."' "$shell" "shell" 2>&1)"
    validate_tudo_test 1 $? "$output" "" "The '$TERMUX_PREFIX/home' cannot be used as TUDO_SHELL_HOME" "*"



    run_tudo_test 40 && \
    output="$(tudo -s --shell-home='/data' 'echo "Hi, $1 $2."' "$shell" "shell" 2>&1)"
    validate_tudo_test 1 $? "$output" "" "The TUDO_SHELL_HOME '/data' must be an absolute path under TERMUX_ROOTFS '$TERMUX_ROOTFS'" "*"



    run_tudo_test 41 && \
    output="$(tudo -si --post-shell-home='~/.config' 'echo "Hi, $1 $2."' "$shell" "shell" 2>&1)"
    validate_tudo_test 1 $? "$output" "" "The '$TERMUX_HOME/.config' cannot be used as TUDO_POST_SHELL_HOME" "*"



    run_tudo_test 42 && \
    output="$(tudo -si --post-shell-home='$PREFIX/' 'echo "Hi, $1 $2."' "$shell" "shell" 2>&1)"
    validate_tudo_test 1 $? "$output" "" "The '$TERMUX_PREFIX' cannot be used as TUDO_POST_SHELL_HOME" "*"



    run_tudo_test 43 && \
    output="$(tudo -si --post-shell-home='$PREFIX/home' 'echo "Hi, $1 $2."' "$shell" "shell" 2>&1)"
    validate_tudo_test 1 $? "$output" "" "The '$TERMUX_PREFIX/home' cannot be used as TUDO_POST_SHELL_HOME" "*"



    run_tudo_test 44 && \
    output="$(tudo -si --post-shell-home='/data' 'echo "Hi, $1 $2."' "$shell" "shell" 2>&1)"
    validate_tudo_test 1 $? "$output" "" "The TUDO_POST_SHELL_HOME '/data' must be an absolute path under TERMUX_ROOTFS '$TERMUX_ROOTFS'" "*"





    run_tudo_test 45 && \
    output="$(tudo -sr "[[ \",\" == \"$COMMA_ALTERNATIVE\" ]] && [[ "\$1" == \"$COMMA_ALTERNATIVE\" ]] && echo \"arg1 equals simple comma\"" "$COMMA_ALTERNATIVE")"
    validate_tudo_test 0 $? "$output" "arg1 equals simple comma"



    if [[ "$TUDO_TESTS_ONLY_BASH_TESTS" == "1" ]]; then
        return 0
    fi



    if [ -x "$TERMUX_PREFIX/bin/python" ]; then
        run_tudo_test 46 && \
        output="$(tudo -si --post-shell="python" --post-shell-stdin-string='exit(0)' 2>&1)"
        validate_tudo_test 0 $? "$output" "*" "Python" "*"
    fi





    ### Run zsh tests
    if [ -x "$TERMUX_PREFIX/bin/zsh" ]; then

        set_tudo_tests_current_test_shell "zsh"
        shell="zsh"


        run_tudo_test 1 && \
        output="$(tudo -s --shell="$shell" "$PROC_SELF_EXE_COMMAND")"
        validate_tudo_test 0 $? "$output" "$TERMUX_PREFIX/bin/zsh"



        run_tudo_test 2 && \
        output="$(tudo -s --shell="$shell" <(cat <<'TUDO_EOF'
echo "Hi, $1 $2."
TUDO_EOF
) "$shell" "shell"
        )"
        validate_tudo_test 0 $? "$output" "Hi, $shell shell."



        run_tudo_test 3 && \
        output="$(tudo -s --shell="$shell" --shell-stdin-string="$shell" <(cat <<'TUDO_EOF'
echo "What is your name?"
read name
echo "Hi, $name."
TUDO_EOF
)
        )"
        validate_tudo_test 0 $? "$output" "What is your name?"$'\n'"Hi, $shell."

    else
        tudo_tests_log 3 "Skipping zsh tests since its not installed"
    fi





    ### Run dash tests
    if [ -x "$TERMUX_PREFIX/bin/dash" ]; then

        set_tudo_tests_current_test_shell "dash"
        shell="dash"


        run_tudo_test 1 && \
        output="$(tudo -s --shell="$shell" <(cat <<'TUDO_EOF'
echo "Hi, $1 $2."
TUDO_EOF
) "$shell" "shell"
        )"
        validate_tudo_test 0 $? "$output" "Hi, $shell shell."



        run_tudo_test 2 && \
        output="$(tudo -s --shell="$shell" --shell-stdin-string="$shell" <(cat <<'TUDO_EOF'
echo "What is your name?"
read name
echo "Hi, $name."
TUDO_EOF
)
        )"
        validate_tudo_test 0 $? "$output" "What is your name?"$'\n'"Hi, $shell."

    else
        tudo_tests_log 3 "Skipping dash tests since its not installed"
    fi





    ### Run sh tests
    if [ -x "$TERMUX_PREFIX/bin/sh" ]; then

        set_tudo_tests_current_test_shell "sh"
        shell="sh"


        run_tudo_test 1 && \
        output="$(tudo -s --shell="$shell" <(cat <<'TUDO_EOF'
echo "Hi, $1 $2."
TUDO_EOF
) "$shell" "shell"
        )"
        validate_tudo_test 0 $? "$output" "Hi, $shell shell."



        run_tudo_test 2 && \
        output="$(tudo -s --shell="$shell" --shell-stdin-string="$shell" <(cat <<'TUDO_EOF'
echo "What is your name?"
read name
echo "Hi, $name."
TUDO_EOF
)
        )"
        validate_tudo_test 0 $? "$output" "What is your name?"$'\n'"Hi, $shell."

    else
        tudo_tests_log 3 "Skipping sh tests since its not installed"
    fi





    ### Run fish tests
    if [ -x "$TERMUX_PREFIX/bin/fish" ]; then

        set_tudo_tests_current_test_shell "fish"
        shell="fish"

        run_tudo_test 1 && \
        output="$(tudo -s --shell="$shell" "$PROC_SELF_EXE_COMMAND_FISH")"
        validate_tudo_test 0 $? "$output" "$TERMUX_PREFIX/bin/fish"


        run_tudo_test 2 && \
        output="$(tudo -s --shell="$shell" <(cat <<'TUDO_EOF'
echo "Hi, $argv[1] $argv[2]."
TUDO_EOF
) "$shell" "shell"
        )"
        validate_tudo_test 0 $? "$output" "Hi, $shell shell."



        run_tudo_test 3 && \
        output="$(tudo -s --shell="$shell" --shell-stdin-string="$shell" <(cat <<'TUDO_EOF'
echo "What is your name?"
read -p "" name
echo "Hi, $name."
TUDO_EOF
)
        )"
        validate_tudo_test 0 $? "$output" "What is your name?"$'\n'"Hi, $shell."

    else
        tudo_tests_log 3 "Skipping fish tests since its not installed"
    fi





    ### Run python tests
    if [ -x "$TERMUX_PREFIX/bin/python" ]; then

        set_tudo_tests_current_test_shell "python"
        shell="python"


        run_tudo_test 1 && \
        output="$(tudo -s --shell="$shell" <(cat <<'TUDO_EOF'
import sys
print("Hi, %s %s." % (sys.argv[1], sys.argv[2]))
TUDO_EOF
) "$shell" "shell"
        )"
        validate_tudo_test 0 $? "$output" "Hi, $shell shell."



        run_tudo_test 2 && \
        output="$(tudo -s --shell="$shell" --shell-stdin-string="$shell" <(cat <<'TUDO_EOF'
name = input("What is your name?\n")
print("Hi, %s." % name)
TUDO_EOF
)
        )"
        validate_tudo_test 0 $? "$output" "What is your name?"$'\n'"Hi, $shell."


        if [ -x "$TERMUX_HOME/.termux/tasker/termux_tasker_basic_python_test" ]; then
            run_tudo_test 3 && \
            output="$(tudo '~/.termux/tasker/termux_tasker_basic_python_test' "$shell" "shell")"
            validate_tudo_test 0 $? "$output" "\$1=\`$shell\`"$'\n'"\$2=\`shell\`"
        else
            skip_tudo_test 3
        fi

        if [ -x "$TERMUX_PREFIX/bin/yt-dlp" ]; then
            run_tudo_test 4 && \
            output="$(tudo -s --shell=python --script-name="yt-dlp" <(cat "$TERMUX_PREFIX/bin/yt-dlp") --help 1>/dev/null)"
            validate_tudo_test 0 $? "$output"
        else
            skip_tudo_test 4
        fi

        if [ -x "$TERMUX_PREFIX/bin/yt-dlp" ]; then
            run_tudo_test 5 && \
            output="$(tudo -sF --shell=python "$TERMUX_PREFIX/bin/yt-dlp" --help 1>/dev/null)"
            validate_tudo_test 0 $? "$output"
        else
            skip_tudo_test 5
        fi

        if [ -x "$TERMUX_PREFIX/bin/bandcamp-dl" ]; then
            run_tudo_test 6 && \
            output="$(tudo -s --shell=python "$(cat "$TERMUX_PREFIX/bin/bandcamp-dl")" --help)"
            validate_tudo_test 0 $? "$output"
        else
            skip_tudo_test 6
        fi

        if [ -x "$TERMUX_PREFIX/bin/bandcamp-dl" ]; then
            run_tudo_test 7 && \
            output="$(tudo -s --script-decode --shell=python "$(cat "$TERMUX_PREFIX/bin/bandcamp-dl" | base64)" --help)"
            validate_tudo_test 0 $? "$output"
        else
            skip_tudo_test 7
        fi

    else
        tudo_tests_log 3 "Skipping python tests since its not installed"
    fi





    ### Run ruby tests
    if [ -x "$TERMUX_PREFIX/bin/ruby" ]; then

        set_tudo_tests_current_test_shell "ruby"
        shell="ruby"


        run_tudo_test 1 && \
        output="$(tudo -s --shell="$shell" <(cat <<'TUDO_EOF'
puts "Hi, " + ARGV[0] + " " + ARGV[1] + "."
TUDO_EOF
) "$shell" "shell"
        )"
        validate_tudo_test 0 $? "$output" "Hi, $shell shell."



        run_tudo_test 2 && \
        output="$(tudo -s --shell="$shell" --shell-stdin-string="$shell" <(cat <<'TUDO_EOF'
puts "What is your name?"
name = STDIN.gets
name = '' if name.nil?
puts "Hi, " + name.chomp.to_s + "."
TUDO_EOF
)
        )"
        validate_tudo_test 0 $? "$output" "What is your name?"$'\n'"Hi, $shell."

    else
        tudo_tests_log 3 "Skipping ruby tests since its not installed"
    fi





    ### Run node tests
    if [ -x "$TERMUX_PREFIX/bin/node" ]; then

        set_tudo_tests_current_test_shell "node"
        shell="node"


        run_tudo_test 1 && \
        output="$(tudo -s --shell="$shell" <(cat <<'TUDO_EOF'
console.log(`Hi, ${process.argv[2]} ${process.argv[3]}.`)
TUDO_EOF
) "$shell" "shell"
        )"
        validate_tudo_test 0 $? "$output" "Hi, $shell shell."



        run_tudo_test 2 && \
        output="$(tudo -s --shell="$shell" --shell-stdin-string="$shell" <(cat <<'TUDO_EOF'
const readline = require('readline').createInterface({
        input: process.stdin,
        output: process.stdout
})

readline.question(`What is your name?\n`, (name) => {
        console.log(`Hi, ${name}.`)
        readline.close()
})
TUDO_EOF
)
        )"
        validate_tudo_test 0 $? "$output" "*" "Hi, $shell." ""

    else
        tudo_tests_log 3 "Skipping node tests since its not installed"
    fi





    ### Run perl tests
    if [ -x "$TERMUX_PREFIX/bin/perl" ]; then

        set_tudo_tests_current_test_shell "perl"
        shell="perl"


        run_tudo_test 1 && \
        output="$(tudo -s --shell="$shell" <(cat <<'TUDO_EOF'
print "Hi, ", $ARGV[0], " ", $ARGV[1], ".\n";
TUDO_EOF
) "$shell" "shell"
        )"
        validate_tudo_test 0 $? "$output" "Hi, $shell shell."



        run_tudo_test 2 && \
        output="$(tudo -s --shell="$shell" --shell-stdin-string="$shell" <(cat <<'TUDO_EOF'
print "What is your name?\n";
$name = <STDIN>;
chomp($name);
print "Hi, ", $name, ".\n";
TUDO_EOF
)
        )"
        validate_tudo_test 0 $? "$output" "What is your name?"$'\n'"Hi, $shell."

    else
        tudo_tests_log 3 "Skipping perl tests since its not installed"
    fi





    ### Run lua5.2 tests
    if [ -x "$TERMUX_PREFIX/bin/lua5.2" ]; then

        set_tudo_tests_current_test_shell "lua5.2"
        shell="lua5.2"


        run_tudo_test 1 && \
        output="$(tudo -s --shell="$shell" <(cat <<'TUDO_EOF'
io.write('Hi, ', arg[1], ' ', arg[2], '.\n')
TUDO_EOF
) "$shell" "shell"
        )"
        validate_tudo_test 0 $? "$output" "Hi, $shell shell."



        run_tudo_test 2 && \
        output="$(tudo -s --shell="$shell" --shell-stdin-string="$shell" <(cat <<'TUDO_EOF'
io.write('What is your name?\n')
local name = io.read()
io.write('Hi, ', name, '.\n')
TUDO_EOF
)
        )"
        validate_tudo_test 0 $? "$output" "What is your name?"$'\n'"Hi, $shell."

    else
        tudo_tests_log 3 "Skipping lua5.2 tests since its not installed"
    fi





    ### Run lua5.3 tests
    if [ -x "$TERMUX_PREFIX/bin/lua5.3" ]; then

        set_tudo_tests_current_test_shell "lua5.3"
        shell="lua5.3"


        run_tudo_test 1 && \
        output="$(tudo -s --shell="$shell" <(cat <<'TUDO_EOF'
io.write('Hi, ', arg[1], ' ', arg[2], '.\n')
TUDO_EOF
) "$shell" "shell"
        )"
        validate_tudo_test 0 $? "$output" "Hi, $shell shell."



        run_tudo_test 2 && \
        output="$(tudo -s --shell="$shell" --shell-stdin-string="$shell" <(cat <<'TUDO_EOF'
io.write('What is your name?\n')
local name = io.read()
io.write('Hi, ', name, '.\n')
TUDO_EOF
)
        )"
        validate_tudo_test 0 $? "$output" "What is your name?"$'\n'"Hi, $shell."

    else
        tudo_tests_log 3 "Skipping lua5.3 tests since its not installed"
    fi





    ### Run lua5.4 tests
    if [ -x "$TERMUX_PREFIX/bin/lua5.4" ]; then

        set_tudo_tests_current_test_shell "lua5.4"
        shell="lua5.4"


        run_tudo_test 1 && \
        output="$(tudo -s --shell="$shell" <(cat <<'TUDO_EOF'
io.write('Hi, ', arg[1], ' ', arg[2], '.\n')
TUDO_EOF
) "$shell" "shell"
        )"
        validate_tudo_test 0 $? "$output" "Hi, $shell shell."



        run_tudo_test 1 && \
        output="$(tudo -s --shell="$shell" --shell-stdin-string="$shell" <(cat <<'TUDO_EOF'
io.write('What is your name?\n')
local name = io.read()
io.write('Hi, ', name, '.\n')
TUDO_EOF
)
        )"
        validate_tudo_test 0 $? "$output" "What is your name?"$'\n'"Hi, $shell."

    else
        tudo_tests_log 3 "Skipping lua5.4 tests since its not installed"
    fi





    ### Run php tests
    if [ -x "$TERMUX_PREFIX/bin/php" ]; then

        set_tudo_tests_current_test_shell "php"
        shell="php"


        run_tudo_test 1 && \
        output="$(tudo -s --shell="$shell" <(cat <<'TUDO_EOF'
<?php
echo "Hi, " . $argv[1] . " " . $argv[2] . ".\n";
TUDO_EOF
) "$shell" "shell"
        )"
        validate_tudo_test 0 $? "$output" "Hi, $shell shell."



        run_tudo_test 2 && \
        output="$(tudo -s --shell="$shell" --shell-stdin-string="$shell" <(cat <<'TUDO_EOF'
<?php
echo "What is your name?\n";
$name = readline();
echo "Hi, " . $name . ".\n";
TUDO_EOF
)
        )"
        validate_tudo_test 0 $? "$output" "What is your name?"$'\n'"php"$'\n'"Hi, $shell."

    else
        tudo_tests_log 3 "Skipping php tests since its not installed"
    fi



    tudo_tests_log 5 $'\n\n'
    tudo_tests_log 2 "End '$TUDO_TESTS_COMMAND_TYPE' tests"

    return 0

}

##
# Capture stdout and stderr of command in separate variables.
#
# `tudo_tests_run_subshell_command` `<stdout_variable_name>` `<stderr_variable_name>` `<command>` [`<arguments...>`]
##
tudo_tests_run_subshell_command() {

    local return_value

    local stdout_variable_name="$1";
    local stderr_variable_name="$2"
    shift 2

    local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'

    # If stdout_variable_name does equals "stdout_variable_name" and or is not a valid bash variable_name
    if [[ "$stdout_variable_name" == "stdout_variable_name" ]]|| [[ ! "$stdout_variable_name" =~ $valid_bash_variable_name_regex ]]; then
        tudo_tests_log_errors "stdout_variable_name '$1' passed to 'tudo_tests_run_subshell_command' equals 'stdout_variable_name' or is not a valid bash variable name"
        return 1
    fi

    # If stderr_variable_name does equals "stderr_variable_name" and or is not a valid bash variable_name
    if [[ "$stderr_variable_name" == "stderr_variable_name" ]]|| [[ ! "$stderr_variable_name" =~ $valid_bash_variable_name_regex ]]; then
        tudo_tests_log_errors "stderr_variable_name '$1' passed to 'tudo_tests_run_subshell_command' equals 'stderr_variable_name' or is not a valid bash variable name"
        return 1
    fi

    unset "$stdout_variable_name"
    unset "$stderr_variable_name"

    # Credits madmurphy https://stackoverflow.com/a/59592881/14686958

    # some_command is launched

    # We then have some_command's stdout on the descriptor 1,
    # some_command's stderr on the descriptor 2 and
    # some_command's exit code redirected to the descriptor 3

    # stdout is piped to tr (sanitization) to remove NUL

    # stderr is swapped with stdout (using temporarily the descriptor 4) and piped to tr (sanitization)

    # The exit code (descriptor 3) is swapped with stderr (now descriptor 1) and piped to exit $(cat)

    # stderr (now descriptor 3) is redirected to the descriptor 1, end expanded as the second argument of printf

    # The exit code of exit $(cat) is captured by the third argument of printf

    # The output of printf is redirected to the descriptor 2, where stdout was already present

    # The concatenation of stdout and the output of printf is piped to read

    # shellcheck disable=SC1102,SC1105
    {
        IFS=$'\n' read -r -d '' "$stdout_variable_name";
        IFS=$'\n' read -r -d '' "$stderr_variable_name";
        (IFS=$'\n' read -r -d '' return_value; return $return_value);
    } < <((printf '\0%s\0%d\0' "$(((({ "$@"; echo "$?" 1>&3-; } | tr -d '\0' 1>&4-) 4>&2- 2>&1- | tr -d '\0' 1>&4-) 3>&1- | exit "$(cat)") 4>&1-)" "$?" 1>&2) 2>&1)
    # Fix syntax highlight `{

}

set_tudo_tests_current_test_shell () {

    tudo_tests_log 3 "$1()"

    TUDO_TESTS_PREVIOUS_TEMP_TEST_SHELL="$TUDO_TESTS_CURRENT_TEST_SHELL";
    TUDO_TESTS_CURRENT_TEST_SHELL="$1"

}

set_tudo_tests_current_test_number () {

    # To handle the case when TUDO_TESTS_USER_TEST_NUMBER was the last test of a shell
    if [[ -n "$TUDO_TESTS_PREVIOUS_TEMP_TEST_SHELL" ]]; then
        TUDO_TESTS_PREVIOUS_TEST_SHELL="$TUDO_TESTS_PREVIOUS_TEMP_TEST_SHELL"
        TUDO_TESTS_PREVIOUS_TEMP_TEST_SHELL=""
    else
        TUDO_TESTS_PREVIOUS_TEST_SHELL="$TUDO_TESTS_CURRENT_TEST_SHELL"
    fi

    TUDO_TESTS_PREVIOUS_TEST_NUMBER="$TUDO_TESTS_CURRENT_TEST_NUMBER";
    TUDO_TESTS_CURRENT_TEST_NUMBER="$1";

    # If TUDO_TESTS_USER_TEST_SHELL and TUDO_TESTS_USER_TEST_NUMBER are set
    # and
    # TUDO_TESTS_PREVIOUS_TEST_SHELL equals TUDO_TESTS_USER_TEST_SHELL
    # and
    # TUDO_TESTS_PREVIOUS_TEST_NUMBER equals TUDO_TESTS_USER_TEST_NUMBER,
    # then exit
    if [ -n "$TUDO_TESTS_USER_TEST_SHELL" ] && [ -n "$TUDO_TESTS_USER_TEST_NUMBER" ] && \
            [[ "$TUDO_TESTS_PREVIOUS_TEST_SHELL" == "$TUDO_TESTS_USER_TEST_SHELL" ]] && \
                [[ "$TUDO_TESTS_PREVIOUS_TEST_NUMBER" == "$TUDO_TESTS_USER_TEST_NUMBER" ]]; then
        tudo_tests_log 5 $'\n\n'
        tudo_tests_log 1 "User 'tudo' test successful"
        exit 0
    fi

    # If TUDO_TESTS_USER_TEST_SHELL and TUDO_TESTS_USER_TEST_NUMBER are set
    # and
    # TUDO_TESTS_CURRENT_TEST_SHELL does not equal TUDO_TESTS_USER_TEST_SHELL
    #     or
    # TUDO_TESTS_CURRENT_TEST_NUMBER does not equal TUDO_TESTS_USER_TEST_NUMBER,
    # then skip the current test
    if [ -n "$TUDO_TESTS_USER_TEST_SHELL" ] && [ -n "$TUDO_TESTS_USER_TEST_NUMBER" ] && \
            { [[ "$TUDO_TESTS_CURRENT_TEST_SHELL" != "$TUDO_TESTS_USER_TEST_SHELL" ]] || \
                [[ "$TUDO_TESTS_CURRENT_TEST_NUMBER" != "$TUDO_TESTS_USER_TEST_NUMBER" ]]; }; then
        return 112
    else
        tudo_tests_run_test=1
        return 0
    fi

}

##
# `run_tudo_test` `<current_test_number>`
##
run_tudo_test () {

    set_tudo_tests_current_test_number "$1" || return $?
    tudo_tests_log 5 $'\n\n'
    tudo_tests_log 4 "$TUDO_TESTS_CURRENT_TEST_NUMBER()"

}

##
# `skip_tudo_test` `<current_test_number>`
##
skip_tudo_test () {

    set_tudo_tests_current_test_number "$1" || return $?
    tudo_tests_log 5 $'\n\n'"Skipping $TUDO_TESTS_CURRENT_TEST_SHELL shell test $TUDO_TESTS_CURRENT_TEST_NUMBER"

}

##
# `validate_tudo_test` `<expected_result_value>` `<actual_result_value>` `<actual_output>` `<expected_output>`
# `validate_tudo_test` `<expected_result_value>` `<actual_result_value>` `<actual_output>` `<expected_output_prefix_glob>` `<expected_output>` `<expected_output_suffix_glob>`
##
validate_tudo_test () {

    local return_value

    if [[ "$tudo_tests_run_test" != "1" ]]; then
        return 0
    fi

    local expected_result_value="$1"
    local actual_result_value="$2"

    # Remove all escape sequences and strip all characters except tab(11), linefeed(12) and characters in range 40-176
    local actual_output="$(sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' <<< "$3" | tr -cd '\11\12\40-\176')"

    local expected_output
    local output_match_test_failed=0

    # If actual_output is set
    if [ -n "$actual_output" ]; then
        tudo_tests_log_no_tag 5 "$(cat -v <<<"$actual_output")"
    fi

    # If argument count equals 4 and actual_output does not exactly match $4
    if [ $# -eq 4 ]; then
        if [[  "$4" == "r+="* ]]; then
            if [[ ! "$actual_output" =~ ${4:3} ]]; then
                output_match_test_failed=1
                expected_output="$4"
            fi
        elif [[ "$actual_output" != "$4" ]]; then
            output_match_test_failed=1
            expected_output="$4"
        fi
    fi

    # If argument count greater than 4 and actual_output does not exactly match $5 with $4 and $6 as optional globs
    if [ $# -gt 4 ] && [[  "$actual_output" != $4"$5"$6 ]]; then
        output_match_test_failed=1
        expected_output="$4$5$6"
    fi

    # If output_match_test_failed is enabled
    if [[  "$output_match_test_failed" == "1" ]]; then
        tudo_tests_log_errors $'\n'"$TUDO_TESTS_CURRENT_TEST_SHELL shell test $TUDO_TESTS_CURRENT_TEST_NUMBER for '$TUDO_TESTS_COMMAND_TYPE' command type failed since expected_output does not match actual_output"
        tudo_tests_log_errors $'\n'"expected_output=\`$expected_output\`"
        tudo_tests_log_errors $'\n'"actual_output=\`$actual_output\`"
        exit 1
    fi

    # If actual_result_value is not a valid exit code
    if [[ ! "$actual_result_value" =~ $VALID_NUMBER_REGEX ]]; then
        tudo_tests_log_errors $'\n'"$TUDO_TESTS_CURRENT_TEST_SHELL shell test $TUDO_TESTS_CURRENT_TEST_NUMBER for '$TUDO_TESTS_COMMAND_TYPE' command type exit code '$actual_result_value' is invalid"
        exit 1
    fi

    # If expected_result_value is not a valid exit code
    if [[ ! "$expected_result_value" =~ $VALID_NUMBER_REGEX ]]; then
        tudo_tests_log_errors $'\n'"$TUDO_TESTS_CURRENT_TEST_SHELL shell test $TUDO_TESTS_CURRENT_TEST_NUMBER for '$TUDO_TESTS_COMMAND_TYPE' command type exit code '$expected_result_value' is invalid"
        exit 1
    fi

    # If actual_result_value does not equal expected_result_value
    if [[ "$actual_result_value" != "$expected_result_value" ]]; then
        tudo_tests_log_errors $'\n'"$TUDO_TESTS_CURRENT_TEST_SHELL shell test $TUDO_TESTS_CURRENT_TEST_NUMBER for '$TUDO_TESTS_COMMAND_TYPE' command type failed with exit code $actual_result_value but expected exit code was $expected_result_value"
        exit "$actual_result_value"
    fi

    return 0

}

tudo_tests_cleanup() {

    # The tudo_tests_cleanup will do the following:
    # Remove the EXIT trap so its not called again.
    # Remove temp_directory if set.
    # If a signal argument was passed, then remove its trap and
    # then exit with the same signal
    # so that parent processes can be notified if necessary.

    local tudo_tests_exit_code=$?
    trap - EXIT
    tudo_tests_remove_tudo_tests_temp_directories
    [ -n "$1" ] && trap - "$1"; exit $tudo_tests_exit_code;

}

tudo_tests_remove_tudo_tests_temp_directories() {

    # If TUDO_TESTS_DIRECTORIES and TUDO_TESTS_TEMP_DIRECTORY_SUFFIX are set
    if [ ${#TUDO_TESTS_DIRECTORIES[@]} -ne 0 ] && [ -n "$TUDO_TESTS_TEMP_DIRECTORY_SUFFIX" ]; then

        tudo_tests_log 5 $'\n\n'"Running tudo_tests_remove_tudo_tests_temp_directories"

        # Remove all directories in TUDO_TESTS_DIRECTORIES if they match the TUDO_TESTS_TEMP_DIRECTORY_SUFFIX
        for i in "${!TUDO_TESTS_DIRECTORIES[@]}"; do
            if [[ "${TUDO_TESTS_DIRECTORIES[$i]}" == *"$TUDO_TESTS_TEMP_DIRECTORY_SUFFIX" ]]; then
                [ -d "${TUDO_TESTS_DIRECTORIES[$i]}" ] && rm -rf "${TUDO_TESTS_DIRECTORIES[$i]}"
            fi
        done

    fi

    return 0

}

##
# `tudo_tests_process_script_arguments` [`<argument...>`]
##
tudo_tests_process_script_arguments() {

    local opt; local opt_arg; local OPTARG=""; local OPTIND=1;

    # Parse options to main command
    while getopts ":hqv-:" opt; do
        case "${opt}" in
            -)
                case "${OPTARG}" in *?=*) opt_arg="${OPTARG#*=}";; *) opt_arg="";; esac
                case "${OPTARG}" in
                    help-extra)
                        tudo_tests_log_args "Parsing option: '--${OPTARG%=*}'"
                        tudo_tests_show_help_extra || return $?
                        TUDO_TESTS_NOOP_COMMAND=1; return 0
                        ;;
                    help-extra=*)
                        tudo_tests_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_tests_exit_on_args_error || return $?
                        ;;
                    help)
                        tudo_tests_log_args "Parsing option: '--${OPTARG%=*}'"
                        tudo_tests_show_help || return $?
                        TUDO_TESTS_NOOP_COMMAND=1; return 0
                        ;;
                    help=*)
                        tudo_tests_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_tests_exit_on_args_error || return $?
                        ;;
                    only-bash-tests)
                        tudo_tests_log_args "Parsing option: '--${OPTARG%=*}'"
                        TUDO_TESTS_ONLY_BASH_TESTS=1
                        ;;
                    only-bash-tests=*)
                        tudo_tests_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_tests_exit_on_args_error || return $?
                        ;;
                    quiet)
                        tudo_tests_log_args "Parsing option: '--${OPTARG%=*}'"
                        TUDO_TESTS_LOG_LEVEL=0
                        ;;
                    quiet=*)
                        tudo_tests_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_tests_exit_on_args_error || return $?
                        ;;
                    '')
                        tudo_tests_log_args "Parsing option: '--'"
                        break # End of options '--'.
                        ;;
                    *)
                        tudo_tests_log_arg_errors "Unknown option: '--${OPTARG:-}'."
                        tudo_tests_exit_on_args_error || return $?
                        ;;
                esac
                ;;
            h)
                tudo_tests_log_args "Parsing option: '-${opt}'"
                tudo_tests_show_help || return $?
                TUDO_TESTS_NOOP_COMMAND=1; return 0
                ;;
            q)
                tudo_tests_log_args "Parsing option: '-${opt}'"
                TUDO_TESTS_LOG_LEVEL=0
                ;;
            v)
                tudo_tests_log_args "Parsing option: '-${opt}'"
                if [ "$TUDO_TESTS_LOG_LEVEL" -lt "$TUDO_TESTS_MAX_LOG_LEVEL" ]; then
                    TUDO_TESTS_LOG_LEVEL=$((TUDO_TESTS_LOG_LEVEL+1));
                else
                    tudo_tests_log_arg_errors "Invalid Option, max log level is $TUDO_TESTS_MAX_LOG_LEVEL"
                    tudo_tests_exit_on_args_error || return $? || return $?
                fi
                ;;
            :)
                tudo_tests_log_arg_errors "No argument passed for arg option '-$OPTARG'."
                tudo_tests_exit_on_args_error || return $?
                ;;
            \?)
                tudo_tests_log_arg_errors "Unknown option${OPTARG:+": '-${OPTARG:-}'"}."
                tudo_tests_exit_on_args_error || return $?
                ;;
        esac
    done
    shift $((OPTIND - 1)) # Remove already processed arguments from arguments array

    TUDO_TESTS_COMMAND_TYPE="$1"
    TUDO_TESTS_USER_TEST_SHELL="$2"
    TUDO_TESTS_USER_TEST_NUMBER="$3"

}

tudo_tests_show_help() {

    cat<<<"$TUDO_TESTS_HELP"

}

tudo_tests_show_help_extra() {

    tudo_tests_show_help

    cat<<<"$TUDO_TESTS_HELP_EXTRA"

}

tudo_tests_exit_on_args_error() {

    tudo_tests_show_help || return $?
    return 64 # EX__USAGE

}



# Call main function
tudo_tests_main "$@"
