Compare commits

...

4 commits

Author SHA1 Message Date
6368928cc2
Fix test framework and add input type check tests
This commit's tests do not run through properly, I will fix that in the next few commits.
2024-10-27 22:12:35 +01:00
5be44a87bf
Add input type checks 2024-10-27 22:04:37 +01:00
b706526e99
Improve documentation 2024-10-27 21:52:26 +01:00
7dcaaf5950
Rename _bashutils_restore_return method 2024-10-27 21:39:23 +01:00
5 changed files with 265 additions and 29 deletions

View file

@ -26,6 +26,9 @@
# Environment control
## => Restores the environment
## => Arguments: none
## => Returns: 0
function _bashutils_restore_environment() {
if [ -n "${_BASHUTILS_ENVIRONMENT_PREVIOUS_OPTIONS}" ]; then
[[ "${_BASHUTILS_ENVIRONMENT_PREVIOUS_OPTIONS}" == *"e"* ]] && set -e
@ -38,7 +41,14 @@ function _bashutils_restore_environment() {
[ -z "${_BASHUTILS_ENVIRONMENT_PREVIOUS_PIPEFAIL}" ] && set +o pipefail
unset _BASHUTILS_ENVIRONMENT_PREVIOUS_OPTIONS
fi
return 0
}
## => Resets the environment to optimal conditions for bashutils
## => Arguments:
## -> 1. none
## -> 2. [?...:command to execute]
## => Returns: 0 or the command's exit code if one is supplied
function _bashutils_reset_environment() {
export "_BASHUTILS_ENVIRONMENT_PREVIOUS_OPTIONS=${-}"
[ -o "pipefail" ] && export "_BASHUTILS_ENVIRONMENT_PREVIOUS_PIPEFAIL=true"
@ -53,20 +63,48 @@ function _bashutils_reset_environment() {
_bashutils_restore_environment
return "${EXITCODE}"
fi
return 0
}
function _bashutils_restore_return() {
## => Resets the environment and returns the first argument.
## This is useful in situations where the environment shall
## be reset and the exit code preserved.
## => Arguments: <byte:exit code>
## => Returns: the provided exit code
function _bashutils_return_environment() {
_bashutils_restore_environment
return "${1}"
return "${1:-0}"
}
# Logging
## => Prints a diagnostic message.
## => Arguments: <str...:message>
## => Returns: 0
function diag() { [ "${BASHUTILS_LOGLEVEL}" -lt 1 ] && echo -e "DIAG ${*//\\n/\\n }"; }
## => Prints a verbose message.
## => Arguments: <str...:message>
## => Returns: 0
function verb() { [ "${BASHUTILS_LOGLEVEL}" -lt 2 ] && echo -e "VERB ${*//\\n/\\n }"; }
## => Prints a silent warning message.
## => Arguments: <str...:message>
## => Returns: 0
function sarn() { [ "${BASHUTILS_LOGLEVEL}" -lt 3 ] && echo -e "SARN ${*//\\n/\\n }"; }
## => Prints an informational message.
## => Arguments: <str...:message>
## => Returns: 0
function info() { [ "${BASHUTILS_LOGLEVEL}" -lt 4 ] && echo -e "INFO ${*//\\n/\\n }"; }
## => Prints a warning message.
## => Arguments: <str...:message>
## => Returns: 0
function warn() { [ "${BASHUTILS_LOGLEVEL}" -lt 5 ] && echo -e "WARN ${*//\\n/\\n }"; }
## => Prints an error message.
## => Arguments: <str...:message>
## => Returns: 0
function error() { [ "${BASHUTILS_LOGLEVEL}" -lt 6 ] && echo -e "ERR! ${*//\\n/\\n }" &> /dev/stderr; }
## => Handles crashes.
## => Arguments: <bool:terminate?> <str...:message>
## => Returns: 0
function crash() {
_bashutils_reset_environment
[ "${1}" == "true" ] && CRASH_TERMINATE=true || CRASH_TERMINATE=false
@ -101,15 +139,57 @@ EOF
}
# Checks
function is_command_alias() { _bashutils_reset_environment; [[ "$(type -t "${1}")" == alias ]]; _bashutils_restore_return ${?}; }
function is_command_keyword() { _bashutils_reset_environment; [[ "$(type -t "${1}")" == keyword ]]; _bashutils_restore_return ${?}; }
function is_command_function() { _bashutils_reset_environment; [[ "$(type -t "${1}")" == function ]]; _bashutils_restore_return ${?}; }
function is_command_builtin() { _bashutils_reset_environment; [[ "$(type -t "${1}")" == builtin ]]; _bashutils_restore_return ${?}; }
function is_command_file() { _bashutils_reset_environment; [[ "$(type -t "${1}")" == file ]]; _bashutils_restore_return ${?}; }
function is_command_defined() { _bashutils_reset_environment; [[ "$(type -t "${1}")" == "" ]]; _bashutils_restore_return ${?}; }
## Command type
## => Checks whether the provided command name is an alias.
## => Arguments: <str:command name>
## => Returns: 0 if it is, 1 otherwise
function is_command_alias() { _bashutils_reset_environment; [[ "$(type -t "${1}")" == alias ]]; _bashutils_return_environment ${?}; }
## => Checks whether the provided command name is a keyword.
## => Arguments: <str:command name>
## => Returns: 0 if it is, 1 otherwise
function is_command_keyword() { _bashutils_reset_environment; [[ "$(type -t "${1}")" == keyword ]]; _bashutils_return_environment ${?}; }
## => Checks whether the provided command name is a function.
## => Arguments: <str:command name>
## => Returns: 0 if it is, 1 otherwise
function is_command_function() { _bashutils_reset_environment; [[ "$(type -t "${1}")" == function ]]; _bashutils_return_environment ${?}; }
## => Checks whether the provided command name is a builtin.
## => Arguments: <str:command name>
## => Returns: 0 if it is, 1 otherwise
function is_command_builtin() { _bashutils_reset_environment; [[ "$(type -t "${1}")" == builtin ]]; _bashutils_return_environment ${?}; }
## => Checks whether the provided command name is a file.
## => Arguments: <str:command name>
## => Returns: 0 if it is, 1 otherwise
function is_command_file() { _bashutils_reset_environment; [[ "$(type -t "${1}")" == file ]]; _bashutils_return_environment ${?}; }
## => Checks whether the provided command name is defined.
## => Arguments: <str:command name>
## => Returns: 0 if it is, 1 otherwise
function is_command_defined() { _bashutils_reset_environment; [[ "$(type -t "${1}")" == "" ]]; _bashutils_return_environment ${?}; }
## Input type
## => Checks whether the provided input is a bool.
## => Arguments: <str:input>
## => Returns: 0 if it is, 1 otherwise
function is_input_bool() { _bashutils_reset_environment; [ "${1}" == "true" ] || [ "${1}" == "false" ]; _bashutils_return_environment "${?}"; }
## => Checks whether the provided input is a byte.
## => Arguments: <str:input>
## => Returns: 0 if it is, 1 otherwise
function is_input_byte() { _bashutils_reset_environment; [[ "${1}" =~ ^[0-9]+$ ]] && [[ "${1}" -gt -1 ]] && [["${1}" -lt 256 ]]; _bashutils_return_environment "${?}"; }
## => Checks whether the provided input is a integer/number.
## => Arguments: <str:input>
## => Returns: 0 if it is, 1 otherwise
function is_input_int() { _bashutils_reset_environment; [[ "${1}" =~ ^[0-9]+$ ]]; _bashutils_return_environment "${?}"; }
## => Checks whether the provided input is a char.
## => Arguments: <str:input>
## => Returns: 0 if it is, 1 otherwise
function is_input_char() { _bashutils_reset_environment; [[ "${1}" =~ ^.$ ]]; _bashutils_return_environment "${?}"; }
# Variable definition
## => Sets the specified variable to the specified value if it is undefined.
## => Arguments: <str:variable> <?:value>
## => Returns: 0 if it is, 1 otherwise
function set_undefined() { _bashutils_reset_environment; [ -z "${!1}" ] && export "${1}=${2}"; _bashutils_restore_environment; }
## => Sets the specified variable to the specified value if it is defined.
## => Arguments: <str:variable> <?:value>
## => Returns: 0 if it is, 1 otherwise
function set_defined() { _bashutils_reset_environment; [ -n "${!1}" ] && export "${1}=${2}"; _bashutils_restore_environment; }

View file

@ -24,8 +24,8 @@ is_command_builtin "echo" && echo "'echo'" is built into bash"
! is_command_defined "setup" && echo "ERROR: 'setup' is undefined"
```
## Command type checks
These check the type of the passed command and return `0` if it matches or `1` if it doesn't.
## Command type
These checks check the type of the passed command and return `0` if it matches or `1` if it doesn't.
<table>
<tr>
@ -57,3 +57,33 @@ These check the type of the passed command and return `0` if it matches or `1` i
<td><code>is_command_defined &lt;str:command name&gt;</code></td>
</tr>
</table>
## Input type
These checks check the type of the specified input and return `0` if the type matches or `1` if it isn't.
<table>
<tr>
<td>Checks for</td>
<td>Usage</td>
</tr>
<tr>
<td><code>bool</code></td>
<td><code>is_input_bool &lt;?:input&gt;</code></td>
</tr>
<tr>
<td><code>byte</code></td>
<td><code>is_input_byte &lt;?:input&gt;</code></td>
</tr>
<tr>
<td><code>int</code></td>
<td><code>is_input_int &lt;?:input&gt;</code></td>
</tr>
<tr>
<td><code>char</code></td>
<td><code>is_input_char &lt;?:input&gt;</code></td>
</tr>
<tr>
<td><code>str</code></td>
<td>Are you serious?</td>
</tr>
</table>

View file

@ -22,32 +22,32 @@ required arguments along.
<tr>
<td>Diagnostic</td>
<td>0</td>
<td><code>diag &lt;str:message&gt;</code></td>
<td><code>diag &lt;str...:message&gt;</code></td>
</tr>
<tr>
<td>Verbose</td>
<td>1</td>
<td><code>verb &lt;str:message&gt;</code></td>
<td><code>verb &lt;str..:message&gt;</code></td>
</tr>
<tr>
<td>Silent warning</td>
<td>2</td>
<td><code>sarn &lt;str:message&gt;</code></td>
<td><code>sarn &lt;str...:message&gt;</code></td>
</tr>
<tr>
<td>Informational</td>
<td>3</td>
<td><code>info &lt;str:message&gt;</code></td>
<td><code>info &lt;str...:message&gt;</code></td>
</tr>
<tr>
<td>Warning</td>
<td>4</td>
<td><code>warn &lt;str:message&gt;</code></td>
<td><code>warn &lt;str...:message&gt;</code></td>
</tr>
<tr>
<td>Error</td>
<td>5</td>
<td><code>error &lt;str:message&gt;</code></td>
<td><code>error &lt;str...:message&gt;</code></td>
</tr>
</table>
@ -56,7 +56,7 @@ bashutils includes a fully functional crash handler.
It prints information about the operating system, environment, stack trace and of course the crash itself.
And, if you wish, it will terminate the script with code `69`.
To trigger a crash, simply invoke `crash <bool:terminate> <str:message>`.
To trigger a crash, simply invoke `crash <bool:terminate> <str...:message>`.
## Customization
bashutils allows you to customize the logging system via environment variables.

View file

@ -7,6 +7,9 @@ description: Describes which data types bashutils uses and understands.
# Data types
This document describes which data types bashutils can understand.
## `?`
Denotes a lack of data types. This means any data type is accepted.
## `bool`
Booleans. May only be `true` or `false`. `1` or `0` is not supported and will be treated as a number instead.

147
test.sh
View file

@ -1,8 +1,9 @@
#!/usr/bin/env bash
export "LC_ALL=C.UTF-8"
set -uo pipefail
IFS=$'\n'
unset TEST TESTS
unset TESTS TEST STAGE
TESTS="
# Logging
@ -15,34 +16,38 @@ logger_error
logger_crash
# Checks
## Command type
check_command_alias
check_command_keyword
check_command_function
check_command_builtin
check_command_file
check_command_defined
## Input type
check_input_bool
check_input_byte
check_input_int
check_input_char
"
# Utility methods
function invalid() { echo ":: Error: Invalid test ${TEST}, skipping"; }
function fail() {
echo -e ":: Test ${TEST} failed\n ${*//\\n/\\n }"
[ "${TEST_FAILFAST}" == "true" ] && exit 1
echo -e ":: Test ${TEST} failed during stage ${STAGE}\n ${*//\\n/\\n }"
[ "${TEST_FAILFAST:-true}" == "true" ] && exit 1
}
## Assertions
function assert_equals() {
EXPECTED="${1}"
shift
ACTUAL="${*}"
ACTUAL="${2}"
[[ "${ACTUAL}" != "${EXPECTED}" ]] && fail "${1}" "String does not match expected string\nExpected: ${EXPECTED}\nActual: ${ACTUAL}"
[[ "${ACTUAL}" != "${EXPECTED}" ]] && fail "String does not match expected string\nExpected: '${EXPECTED}'\nActual: '${ACTUAL}'"
}
function assert_contains() {
EXPECTED="${1}"
shift
ACTUAL="${*}"
EXPECTED="${1}"
ACTUAL="${2}"
[[ "${ACTUAL}" != *"${EXPECTED}"* ]] && fail "${1}" "String does not contain expected string\nExpected: ${EXPECTED}\nActual: ${ACTUAL}"
[[ "${ACTUAL}" != *"${EXPECTED}"* ]] && fail "String does not contain expected string\nExpected: '${EXPECTED}'\nActual: '${ACTUAL}'"
}
# Test loop
@ -50,7 +55,8 @@ for TEST in ${TESTS}; do
[ -z "${TEST}" ] || [[ "${TEST}" == "#"* ]] && continue
echo ":: Running test ${TEST}"
export TEST
export "TEST"
export "STAGE=0"
# Logging
if [[ "${TEST}" == "logger_"* ]]; then
@ -73,7 +79,7 @@ for TEST in ${TESTS}; do
elif [[ "${TEST}" == "check_"* ]]; then
# Command checks
if [[ "${TEST}" == "check_command_"* ]]; then
case "${TEST//check_command/}" in
case "${TEST//check_command_/}" in
"alias")
assert_equals "0" "$(
source "bashutils.sh"
@ -117,6 +123,123 @@ for TEST in ${TESTS}; do
echo "${?}"
)"
;;
*)
invalid
;;
esac
# Input checks
elif [[ "${TEST}" == "check_input_"* ]]; then
case "${TEST//check_input_/}" in
"bool")
assert_equals "0" "$(
source "bashutils.sh"
is_input_bool "true"
echo "${?}"
)"
export "STAGE=1"
assert_equals "0" "$(
source "bashutils.sh"
is_input_bool "false"
echo "${?}"
)"
export "STAGE=2"
assert_equals "1" "$(
source "bashutils.sh"
is_input_bool "0"
echo "${?}"
)"
export "STAGE=3"
assert_equals "1" "$(
source "bashutils.sh"
is_input_bool "1"
echo "${?}"
)"
;;
"byte")
assert_equals "0" "$(
source "bashutils.sh"
is_input_byte "0"
echo "${?}"
)"
export "STAGE=1"
assert_equals "0" "$(
source "bashutils.sh"
is_input_byte "255"
echo "${?}"
)"
export "STAGE=2"
assert_equals "0" "$(
source "bashutils.sh"
is_input_byte "69"
echo "${?}"
)"
export "STAGE=3"
assert_equals "1" "$(
source "bashutils.sh"
is_input_byte "256"
echo "${?}"
)"
export "STAGE=4"
assert_equals "1" "$(
source "bashutils.sh"
is_input_byte "-1"
echo "${?}"
)"
export "STAGE=5"
assert_equals "1" "$(
source "bashutils.sh"
is_input_int "asd"
echo "${?}"
)"
;;
"int")
assert_equals "0" "$(
source "bashutils.sh"
is_input_int "9223372036854775807"
echo "${?}"
)"
export "STAGE=1"
assert_equals "1" "$(
source "bashutils.sh"
is_input_int "asd"
echo "${?}"
)"
;;
"char")
assert_equals "0" "$(
source "bashutils.sh"
is_input_int "!"
echo "${?}"
)"
export "STAGE=1"
assert_equals "0" "$(
source "bashutils.sh"
is_input_int "™"
echo "${?}"
)"
export "STAGE=2"
assert_equals "0" "$(
source "bashutils.sh"
is_input_int "5"
echo "${?}"
)"
export "STAGE=3"
assert_equals "1" "$(
source "bashutils.sh"
is_input_int "asd"
echo "${?}"
)"
export "STAGE=4"
assert_equals "1" "$(
source "bashutils.sh"
is_input_int "666"
echo "${?}"
)"
;;
*)
invalid
;;
esac
# Invalid command