#!/usr/bin/env bash # shellcheck disable=SC2068 set -Eeuo pipefail EXAMPLES_DIR="${PWD}/examples" RED="$(tput setf 4)" GREEN="$(tput setf 2)" NO_COLOR="$(tput setf 7)" if [[ -z ${DEBUG+x} ]]; then # Debugging disabled, do not display nstow command output REDIRECTION="&>/dev/null" else # Debugging enabled, display nstow command output REDIRECTION="2>&1" fi function status() { local indent='' local char='>' case "$1" in 1) shift indent=" " char='-' ;; 2) shift indent=" " char='-' ;; esac printf "${indent}${char} %s\n" "$*" >&2 } function debug_log() { if [[ -n ${DEBUG+x} ]]; then echo '' echo "[DEBUG] ${*}" >&2 echo '' fi } function load_vars() { local stowfile="$1" status 1 "Loading vars to env" local vars=($(yq -re '.vars[]' "${stowfile}" 2>/dev/null)) for var in "${vars[@]}"; do status 2 "Found var: ${var}" eval "export ${var}" done } function get_symlinks() { local stowfile="$1" status 1 "Reading links" local links=($(yq -re '.. |."links"? | select(. != null)' "${stowfile}" 2>/dev/null)) for link in "${links[@]}"; do # Globbing is messed up. Every other value is just a '-'. Quickest way to fix is just to skip those if [[ "${link}" == '-' ]]; then continue fi echo "${link}" done } function pretty_format_path() { local path="$1" echo "${path/${HOME}/\~}" } function do_check() { local test_expression="$1" local message="$2" local return_code=1 local outcome="${RED}FAIL${NO_COLOR}" #debug_log "Running test: >> ${test_expression} <<" eval "if ${test_expression}; then outcome=${GREEN}PASS${NO_COLOR}; return_code=0; fi" status 2 "[${outcome}] ${message}" return "${return_code}" } function check_file() { local message="${1}" shift local fail_condition="${1}" shift local return_code=0 while (("$#")); do local link="${1}" local message message="$(pretty_format_path "${link}")" local expression="test ${fail_condition} ${link}" if ! do_check "${expression}" "${message}"; then return_code=1 fi shift # Move to next arg done return "${return_code}" } function assert_fail() { local args="$*" local return_code=1 status 1 "Running command '${args}'" if do_check "! command ${args} ${REDIRECTION}" "Command should fail"; then return_code=0 fi return "${return_code}" } function assert_success() { local args="$*" local return_code=0 status 1 "Running command '${args}'" if ! do_check "command ${args} ${REDIRECTION}" "Command should succeed"; then return_code=1 fi return "${return_code}" } function test_stowfile() { local stowfile="$1" local stowfile_dir stowfile_dir="$(dirname "${stowfile}")" status "Testing nstow with ${stowfile}" load_vars "${stowfile}" local links links="$(get_symlinks "${stowfile}")" &>/dev/null assert_fail nstow -v --dry-run --dir "${stowfile_dir}" --unstow check_file "should not exist" "! -e" ${links[@]} assert_success nstow -v --dir "${stowfile_dir}" check_file "should exist and be a symlink" "-L" ${links[@]} assert_success nstow -v --dir "${stowfile_dir}" --restow check_file "should exist and be a symlink" "-L" ${links[@]} assert_success nstow -v --dir "${stowfile_dir}" --unstow check_file "does not exist" "! -e" ${links[@]} } # Run tests on all stowfiles in the examples dir find "${EXAMPLES_DIR}" -name stowfile | while read -r stowfile; do # Remove dotfiles from home directory before running test find "${HOME}" -maxdepth 1 -name '.*' -print0 | xargs -0 rm -r test_stowfile "${stowfile}" done status "All tests pass"