test-lib.sh 12.0 KB
Newer Older
1 2 3 4 5
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#

6 7 8
# Keep the original TERM for say_color
ORIGINAL_TERM=$TERM

9 10
# For repeatability, reset the environment to known value.
LANG=C
11
LC_ALL=C
12
PAGER=cat
13
TZ=UTC
14 15
TERM=dumb
export LANG LC_ALL PAGER TERM TZ
16 17
EDITOR=:
VISUAL=:
18
unset GIT_EDITOR
19 20 21 22 23
unset AUTHOR_DATE
unset AUTHOR_EMAIL
unset AUTHOR_NAME
unset COMMIT_AUTHOR_EMAIL
unset COMMIT_AUTHOR_NAME
24
unset EMAIL
25 26
unset GIT_ALTERNATE_OBJECT_DIRECTORIES
unset GIT_AUTHOR_DATE
27 28
GIT_AUTHOR_EMAIL=author@example.com
GIT_AUTHOR_NAME='A U Thor'
29
unset GIT_COMMITTER_DATE
30 31
GIT_COMMITTER_EMAIL=committer@example.com
GIT_COMMITTER_NAME='C O Mitter'
32 33
unset GIT_DIFF_OPTS
unset GIT_DIR
34
unset GIT_WORK_TREE
35 36 37
unset GIT_EXTERNAL_DIFF
unset GIT_INDEX_FILE
unset GIT_OBJECT_DIRECTORY
38
unset GIT_CEILING_DIRECTORIES
39 40
unset SHA1_FILE_DIRECTORIES
unset SHA1_FILE_DIRECTORY
41 42
GIT_MERGE_VERBOSITY=5
export GIT_MERGE_VERBOSITY
43 44
export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
45
export EDITOR VISUAL
46
GIT_TEST_CMP=${GIT_TEST_CMP:-diff -u}
47

48 49 50 51
# Protect ourselves from common misconfiguration to export
# CDPATH into the environment
unset CDPATH

52
case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in
53 54 55 56 57 58 59 60
	1|2|true)
		echo "* warning: Some tests will not work if GIT_TRACE" \
			"is set as to trace on STDERR ! *"
		echo "* warning: Please set GIT_TRACE to something" \
			"other than 1, 2 or true ! *"
		;;
esac

61 62 63 64 65 66
# Each test should start with something like this, after copyright notices:
#
# test_description='Description of this test...
# This test checks if command xyzzy does the right thing...
# '
# . ./test-lib.sh
67 68 69 70 71 72 73 74
[ "x$ORIGINAL_TERM" != "xdumb" ] && (
		TERM=$ORIGINAL_TERM &&
		export TERM &&
		[ -t 1 ] &&
		tput bold >/dev/null 2>&1 &&
		tput setaf 1 >/dev/null 2>&1 &&
		tput sgr0 >/dev/null 2>&1
	) &&
75
	color=t
76 77 78 79 80 81

while test "$#" -ne 0
do
	case "$1" in
	-d|--d|--de|--deb|--debu|--debug)
		debug=t; shift ;;
J
Junio C Hamano 已提交
82 83
	-i|--i|--im|--imm|--imme|--immed|--immedi|--immedia|--immediat|--immediate)
		immediate=t; shift ;;
84 85
	-l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
		export GIT_TEST_LONG=t; shift ;;
86
	-h|--h|--he|--hel|--help)
87
		help=t; shift ;;
88 89
	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
		verbose=t; shift ;;
90 91
	-q|--q|--qu|--qui|--quie|--quiet)
		quiet=t; shift ;;
92
	--no-color)
93
		color=; shift ;;
94
	--no-python)
J
Junio C Hamano 已提交
95 96
		# noop now...
		shift ;;
97 98 99 100 101
	*)
		break ;;
	esac
done

102 103
if test -n "$color"; then
	say_color () {
104 105 106
		(
		TERM=$ORIGINAL_TERM
		export TERM
107 108 109 110 111
		case "$1" in
			error) tput bold; tput setaf 1;; # bold red
			skip)  tput bold; tput setaf 2;; # bold green
			pass)  tput setaf 2;;            # green
			info)  tput setaf 3;;            # brown
112
			*) test -n "$quiet" && return;;
113 114
		esac
		shift
S
Shawn O. Pearce 已提交
115
		printf "* %s" "$*"
116
		tput sgr0
117
		echo
118
		)
119 120 121
	}
else
	say_color() {
122
		test -z "$1" && test -n "$quiet" && return
123 124 125 126 127 128 129
		shift
		echo "* $*"
	}
fi

error () {
	say_color error "error: $*"
130
	trap - EXIT
131 132 133 134 135 136 137
	exit 1
}

say () {
	say_color info "$*"
}

138 139 140 141 142 143 144 145 146
test "${test_description}" != "" ||
error "Test script did not set test_description."

if test "$help" = "t"
then
	echo "$test_description"
	exit 0
fi

147
exec 5>&1
148 149 150 151 152 153 154 155 156
if test "$verbose" = "t"
then
	exec 4>&2 3>&1
else
	exec 4>/dev/null 3>/dev/null
fi

test_failure=0
test_count=0
J
Junio C Hamano 已提交
157 158
test_fixed=0
test_broken=0
159
test_success=0
160

161 162 163 164 165
die () {
	echo >&5 "FATAL: Unexpected exit with code $?"
	exit 1
}

166
trap 'die' EXIT
167

168 169 170 171 172 173 174 175
# The semantics of the editor variables are that of invoking
# sh -c "$EDITOR \"$@\"" files ...
#
# If our trash directory contains shell metacharacters, they will be
# interpreted if we just set $EDITOR directly, so do a little dance with
# environment variables to work around this.
#
# In particular, quoting isn't enough, as the path may contain the same quote
176
# that we're using.
177 178 179 180 181 182 183
test_set_editor () {
	FAKE_EDITOR="$1"
	export FAKE_EDITOR
	VISUAL='"$FAKE_EDITOR"'
	export VISUAL
}

184 185 186
test_tick () {
	if test -z "${test_tick+set}"
	then
J
Junio C Hamano 已提交
187
		test_tick=1112911993
188 189 190
	else
		test_tick=$(($test_tick + 60))
	fi
J
Junio C Hamano 已提交
191 192
	GIT_COMMITTER_DATE="$test_tick -0700"
	GIT_AUTHOR_DATE="$test_tick -0700"
193 194
	export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
}
195

J
Junio C Hamano 已提交
196 197 198 199
# You are not expected to call test_ok_ and test_failure_ directly, use
# the text_expect_* functions instead.

test_ok_ () {
200
	test_count=$(expr "$test_count" + 1)
201
	test_success=$(expr "$test_success" + 1)
202
	say_color "" "  ok $test_count: $@"
203 204
}

J
Junio C Hamano 已提交
205
test_failure_ () {
206 207
	test_count=$(expr "$test_count" + 1)
	test_failure=$(expr "$test_failure" + 1);
208
	say_color error "FAIL $test_count: $1"
209 210
	shift
	echo "$@" | sed -e 's/^/	/'
211
	test "$immediate" = "" || { trap - EXIT; exit 1; }
J
Junio C Hamano 已提交
212 213
}

J
Junio C Hamano 已提交
214 215 216 217 218 219 220 221 222 223 224
test_known_broken_ok_ () {
	test_count=$(expr "$test_count" + 1)
	test_fixed=$(($test_fixed+1))
	say_color "" "  FIXED $test_count: $@"
}

test_known_broken_failure_ () {
	test_count=$(expr "$test_count" + 1)
	test_broken=$(($test_broken+1))
	say_color skip "  still broken $test_count: $@"
}
J
Junio C Hamano 已提交
225 226

test_debug () {
227
	test "$debug" = "" || eval "$1"
228 229
}

230 231 232 233 234 235
test_run_ () {
	eval >&3 2>&4 "$1"
	eval_ret="$?"
	return 0
}

236 237 238 239 240 241 242 243 244 245 246 247 248
test_skip () {
	this_test=$(expr "./$0" : '.*/\(t[0-9]*\)-[^/]*$')
	this_test="$this_test.$(expr "$test_count" + 1)"
	to_skip=
	for skp in $GIT_SKIP_TESTS
	do
		case "$this_test" in
		$skp)
			to_skip=t
		esac
	done
	case "$to_skip" in
	t)
249
		say_color skip >&3 "skipping test: $@"
250
		test_count=$(expr "$test_count" + 1)
251
		say_color skip "skip $test_count: $1"
252 253 254 255 256 257 258 259
		: true
		;;
	*)
		false
		;;
	esac
}

260
test_expect_failure () {
261
	test "$#" = 2 ||
262
	error "bug in the test script: not 2 parameters to test-expect-failure"
263
	if ! test_skip "$@"
264
	then
J
Junio C Hamano 已提交
265
		say >&3 "checking known breakage: $2"
266
		test_run_ "$2"
J
Junio C Hamano 已提交
267
		if [ "$?" = 0 -a "$eval_ret" = 0 ]
268
		then
J
Junio C Hamano 已提交
269
			test_known_broken_ok_ "$1"
270
		else
J
Junio C Hamano 已提交
271
		    test_known_broken_failure_ "$1"
272
		fi
273
	fi
274
	echo >&3 ""
275 276 277
}

test_expect_success () {
278
	test "$#" = 2 ||
279
	error "bug in the test script: not 2 parameters to test-expect-success"
280
	if ! test_skip "$@"
281
	then
282 283 284 285 286 287 288 289
		say >&3 "expecting success: $2"
		test_run_ "$2"
		if [ "$?" = 0 -a "$eval_ret" = 0 ]
		then
			test_ok_ "$1"
		else
			test_failure_ "$@"
		fi
290
	fi
291
	echo >&3 ""
292 293
}

294 295 296
test_expect_code () {
	test "$#" = 3 ||
	error "bug in the test script: not 3 parameters to test-expect-code"
297
	if ! test_skip "$@"
298
	then
299 300 301 302 303 304 305 306
		say >&3 "expecting exit code $1: $3"
		test_run_ "$3"
		if [ "$?" = 0 -a "$eval_ret" = "$1" ]
		then
			test_ok_ "$2"
		else
			test_failure_ "$@"
		fi
307
	fi
308
	echo >&3 ""
309 310
}

311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
# test_external runs external test scripts that provide continuous
# test output about their progress, and succeeds/fails on
# zero/non-zero exit code.  It outputs the test output on stdout even
# in non-verbose mode, and announces the external script with "* run
# <n>: ..." before running it.  When providing relative paths, keep in
# mind that all scripts run in "trash directory".
# Usage: test_external description command arguments...
# Example: test_external 'Perl API' perl ../path/to/test.pl
test_external () {
	test "$#" -eq 3 ||
	error >&5 "bug in the test script: not 3 parameters to test_external"
	descr="$1"
	shift
	if ! test_skip "$descr" "$@"
	then
		# Announce the script to reduce confusion about the
		# test output that follows.
		say_color "" " run $(expr "$test_count" + 1): $descr ($*)"
		# Run command; redirect its stderr to &4 as in
		# test_run_, but keep its stdout on our stdout even in
		# non-verbose mode.
		"$@" 2>&4
		if [ "$?" = 0 ]
		then
			test_ok_ "$descr"
		else
			test_failure_ "$descr" "$@"
		fi
	fi
}

# Like test_external, but in addition tests that the command generated
# no output on stderr.
test_external_without_stderr () {
	# The temporary file has no (and must have no) security
	# implications.
	tmp="$TMPDIR"; if [ -z "$tmp" ]; then tmp=/tmp; fi
	stderr="$tmp/git-external-stderr.$$.tmp"
	test_external "$@" 4> "$stderr"
	[ -f "$stderr" ] || error "Internal error: $stderr disappeared."
	descr="no stderr: $1"
	shift
	say >&3 "expecting no stderr from previous command"
	if [ ! -s "$stderr" ]; then
		rm "$stderr"
		test_ok_ "$descr"
	else
		if [ "$verbose" = t ]; then
			output=`echo; echo Stderr is:; cat "$stderr"`
		else
			output=
		fi
		# rm first in case test_failure exits.
		rm "$stderr"
		test_failure_ "$descr" "$@" "$output"
	fi
}

J
Junio C Hamano 已提交
369 370 371 372 373 374 375 376 377 378 379 380 381 382
# This is not among top-level (test_expect_success | test_expect_failure)
# but is a prefix that can be used in the test script, like:
#
#	test_expect_success 'complain and die' '
#           do something &&
#           do something else &&
#	    test_must_fail git checkout ../outerspace
#	'
#
# Writing this as "! git checkout ../outerspace" is wrong, because
# the failure could be due to a segv.  We want a controlled failure.

test_must_fail () {
	"$@"
383
	test $? -gt 0 -a $? -le 129 -o $? -gt 192
J
Junio C Hamano 已提交
384 385
}

386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
# test_cmp is a helper function to compare actual and expected output.
# You can use it like:
#
#	test_expect_success 'foo works' '
#		echo expected >expected &&
#		foo >actual &&
#		test_cmp expected actual
#	'
#
# This could be written as either "cmp" or "diff -u", but:
# - cmp's output is not nearly as easy to read as diff -u
# - not all diff versions understand "-u"

test_cmp() {
	$GIT_TEST_CMP "$@"
}

403
# Most tests can use the created repository, but some may need to create more.
404 405 406 407 408 409
# Usage: test_create_repo <directory>
test_create_repo () {
	test "$#" = 1 ||
	error "bug in the test script: not 1 parameter to test-create-repo"
	owd=`pwd`
	repo="$1"
410
	mkdir -p "$repo"
411
	cd "$repo" || error "Cannot setup test environment"
412
	"$GIT_EXEC_PATH/git" init "--template=$GIT_EXEC_PATH/templates/blt/" >&3 2>&4 ||
413
	error "cannot run git init -- have you built things yet?"
414 415 416
	mv .git/hooks .git/hooks-disabled
	cd "$owd"
}
J
Junio C Hamano 已提交
417

418
test_done () {
419
	trap - EXIT
420 421 422 423 424 425 426 427 428 429
	test_results_dir="$TEST_DIRECTORY/test-results"
	mkdir -p "$test_results_dir"
	test_results_path="$test_results_dir/${0%-*}-$$"

	echo "total $test_count" >> $test_results_path
	echo "success $test_success" >> $test_results_path
	echo "fixed $test_fixed" >> $test_results_path
	echo "broken $test_broken" >> $test_results_path
	echo "failed $test_failure" >> $test_results_path
	echo "" >> $test_results_path
J
Junio C Hamano 已提交
430 431 432 433 434 435 436 437

	if test "$test_fixed" != 0
	then
		say_color pass "fixed $test_fixed known breakage(s)"
	fi
	if test "$test_broken" != 0
	then
		say_color error "still have $test_broken known breakage(s)"
438 439 440
		msg="remaining $(($test_count-$test_broken)) test(s)"
	else
		msg="$test_count test(s)"
J
Junio C Hamano 已提交
441
	fi
442
	case "$test_failure" in
443
	0)
444
		# We could:
445
		# cd .. && rm -fr 'trash directory'
446 447 448 449 450 451
		# but that means we forbid any tests that use their own
		# subdirectory from calling test_done without coming back
		# to where they started from.
		# The Makefile provided will clean this test area so
		# we will leave things as they are.

452
		say_color pass "passed all $msg"
J
Johannes Schindelin 已提交
453 454 455 456 457

		test -d "$remove_trash" &&
		cd "$(dirname "$remove_trash")" &&
		rm -rf "$(basename "$remove_trash")"

458 459 460
		exit 0 ;;

	*)
461
		say_color error "failed $test_failure among $msg"
462 463 464 465 466 467
		exit 1 ;;

	esac
}

# Test the binaries we have just built.  The tests are kept in
468
# t/ subdirectory and are run in 'trash directory' subdirectory.
469 470
TEST_DIRECTORY=$(pwd)
PATH=$TEST_DIRECTORY/..:$PATH
J
Johannes Schindelin 已提交
471
GIT_EXEC_PATH=$(pwd)/..
J
Johannes Schindelin 已提交
472
GIT_TEMPLATE_DIR=$(pwd)/../templates/blt
J
Jeff King 已提交
473 474 475 476
unset GIT_CONFIG
GIT_CONFIG_NOSYSTEM=1
GIT_CONFIG_NOGLOBAL=1
export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOBAL
477

478 479
GITPERLLIB=$(pwd)/../perl/blib/lib:$(pwd)/../perl/blib/arch/auto/Git
export GITPERLLIB
480 481 482
test -d ../templates/blt || {
	error "You haven't built things yet, have you?"
}
483

E
Eric Wong 已提交
484 485 486 487 488 489
if ! test -x ../test-chmtime; then
	echo >&2 'You need to build test-chmtime:'
	echo >&2 'Run "make test-chmtime" in the source (toplevel) directory'
	exit 1
fi

490 491
. ../GIT-BUILD-OPTIONS

492
# Test repository
J
Johannes Schindelin 已提交
493
test="trash directory.$(basename "$0" .sh)"
494
test ! -z "$debug" || remove_trash="$TEST_DIRECTORY/$test"
495
rm -fr "$test" || {
496
	trap - EXIT
497 498 499 500
	echo >&5 "FATAL: Cannot prepare test area"
	exit 1
}

501
test_create_repo "$test"
502 503 504
# Use -P to resolve symlinks in our working directory so that the cwd
# in subprocesses like git equals our $PWD (for pathname comparisons).
cd -P "$test" || exit 1
505 506 507 508 509 510 511 512 513 514 515 516 517 518

this_test=$(expr "./$0" : '.*/\(t[0-9]*\)-[^/]*$')
for skp in $GIT_SKIP_TESTS
do
	to_skip=
	for skp in $GIT_SKIP_TESTS
	do
		case "$this_test" in
		$skp)
			to_skip=t
		esac
	done
	case "$to_skip" in
	t)
519 520
		say_color skip >&3 "skipping test $this_test altogether"
		say_color skip "skip all tests in $this_test"
521 522 523
		test_done
	esac
done