Skip to content

Commit

Permalink
♻️ tests ok
Browse files Browse the repository at this point in the history
  • Loading branch information
jcaillon committed Jan 18, 2025
1 parent 846209d commit 218bdf8
Show file tree
Hide file tree
Showing 41 changed files with 515 additions and 644 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ sandbox.sh
benchmark.sh
try.sh
sort.sh
file
file?
f?

# tests
tests.d/1005-lib-io/resources/gitignored/**
Expand Down
4 changes: 2 additions & 2 deletions commands.d/self-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ function selfBuild() {
"${GLOBAL_VALET_HOME}/valet"
"${GLOBAL_VALET_HOME}/commands.d"/*.sh
)
if [[ -d "${GLOBAL_VALET_HOME}/tests.d/commands.d" ]]; then
commandDefinitionFiles+=("${GLOBAL_VALET_HOME}/tests.d/commands.d"/*.sh)
if [[ -d "${GLOBAL_VALET_HOME}/tests.d/.commands.d" ]]; then
commandDefinitionFiles+=("${GLOBAL_VALET_HOME}/tests.d/.commands.d"/*.sh)
log::info "Added the test commands to the build."
fi
if [[ ${coreOnly:-} != "true" ]]; then
Expand Down
8 changes: 2 additions & 6 deletions commands.d/self-test-utils
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,10 @@ function selfTestUtils_setupValetForConsistency() {

# fix the time to a known value
export TZ=Etc/GMT+0
unset EPOCHSECONDS EPOCHREALTIME
# unset EPOCHSECONDS EPOCHREALTIME
export EPOCHSECONDS=548902800
export EPOCHREALTIME=548902800.000000

# set a new user directory so that commands are correctly recreated if calling
# valet from a test
export VALET_USER_DIRECTORY="${GLOBAL_TEST_VALET_USER_DIRECTORY}"

log::createPrintFunction
eval "${GLOBAL_LOG_PRINT_FUNCTION}"
}
Expand Down Expand Up @@ -185,7 +181,7 @@ function selfTestUtils_setupDiffCommand() {
if [[ -z ${GLOBAL_TEST_DIFF_COMMAND} ]]; then
if command -v delta &>/dev/null; then
log::debug "Using delta as diff command."
GLOBAL_TEST_DIFF_COMMAND="delta --paging=never --no-gitconfig --line-numbers --side-by-side %APPROVED_FILE% %RECEIVED_FILE%"
GLOBAL_TEST_DIFF_COMMAND="delta --paging=never --no-gitconfig --line-numbers --width ${GLOBAL_COLUMNS} --side-by-side %APPROVED_FILE% %RECEIVED_FILE%"
# delta compares the file modes, so we need to match them
GLOBAL_TEST_REPORT_FILE_MODE="${VALET_CONFIG_TEST_REPORT_FILE_MODE:-644}"
elif command -v diff &>/dev/null; then
Expand Down
44 changes: 25 additions & 19 deletions commands.d/self-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,6 @@ function selfTest() {
core::parseArguments "$@" && eval "${RETURNED_VALUE}"
core::checkParseResults "${help:-}" "${parsingErrors:-}"

# can't have the profiler on
if command -v profiler::disable &>/dev/null; then
profiler::disable
fi

local startTime="${EPOCHREALTIME}"

# check what will be used to display the diff between received and approved files
Expand Down Expand Up @@ -352,7 +347,11 @@ function selfTest_runSingleTestSuite() {
GLOBAL_TEST_REPORT_FILE="${GLOBAL_TEST_OUTPUT_TEMPORARY_DIRECTORY}/report"
GLOBAL_TEST_STACK_FILE="${GLOBAL_TEST_OUTPUT_TEMPORARY_DIRECTORY}/stack"
GLOBAL_TEST_LOG_FILE="${GLOBAL_TEST_OUTPUT_TEMPORARY_DIRECTORY}/log"
# shellcheck disable=SC2034
GLOBAL_TEST_TEMP_FILE="${GLOBAL_TEST_BASE_TEMPORARY_DIRECTORY}/temp"
mkdir -p "${GLOBAL_TEST_OUTPUT_TEMPORARY_DIRECTORY}"
# shellcheck disable=SC2034
GLOBAL_TEST_CURRENT_DIRECTORY="${testSuiteDirectory}"

# run a custom user script before the test suite if it exists
selfTestUtils_runHookScript "${testsDotDirectory}/before-each-test-suite"
Expand All @@ -374,6 +373,9 @@ function selfTest_runSingleTestSuite() {
fi
log::printString "${treeString} ${GLOBAL_TEST_SUITE_SCRIPT_NAME}" "${treePadding}"

# write the test script name
printf "%s\n\n" "## Test script ${GLOBAL_TEST_SUITE_SCRIPT_NAME%.sh}" >>"${GLOBAL_TEST_REPORT_FILE}"

# Run the test script in a subshell.
# This way each test can define any vars or functions without polluting
# the global execution of the tests.
Expand Down Expand Up @@ -526,30 +528,18 @@ function selfTest_runSingleTest() {
rm -Rf "${GLOBAL_TEST_BASE_TEMPORARY_DIRECTORY}"
fi
io::setupTempFileGlobalVariable

io::cleanupTempFiles
mkdir -p "${GLOBAL_TEST_BASE_TEMPORARY_DIRECTORY}"

# set a new user directory so that commands are correctly recreated if calling
# valet from a test
cp -R "${GLOBAL_TEST_VALET_USER_DIRECTORY}" "${GLOBAL_TEST_BASE_TEMPORARY_DIRECTORY}/valet.d"
export VALET_USER_DIRECTORY="${GLOBAL_TEST_BASE_TEMPORARY_DIRECTORY}/valet.d"

# The following file can be used by tests during tests.
# shellcheck disable=SC2034
GLOBAL_TEST_TEMP_FILE="${GLOBAL_TEMPORARY_FILE_PREFIX}${BASHPID}.valet-test-tempfile"
cp -R "${GLOBAL_TEST_VALET_USER_DIRECTORY}" "${GLOBAL_TEMPORARY_DIRECTORY_PREFIX}.valet.d"
export VALET_USER_DIRECTORY="${GLOBAL_TEMPORARY_DIRECTORY_PREFIX}.valet.d"

# redirect the standard output and error output to files
exec 3>&1 1>"${GLOBAL_TEST_STANDARD_OUTPUT_FILE}"
exec 4>&2 2>"${GLOBAL_TEST_STANDARD_ERROR_FILE}"

# used in test library to replace this path with .
# shellcheck disable=SC2034
GLOBAL_TEST_CURRENT_DIRECTORY="${PWD}"

# write the test script name
printf "%s\n\n" "## Test script ${GLOBAL_TEST_SUITE_SCRIPT_NAME%.sh}" >>"${GLOBAL_TEST_REPORT_FILE}"

# run a custom user script before the test if it exists
selfTestUtils_runHookScript "${testDirectory}/before-each-test"

Expand All @@ -562,4 +552,20 @@ function selfTest_runSingleTest() {

exec 3>&-
exec 4>&-

self_makeReplacementsInReport
}

# ## self_makeReplacementsInReport
#
# In order to have consistent results in tests, we need to replace to replace
# values that could be different on each run/machine.
function self_makeReplacementsInReport() {
io::readFile "${GLOBAL_TEST_REPORT_FILE}"
RETURNED_VALUE="${RETURNED_VALUE//${GLOBAL_VALET_HOME}\/valet/valet}"
RETURNED_VALUE="${RETURNED_VALUE//${GLOBAL_VALET_HOME}/\$GLOBAL_VALET_HOME}"
RETURNED_VALUE="${RETURNED_VALUE//${GLOBAL_TEST_CURRENT_DIRECTORY}/.}"
RETURNED_VALUE="${RETURNED_VALUE//${GLOBAL_TEMPORARY_DIRECTORY_PREFIX}/\/tmp/valet}"
RETURNED_VALUE="${RETURNED_VALUE//${GLOBAL_TEMPORARY_FILE_PREFIX}/\/tmp/valet}"
printf "%s" "${RETURNED_VALUE}" >"${GLOBAL_TEST_REPORT_FILE}"
}
1 change: 1 addition & 0 deletions docs/content/docs/800.roadmap/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ url: /docs/roadmap

This page lists the features that I would like to implement in Valet. They come in addition to new features described in the [issues][valet-issues].

- propagate the set -x in self test subshells to have profiling enabled. We can create a new method in lib-profiler to profiler::reapply.
- test the "sudo" feature: it runs the command by forking. We could add an option to instead rerun valet with sudo.
- document the test; use the lib-test test as an example, and also link to the test:: lib.
- test the new bash:: lib
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### Testing the showcase command1



Exit code: `0`

**Standard output**:
Expand All @@ -25,6 +27,8 @@ INFO Extracted text is: ⌜My bold text⌝

### Testing the showcase sudo command by replacing sudo with echo



Exit code: `0`

**Standard output**:
Expand All @@ -36,6 +40,8 @@ whoami

### Testing the behavior of onInterrupt



Exit code: `0`

**Standard output**:
Expand Down
6 changes: 4 additions & 2 deletions libraries.d/lib-profiler
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
function profiler::enable() {
local file="${1}"
# Nested profiling not supported
if [[ -n ${_ACTIVE_PROFILER:-} ]]; then return 0; fi
if [[ -n ${_ACTIVE_PROFILER:-} ]]; then
return 0
fi
_ACTIVE_PROFILER=1

# create the directory for file and reset it
Expand All @@ -34,7 +36,7 @@ function profiler::enable() {
functionDepthExpression='0'
fi

PS4='+'$'\011''$(("${EPOCHREALTIME//./}" - _PROFILER_START_REALTIME))'$'\011''${BASH_SOURCE[0]:-}'$'\011''${LINENO:-?}'$'\011''${FUNCNAME[0]:-}'$'\011''${BASH_SUBSHELL}'$'\011'"${functionDepthExpression}"$'\011'''$'\011'
export PS4='+'$'\011''$(("${EPOCHREALTIME//./}" - _PROFILER_START_REALTIME))'$'\011''${BASH_SOURCE[0]:-}'$'\011''${LINENO:-?}'$'\011''${FUNCNAME[0]:-}'$'\011''${BASH_SUBSHELL:-}'$'\011'"${functionDepthExpression}"$'\011'''$'\011'

exec 5>"${file}"

Expand Down
85 changes: 46 additions & 39 deletions libraries.d/lib-test
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ function test::exit() {
# ```bash
# test_exec false echo "Hello, world!"
# ```
# shellcheck disable=SC2034
function test_exec() {
local canExit="${1}"
local displayReturnedValues="${2}"
Expand All @@ -123,31 +124,24 @@ function test_exec() {

local IFS=' '
# compute the command to run, escaping special characters
local compoundCommand="${*//[\\ ]/\\&}"
local compoundCommand="${*//[\\ $'\t']/\\&}"
compoundCommand="${compoundCommand//$'\n'/"$'\n'"}"
compoundCommand="${compoundCommand//$'\t'/"$'\t'"}"

_TEST_OUTPUT="${compoundCommand}"
_TEST_OUTPUT="${_TEST_OUTPUT//main::parseMainArguments/valet}"
test_replaceDynamicStrings

# shellcheck disable=SC2016
printf 'Prompt:\n\n```bash\n%s\n```\n\n' "${_TEST_OUTPUT}" >>"${GLOBAL_TEST_REPORT_FILE}"
printf '❯ `%s`\n\n' "${_TEST_OUTPUT}" >>"${GLOBAL_TEST_REPORT_FILE}"

if [[ -s "${GLOBAL_TEST_STANDARD_OUTPUT_FILE}" || -s "${GLOBAL_TEST_STANDARD_ERROR_FILE}" ]]; then
test::fail "${FUNCNAME[1]:-}⌝ was called in ⌜${BASH_SOURCE[2]:-}:${BASH_LINENO[1]:-}⌝ but the standard/error output were not empty, call ⌜test::flush⌝ first or do not write to these streams."
fi

if [[ ${displayReturnedValues} == "true" ]]; then
# shellcheck disable=SC2034
local RETURNED_VALUE
# shellcheck disable=SC2034
local RETURNED_VALUE2
# shellcheck disable=SC2034
local RETURNED_VALUE3
# shellcheck disable=SC2034
local RETURNED_VALUE4
# shellcheck disable=SC2034
local -a RETURNED_ARRAY
local -a RETURNED_ARRAY2
local -A RETURNED_ASSOCIATIVE_ARRAY
Expand Down Expand Up @@ -179,50 +173,47 @@ function test_exec() {
test_flushFdToCodeBlock 2 "Error output"

if [[ ${displayReturnedValues} == "true" ]]; then
test::revealReturnedVars
test::printReturnedVars
fi
}

# ## test::revealReturnedVars
# ## test::printReturnedVars
#
# This function can be called to display the returned values,
# e.g. RETURNED_VALUE, RETURNED_VALUE2, RETURNED_ARRAY...
# They will each be displayed in a code block in the report file.
#
# ```bash
# test::revealReturnedVars
# test::printReturnedVars
# ```
function test::revealReturnedVars() {
local IFS=$'\n' output key varName
test::log "${RETURNED_ARRAY[*]} ${RETURNED_ARRAY2[*]}"
function test::printReturnedVars() {
local IFS=$'\n' key varName _TEST_OUTPUT=""
for varName in RETURNED_VALUE RETURNED_VALUE2 RETURNED_VALUE3 RETURNED_VALUE4; do
if [[ -v ${varName} ]]; then
_TEST_OUTPUT="${!varName}"
test_replaceDynamicStrings
# shellcheck disable=SC2016
printf '%s:\n\n```text\n%s\n```\n\n' "${varName}" "${_TEST_OUTPUT}" >>"${GLOBAL_TEST_REPORT_FILE}"
_TEST_OUTPUT+="${varName}=${!varName@Q}"$'\n'
fi
done
for varName in RETURNED_ARRAY RETURNED_ARRAY2; do
if [[ -v ${varName} ]]; then
_TEST_OUTPUT=''
_TEST_OUTPUT+="${varName}=("$'\n'
local -n array="${varName}"
for key in "${!array[@]}"; do
_TEST_OUTPUT+="[${key}]=${array[${key}]}"$'\n'
_TEST_OUTPUT+="[${key}]=${array[${key}]@Q}"$'\n'
done
test_replaceDynamicStrings
# shellcheck disable=SC2016
printf '%s:\n\n```text\n%s\n```\n\n' "${varName}" "${_TEST_OUTPUT%$'\n'}" >>"${GLOBAL_TEST_REPORT_FILE}"
_TEST_OUTPUT+=")"$'\n'
fi
done
if declare -p RETURNED_ASSOCIATIVE_ARRAY &>/dev/null; then
_TEST_OUTPUT=''
if [[ -v RETURNED_ASSOCIATIVE_ARRAY || -v RETURNED_ASSOCIATIVE_ARRAY[@] ]]; then
_TEST_OUTPUT+="RETURNED_ASSOCIATIVE_ARRAY=("$'\n'
for key in "${!RETURNED_ASSOCIATIVE_ARRAY[@]}"; do
_TEST_OUTPUT+="[${key}]=${RETURNED_ASSOCIATIVE_ARRAY[${key}]}"$'\n'
_TEST_OUTPUT+="[${key}]=${RETURNED_ASSOCIATIVE_ARRAY[${key}]@Q}"$'\n'
done
_TEST_OUTPUT+=")"$'\n'
fi
if [[ -n ${_TEST_OUTPUT} ]]; then
test_replaceDynamicStrings
# shellcheck disable=SC2016
printf 'RETURNED_ASSOCIATIVE_ARRAY:\n\n```text\n%s\n```\n\n' "${_TEST_OUTPUT%$'\n'}" >>"${GLOBAL_TEST_REPORT_FILE}"
printf 'Returned variables:\n\n```text\n%s\n```\n\n' "${_TEST_OUTPUT%$'\n'}" >>"${GLOBAL_TEST_REPORT_FILE}"
fi
}

Expand All @@ -239,7 +230,7 @@ function test::resetReturnedVars() {
unset ${!RETURNED_*}
}

# ## test::revealVars
# ## test::printVars
#
# This function can be called to display the global variables in the report file.
# They will displayed in a code block in the report file.
Expand All @@ -248,15 +239,37 @@ function test::resetReturnedVars() {
# The variables to display.
#
# ```bash
# test::revealVars myVar
# test::printVars myVar
# ```
function test::revealVars() {
function test::printVars() {
local IFS=$'\n'
local chunk varName
io::captureOutput declare -p "${@}"
_TEST_OUTPUT="${RETURNED_VALUE//declare -? /}"
_TEST_OUTPUT=""
while [[ -n ${RETURNED_VALUE} ]]; do
chunk="${RETURNED_VALUE%%$'\n'*}"
RETURNED_VALUE="${RETURNED_VALUE:${#chunk} + 1}"

if [[ ${chunk} =~ "declare -"[aA][ilnrtux]*" "([^=]+)"=" ]]; then
# we display an array
varName="${BASH_REMATCH[1]}"
test::log "Printing variable: ⌜${varName}"
local -n array="${varName}"
_TEST_OUTPUT+="${varName}=("$'\n'
for key in "${!array[@]}"; do
_TEST_OUTPUT+="[${key}]=${array[${key}]@Q}"$'\n'
done
_TEST_OUTPUT+=")"$'\n'
elif [[ ${chunk} =~ "declare -"[^[:space:]]+" " ]]; then
# we display a simple variable
_TEST_OUTPUT+="${chunk//"${BASH_REMATCH[0]}"/}"$'\n'
else
test::fail "Could not parse variable declaration: ⌜${chunk}⌝."
fi
done
test_replaceDynamicStrings
# shellcheck disable=SC2016
printf '```text\n%s\n```\n\n' "${_TEST_OUTPUT%$'\n'}" >>"${GLOBAL_TEST_REPORT_FILE}"
printf 'Variables:\n\n```text\n%s\n```\n\n' "${_TEST_OUTPUT%$'\n'}" >>"${GLOBAL_TEST_REPORT_FILE}"
}

# ## test_flushFdToCodeBlock (private)
Expand Down Expand Up @@ -315,12 +328,6 @@ function test_flushFdToCodeBlock() {
# test_replaceDynamicStrings
# ```
function test_replaceDynamicStrings() {
_TEST_OUTPUT="${_TEST_OUTPUT//${GLOBAL_VALET_HOME}\/valet/valet}"
_TEST_OUTPUT="${_TEST_OUTPUT//${GLOBAL_VALET_HOME}/\$GLOBAL_VALET_HOME}"
_TEST_OUTPUT="${_TEST_OUTPUT//${GLOBAL_TEST_CURRENT_DIRECTORY}/.}"
_TEST_OUTPUT="${_TEST_OUTPUT//${GLOBAL_TEMPORARY_DIRECTORY_PREFIX}/\/tmp/valet}"
_TEST_OUTPUT="${_TEST_OUTPUT//${GLOBAL_TEMPORARY_FILE_PREFIX}/\/tmp/valet}"

# If a callback is defined, call it to modify the text before adding it to the report
if declare -f test::transformTextBeforeFlushing &>/dev/null; then
test::transformTextBeforeFlushing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ set -Eeu -o pipefail

# import the main script (should always be skipped if the command is run from valet, this is mainly for shellcheck)
if [[ -z "${GLOBAL_CORE_INCLUDED:-}" ]]; then
# shellcheck source=../libraries.d/core
# shellcheck source=../../libraries.d/core
source "$(dirname -- "$(command -v valet)")/libraries.d/core"
fi
# --- END OF COMMAND COMMON PART

# shellcheck source=../../libraries.d/lib-io
source io

#===============================================================
# >>> command: self mock1
#===============================================================
Expand Down Expand Up @@ -99,10 +102,7 @@ function selfMock1() {
;;
wait-indefinitely)
log::info "This is for testing valet core functions, waiting indefinitely."
while true; do
# sleep for 1s
read -rt 1 <> <(:) || :
done
io::sleep 999
;;
show-help)
core::showHelp
Expand Down
Loading

0 comments on commit 218bdf8

Please sign in to comment.