README_DOCS.rst: update tg prev and tg next usage summary
[topgit/pro.git] / t / test-lib.sh
blob2364eb5c2efdf06fb32f8fc620006dccf5bf88b8
1 # Test lib caching support
2 # Copyright (C) 2016,2017,2021 Kyle J. McKay
3 # All rights reserved
4 # License GPLv2+
7 # some ridiculous sh implementations require 'trap ... EXIT' to be executed
8 # OUTSIDE ALL FUNCTIONS to work in a sane fashion. Always trap it and eval
9 # "${TRAPEXIT_:-exit}" as a substitute.
10 trapexit_()
12 EXITCODE_=${1:-$?}
13 trap - EXIT
14 eval "${TRAPEXIT_:-exit $EXITCODE_}"
15 exit $EXITCODE_
17 trap 'trapexit_ $?' EXIT
19 # unset that ignnores error code that shouldn't be produced according to POSIX
20 unset_() {
21 { unset "$@"; } >/dev/null 2>&1 || :
24 # stores the single-quoted value of the variable name passed as
25 # the first argument into the variable name passed as the second
26 # (use test_quotevar_ 3 varname "$value" to quote a value directly)
27 test_quotevar_() {
28 eval "set -- \"\${$1}\" \"$2\""
29 case "$1" in *"'"*)
30 set -- "$(printf '%s\nZ\n' "$1" | sed "s/'/'\\\''/g")" "$2"
31 set -- "${1%??}" "$2"
32 esac
33 eval "$2=\"'$1'\""
36 if [ "$1" = "--cache" ]; then
37 # export all state to $PWD/TG-TEST-CACHE
38 # then return a suitable value for 'TESTLIB_CACHE'
40 # CACHE_VARS is a list of variable names to cache but only if they
41 # are actually set.
43 # EXPORT_VARS is a list of variables that should be exported.
45 # UNSET_VARS is a list of variables that should always be unset
46 # it will automatically have unwanted GIT_XXX vars added to it
48 CACHE_VARS="GIT_DEFAULT_HASH GIT_MERGE_VERBOSITY GIT_MERGE_AUTOEDIT \
49 GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM GIT_TRACE_BARE \
50 debug verbose verbose_only test_count trace LANG LC_ALL \
51 TZ _x05 _x40 LF u200c color test_git229_plus test_hash_algo \
52 immediate TESTLIB_TEST_LONG run_list help quiet \
53 say_color_error say_color_skip say_color_warn say_color_pass \
54 say_color_info say_color_ TERM TESTLIB_SHELL_HAS_SHOPT \
55 test_failure test_count test_fixed test_broken test_success \
56 test_external_has_tap last_verbose GIT_MINIMUM_VERSION \
57 TG_TEST_INSTALLED uname_s test_prereq TG_GIT_MINIMUM_VERSION \
58 TG_INST_BINDIR TG_INST_CMDDIR TG_INST_HOOKSDIR TG_VERSION \
59 TG_INST_SHAREDIR git_version test_auh tg_version UNAME_S \
60 lazily_tested_prereq satisfied_prereq PATH TESTLIB_TEST_CMP \
61 GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_PATH AWK_PATH DIFF \
62 GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_TEMPLATE_DIR \
63 EMPTY_DIRECTORY EDITOR TESTLIB_DIRECTORY TEST_DIRECTORY \
64 TEST_OUTPUT_DIRECTORY PAGER root SHELL_PATH \
65 TESTLIB_NO_TOLERATE TESTLIB_TEST_CHAIN_LINT \
66 TESTLIB_TEST_TAP_ONLY"
68 EXPORT_VARS="PATH GIT_DEFAULT_HASH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM \
69 GIT_ATTR_NOSYSTEM GIT_MERGE_VERBOSITY GIT_MERGE_AUTOEDIT \
70 GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME GIT_COMMITTER_EMAIL TZ \
71 GIT_COMMITTER_NAME EDITOR GIT_TRACE_BARE LANG LC_ALL PAGER \
72 _x05 _x40 LF u200c UNAME_S \
73 TERM SHELL_PATH GIT_PATH DIFF TG_TEST_INSTALLED \
74 test_prereq TESTLIB_NO_TOLERATE TESTLIB_TEST_LONG \
75 GIT_CEILING_DIRECTORIES TG_TEST_FULL_PATH TEST_HELPER_DIRECTORY"
77 UNSET_VARS="VISUAL EMAIL LANGUAGE COLUMNS XDG_CONFIG_HOME GITPERLLIB \
78 CDPATH GREP_OPTIONS UNZIP TESTLIB_EXIT_OK last_verbose"
80 # Add most GIT_XXX vars (variation of code from test-lib-main.sh)
81 UNSET_VARS="$UNSET_VARS $("${AWK_PATH:-awk}" '
82 BEGIN {exit} END {
83 split("\
84 TRACE \
85 DEBUG \
86 DEFAULT_HASH \
87 USE_LOOKUP \
88 TEST \
89 .*_TEST \
90 MINIMUM_VERSION \
91 PATH \
92 PROVE \
93 UNZIP \
94 PERF_ \
95 CURL_VERBOSE \
96 TRACE_CURL \
97 CEILING_DIRECTORIES \
98 ", ok, " ")
99 reok = "^GIT_("
100 for (i in ok) reok = reok ok[i] "|"
101 reok = substr(reok, 1, length(reok) - 1) ")"
102 for (e in ENVIRON) {
103 if (e ~ /^GIT_/ && e !~ reok) print e
105 }')"
107 # strip off --cache
108 shift
110 # set UNAME_S if needed
111 : "${UNAME_S:=$(uname -s)}"
113 # run the standard init but avoid doing any --tee processing now
114 . ./test-lib-main.sh
115 TESTLIB_TEST_TEE_STARTED=done
116 test_lib_main_init_generic "$@" || exit $?
117 unset_ TESTLIB_TEST_TEE_STARTED
119 if [ -n "$lazily_testable_prereq" ]; then
120 # run all the "lazy" prereq tests now in a new subdir
121 # (set up on the "--root" if selected) using setup code
122 # taken (and modified) from test-lib-main.sh so that the
123 # lazy prereqs get the same answer they would when not cached
124 TRASH_DIRECTORY="cachetest"
125 test -n "$root" && TRASH_DIRECTORY="$root/$TRASH_DIRECTORY"
126 case "$TRASH_DIRECTORY" in
127 /*) ;; # absolute path is good
128 *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$TRASH_DIRECTORY" ;;
129 esac
130 ! [ -e "$TRASH_DIRECTORY" ] || rm -fr "$TRASH_DIRECTORY" ||
131 fatal "FATAL: Cannot prepare cache test area"
132 mkdir -p "$TRASH_DIRECTORY" && [ -d "$TRASH_DIRECTORY" ] ||
133 fatal "cannot mkdir -p $TRASH_DIRECTORY"
134 TRASHTMP_DIRECTORY="$TRASH_DIRECTORY"
135 savepwd="$PWD"
136 savehome="$HOME"
137 cd -P "$TRASH_DIRECTORY" || fatal "cannot cd to $TRASH_DIRECTORY"
138 git init --quiet --template="$EMPTY_DIRECTORY" >/dev/null 2>&1 ||
139 fatal "cannot run git init"
140 HOME="$TRASH_DIRECTORY"
141 GNUPGHOME="$HOME/gnupg-home-not-used"
142 export HOME GNUPGHOME
143 for lp in $lazily_testable_prereq; do
144 ! { eval "lpscript=\$test_prereq_lazily_$lp" &&
145 (t() { eval "$lpscript";}; t) >/dev/null 2>&1;} || test_set_prereq $lp
146 lazily_tested_prereq="$lazily_tested_prereq$lp "
147 done
148 HOME="$savehome"
149 cd "$savepwd" || fatal "cannot cd to $savepwd"
150 rm -rf "$TRASH_DIRECTORY"
151 unset_ savepwd savehome TRASH_DIRECTORY TRASHTMP_DIRECTORY GNUPGHOME
154 # return true if variable name passed as the first argument is
155 # set even if to an empty value
156 isvarset() {
157 eval "test \"z\${$1+set}\" = \"zset\""
159 test_quotevar_ PWD PWD_SQ
160 test_quotevar_ TESTLIB_DIRECTORY TD_SQ
162 echo unset $UNSET_VARS "|| : &&"
163 while read vname && [ -n "$vname" ]; do
164 ! isvarset $vname || { test_quotevar_ "$vname" qv; printf '%s=%s &&\n' "$vname" "$qv"; }
165 done <<-EOT
166 $(echo $CACHE_VARS $EXPORT_VARS | LC_ALL=C sed 'y/ /\n/' | LC_ALL=C sort -u)
167 say_color_reset
169 echo export $EXPORT_VARS "&&"
170 printf '%s\n' \
171 "cd $PWD_SQ &&" \
172 ". $TD_SQ/test-lib-functions-tg.sh &&" \
173 ". $TD_SQ/test-lib-functions.sh &&" \
174 ". $TD_SQ/test-lib-main.sh &&"
175 echo "TESTLIB_CACHE_ACTIVE=1"
176 } >TG-TEST-CACHE
177 printf ". %s/TG-TEST-CACHE || { echo 'error: missing '\'%s'/TG-TEST-CACHE'\' >&2; exit 1; }\n" "$PWD_SQ" "$PWD_SQ"
178 TESTLIB_EXIT_OK=1
179 exit 0
182 # usage: whats_the_dir [-P | -L] [--] path-to-something varname
183 # determine path-to-something's directory and store it into varname
184 # without "-P" or "-L" a relative dirname may be returned
185 whats_the_dir() {
186 # determine "$1"'s directory and store it into the var name passed as "$2"
187 if [ "z$1" = "z-P" ] || [ "z$1" = "z-L" ]; then
188 if [ "z$2" = "z--" ]; then
189 set -- "$3" "$4" "$1"
190 else
191 set -- "$2" "$3" "$1"
193 elif [ "z$1" = "z--" ]; then
194 shift
196 case "$1" in *"/"*);;*) set -- "./$1" "$2" "$3"; esac
197 while [ -L "$1" ]; do
198 set -- "$(readlink "$1")" "$2" "$3" "$1"
199 case "$1" in "/"*);;*)
200 set -- "${4%/*}/$1" "$2" "$3"
201 esac
202 done
203 set -- "${1%/*}" "$2" "$3"
204 if [ "z$3" != "z" ] && [ -d "$1" ] &&
205 ! case "$1" in [!/]*|*"/./"*|*"/."|*"/../"*|*"/..") ! :; esac; then
206 [ "z$3" = "z-P" ] || set -- "$1" "$2"
207 if [ "z$3" = "z" ] && { [ "z$1" = "z." ] || [ "z$1" = "z$PWD" ]; }; then
208 set -- "$PWD" "$2"
209 else
210 set -- "$(cd "$1" && pwd $3)" "$2"
213 eval "$2=\"$1\""
216 [ -z "$TESTLIB_CACHE" ] || eval "$TESTLIB_CACHE" || exit $?
217 if [ -n "$TESTLIB_CACHE_ACTIVE" ]; then
218 # Everything should have been restored by the eval of "$TESTLIB_CACHE"
219 # Remove the leftover variables used to trigger use of the cache
220 unset_ TESTLIB_CACHE TESTLIB_CACHE_ACTIVE
222 # Handle --tee now if needed
223 test_lib_main_init_tee "$@"
225 # We must also still perform per-test initialization though
226 test_lib_main_init_specific "$@"
227 else
228 # Normal, non-cached case where we run the init function
229 whats_the_dir -- "${TEST_DIRECTORY:-.}/test-lib.sh" testlib_dir_
230 . "$testlib_dir_/test-lib-main.sh" &&
231 unset_ _testlib_dir_ &&
232 test_lib_main_init "$@"