1#!/bin/sh
2. tests/shlib/common.sh
3
4enter_suite shell final
5
6if test $# -eq 0 ; then
7	FAST=1
8fi
9ONLY_SHELL="$1"
10ONLY_TEST_TYPE="$2"
11ONLY_TEST_CLIENT="$3"
12
13export PYTHON
14
15if test "$ONLY_SHELL" = "--help" ; then
16cat << EOF
17Usage:
18	$0 [[[ONLY_SHELL | ""] (ONLY_TEST_TYPE | "")] (ONLY_TEST_CLIENT | "")]
19
20ONLY_SHELL: execute only tests for given shell
21ONLY_TEST_TYPE: execute only "daemon" or "nodaemon" tests
22ONLY_TEST_CLIENT: use only given test client (one of C, python, render, shell)
23EOF
24exit 0
25fi
26
27check_screen_log() {
28	TEST_TYPE="$1"
29	TEST_CLIENT="$2"
30	SH="$3"
31	if test -e "$ROOT/tests/test_shells/outputs/${SH}.${TEST_TYPE}.ok" ; then
32		diff -a -u "$ROOT/tests/test_shells/outputs/${SH}.${TEST_TYPE}.ok" \
33		           "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log"
34		return $?
35	elif test -e "$ROOT/tests/test_shells/outputs/${SH}.ok" ; then
36		diff -a -u "$ROOT/tests/test_shells/outputs/${SH}.ok" \
37		           "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log"
38		return $?
39	else
40		cat "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log"
41		return 1
42	fi
43}
44
45# HACK: get newline for use in strings given that "\n" and $'' do not work.
46NL="$(printf '\nE')"
47NL="${NL%E}"
48
49print_full_output() {
50	TEST_TYPE="$1"
51	TEST_CLIENT="$2"
52	SH="$3"
53	echo "Full output:"
54	echo '============================================================'
55	cat "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.full.log"
56	echo
57	echo '____________________________________________________________'
58	if test "$POWERLINE_TEST_NO_CAT_V" != "1" ; then
59		echo "Full output (cat -v):"
60		echo '============================================================'
61		cat -v "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.full.log"
62		echo
63		echo '____________________________________________________________'
64	fi
65}
66
67do_run_test() {
68	TEST_TYPE="$1"
69	shift
70	TEST_CLIENT="$1"
71	shift
72	SH="$1"
73
74	local wait_for_echo_arg=
75	if ( \
76		test "${SH}" = "dash" \
77		|| ( \
78			test "${SH}" = "pdb" \
79			&& ( \
80				( \
81					test "$PYTHON_VERSION_MAJOR" -eq 3 \
82					&& test "$PYTHON_VERSION_MINOR" -eq 2 \
83					&& test "$PYTHON_IMPLEMENTATION" = "CPython" \
84				) \
85				|| test "$PYTHON_IMPLEMENTATION" = "PyPy" \
86			) \
87		) \
88		|| ( \
89			test "${SH}" = "ipython" \
90			&& test "$("${PYTHON}" -mIPython --version | head -n1 | cut -d. -f1)" -ge 5 \
91		) \
92	) ; then
93		wait_for_echo_arg="--wait-for-echo"
94	fi
95	"${PYTHON}" tests/test_shells/run_script.py \
96		$wait_for_echo_arg --type=${TEST_TYPE} --client=${TEST_CLIENT} --shell=${SH} \
97		"$@"
98	if ! check_screen_log ${TEST_TYPE} ${TEST_CLIENT} ${SH} ; then
99		echo '____________________________________________________________'
100		if test "$POWERLINE_TEST_NO_CAT_V" != "1" ; then
101			# Repeat the diff to make it better viewable in travis output
102			echo "Diff (cat -v):"
103			echo '============================================================'
104			check_screen_log  ${TEST_TYPE} ${TEST_CLIENT} ${SH} | cat -v
105			echo '____________________________________________________________'
106		fi
107		echo -n "Failed ${SH}. "
108		print_full_output ${TEST_TYPE} ${TEST_CLIENT} ${SH}
109		case "${SH}" in
110			*ksh)
111				"$TEST_ROOT/path/${SH}" -c 'echo ${KSH_VERSION}'
112				;;
113			dash)
114				# ?
115				;;
116			busybox)
117				busybox --help
118				;;
119			*)
120				"$TEST_ROOT/path/${SH}" --version
121				;;
122		esac
123		if which dpkg >/dev/null ; then
124			dpkg -s ${SH}
125		fi
126		return 1
127	fi
128	return 0
129}
130
131run_test() {
132	TEST_TYPE="$1"
133	TEST_CLIENT="$2"
134	SH="$3"
135	local attempts=3
136	if test -n "$ONLY_SHELL$ONLY_TEST_TYPE$ONLY_TEST_CLIENT" ; then
137		attempts=1
138	fi
139	while test $attempts -gt 0 ; do
140		rm -f "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log"
141		rm -f "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.full.log"
142		do_run_test "$@" && return 0
143		attempts=$(( attempts - 1 ))
144	done
145	return 1
146}
147
148make_test_root
149
150git init "$TEST_ROOT/3rd"
151git --git-dir="$TEST_ROOT/3rd/.git" checkout -b BRANCH
152export DIR1=""
153export DIR2=""
154mkdir "$TEST_ROOT/3rd/$DIR1"
155mkdir "$TEST_ROOT/3rd/$DIR2"
156mkdir "$TEST_ROOT"/3rd/'\[\]'
157mkdir "$TEST_ROOT"/3rd/'%%'
158mkdir "$TEST_ROOT"/3rd/'#[bold]'
159mkdir "$TEST_ROOT"/3rd/'(echo)'
160mkdir "$TEST_ROOT"/3rd/'$(echo)'
161mkdir "$TEST_ROOT"/3rd/'`echo`'
162mkdir "$TEST_ROOT"/3rd/'«Unicode!»'
163
164mkdir "$TEST_ROOT/fish_home"
165mkdir "$TEST_ROOT/fish_home/fish"
166mkdir "$TEST_ROOT/fish_home/fish/generated_completions"
167cp -r "$ROOT/tests/test_shells/ipython_home" "$TEST_ROOT"
168
169mkdir "$TEST_ROOT/path"
170ln -s "$(which "${PYTHON}")" "$TEST_ROOT/path/python"
171ln -s "$(which env)" "$TEST_ROOT/path"
172ln -s "$(which git)" "$TEST_ROOT/path"
173ln -s "$(which sleep)" "$TEST_ROOT/path"
174ln -s "$(which cat)" "$TEST_ROOT/path"
175ln -s "$(which false)" "$TEST_ROOT/path"
176ln -s "$(which true)" "$TEST_ROOT/path"
177ln -s "$(which kill)" "$TEST_ROOT/path"
178ln -s "$(which echo)" "$TEST_ROOT/path"
179ln -s "$(which which)" "$TEST_ROOT/path"
180ln -s "$(which dirname)" "$TEST_ROOT/path"
181ln -s "$(which wc)" "$TEST_ROOT/path"
182ln -s "$(which stty)" "$TEST_ROOT/path"
183ln -s "$(which cut)" "$TEST_ROOT/path"
184ln -s "$(which bc)" "$TEST_ROOT/path"
185ln -s "$(which expr)" "$TEST_ROOT/path"
186ln -s "$(which mktemp)" "$TEST_ROOT/path"
187ln -s "$(which grep)" "$TEST_ROOT/path"
188ln -s "$(which sed)" "$TEST_ROOT/path"
189ln -s "$(which rm)" "$TEST_ROOT/path"
190ln -s "$(which tr)" "$TEST_ROOT/path"
191ln -s "$(which uname)" "$TEST_ROOT/path"
192ln -s "$(which test)" "$TEST_ROOT/path"
193ln -s "$(which pwd)" "$TEST_ROOT/path"
194ln -s "$(which hostname)" "$TEST_ROOT/path"
195ln -s "$ROOT/tests/test_shells/bgscript.sh" "$TEST_ROOT/path"
196ln -s "$ROOT/tests/test_shells/waitpid.sh" "$TEST_ROOT/path"
197if which socat ; then
198	ln -s "$(which socat)" "$TEST_ROOT/path"
199fi
200for pexe in powerline powerline-config powerline-render powerline.sh powerline.py ; do
201	if test -e "$ROOT/scripts/$pexe" ; then
202		ln -s "$ROOT/scripts/$pexe" "$TEST_ROOT/path"
203	elif test -e client/$pexe ; then
204		ln -s "$ROOT/client/$pexe" "$TEST_ROOT/path"
205	elif which $pexe ; then
206		ln -s "$(which $pexe)" "$TEST_ROOT/path"
207	else
208		echo "Executable $pexe was not found"
209		exit 1
210	fi
211done
212
213ln -s python "$TEST_ROOT/path/pdb"
214PDB_PYTHON=pdb
215ln -s python "$TEST_ROOT/path/ipython"
216IPYTHON_PYTHON=ipython
217
218if test -z "$POWERLINE_RC_EXE" ; then
219	if which rc-status >/dev/null ; then
220		# On Gentoo `rc` executable is from OpenRC. Thus app-shells/rc instals
221		# `rcsh` executable.
222		POWERLINE_RC_EXE=rcsh
223	else
224		POWERLINE_RC_EXE=rc
225	fi
226fi
227
228if which "$POWERLINE_RC_EXE" >/dev/null ; then
229	ln -s "$(which $POWERLINE_RC_EXE)" "$TEST_ROOT/path/rc"
230fi
231
232exes="bash zsh busybox tcsh mksh"
233
234if test "$TRAVIS" != "true" ; then
235	# For some reason fish does not work on travis
236	exes="$exes fish"
237fi
238
239# dash has some problems with job control
240#exes="$exes dash"
241
242for exe in $exes ; do
243	if which $exe >/dev/null ; then
244		if test "$exe" = "fish" ; then
245			fish_version="$(fish --version 2>&1)"
246			fish_version="${fish_version##* }"
247			fish_version_major="${fish_version%%.*}"
248			if test "$fish_version_major" != "$fish_version" ; then
249				# No dot is in development version compiled by bot-ci
250				fish_version_minor="${fish_version#*.}"
251				fish_version_patch="${fish_version_minor#*.}"
252				fish_version_dev="${fish_version_patch#*-}"
253				if test "$fish_version_dev" = "$fish_version_patch" ; then
254					fish_version_dev=""
255				fi
256				fish_version_minor="${fish_version_minor%%.*}"
257				fish_version_patch="${fish_version_patch%%-*}"
258				if test $fish_version_major -lt 2 || ( \
259					test $fish_version_major -eq 2 && (\
260						test $fish_version_minor -lt 1 || (\
261							test $fish_version_minor -eq 1 &&
262							test $fish_version_patch -lt 2 && \
263							test -z "$fish_version_dev"
264						) \
265					) \
266				) ; then
267					continue
268				fi
269			fi
270		fi
271		ln -s "$(which $exe)" "$TEST_ROOT/path"
272	fi
273done
274
275mkdir "$TEST_ROOT/home"
276export HOME="$TEST_ROOT/home"
277
278unset ENV
279
280export ADDRESS="powerline-ipc-test-$$"
281export PYTHON
282echo "Powerline address: $ADDRESS"
283
284check_test_client() {
285	local executable="$1"
286	local client_type="$2"
287	local actual_mime_type="$(
288		file --mime-type --brief --dereference "$TEST_ROOT/path/$executable" \
289		| cut -d/ -f1
290	)"
291	local expected_mime_type
292	case "$client_type" in
293		C)      expected_mime_type="application/x-executable" ;;
294		python) expected_mime_type="text/x-python" ;;
295		render) expected_mime_type="text/x-python" ;;
296		shell)  expected_mime_type="text/x-shellscript" ;;
297	esac
298	expected_mime_type="${expected_mime_type%/*}"
299	if test "$expected_mime_type" != "$actual_mime_type" ; then
300		fail "MIME-$executable" "M" "Expected $executable to have MIME type $expected_mime_type, but got $actual_mime_type"
301	fi
302}
303
304if ( \
305	test -z "${ONLY_SHELL}" \
306	|| test "${ONLY_SHELL%sh}" != "${ONLY_SHELL}" \
307	|| test "${ONLY_SHELL}" = "busybox" \
308	|| test "${ONLY_SHELL}" = "rc" \
309) ; then
310	scripts/powerline-config shell command
311
312	for TEST_TYPE in "daemon" "nodaemon" ; do
313		if test -n "$ONLY_TEST_TYPE" && test "$ONLY_TEST_TYPE" != "$TEST_TYPE"
314		then
315			continue
316		fi
317		if test "$FAST" = 1 ; then
318			if test $TEST_TYPE = daemon ; then
319				VARIANTS=3
320			else
321				VARIANTS=4
322			fi
323			EXETEST="$(( ${RANDOM:-`date +%N | sed s/^0*//`} % $VARIANTS ))"
324			echo "Execute tests: $EXETEST"
325		fi
326
327		if test $TEST_TYPE = daemon ; then
328			sh -c '
329				echo $$ > "$TEST_ROOT/daemon_pid"
330				exec "$PYTHON" ./scripts/powerline-daemon -s"$ADDRESS" -f >"$TEST_ROOT/daemon_log" 2>&1
331			' &
332		fi
333		echo "> Testing $TEST_TYPE"
334		I=-1
335		for POWERLINE_COMMAND in \
336			powerline \
337			powerline-render \
338			powerline.py \
339			powerline.sh
340		do
341			case "$POWERLINE_COMMAND" in
342				powerline)        TEST_CLIENT=C ;;
343				powerline-render) TEST_CLIENT=render ;;
344				powerline.py)     TEST_CLIENT=python ;;
345				powerline.sh)     TEST_CLIENT=shell ;;
346			esac
347			check_test_client "$POWERLINE_COMMAND" $TEST_CLIENT
348			if test "$TEST_CLIENT" = render && test "$TEST_TYPE" = daemon ; then
349				continue
350			fi
351			I="$(( I + 1 ))"
352			if test "$TEST_CLIENT" = "C" && ! test -x "$ROOT/scripts/powerline"
353			then
354				if which powerline >/dev/null ; then
355					POWERLINE_COMMAND=powerline
356				else
357					continue
358				fi
359			fi
360			if ( \
361				test "$TEST_CLIENT" = "shell" \
362				&& ! test -x "$TEST_ROOT/path/socat" \
363			) ; then
364				continue
365			fi
366			if ( \
367				test -n "$ONLY_TEST_CLIENT" \
368				&& test "$TEST_CLIENT" != "$ONLY_TEST_CLIENT" \
369			) ; then
370				continue
371			fi
372			export POWERLINE_COMMAND_ARGS="--socket $ADDRESS"
373			export POWERLINE_COMMAND="$POWERLINE_COMMAND"
374			echo ">> powerline command is ${POWERLINE_COMMAND:-empty}"
375			J=-1
376			for TEST_COMMAND in \
377				"bash --norc --noprofile -i" \
378				"zsh -f -i" \
379				"fish -i" \
380				"tcsh -f -i" \
381				"busybox ash -i" \
382				"mksh -i" \
383				"dash -i" \
384				"rc -i -p"
385			do
386				J="$(( J + 1 ))"
387				if test "$FAST" = 1 ; then
388					if test $(( (I + J) % $VARIANTS )) -ne $EXETEST ; then
389						continue
390					fi
391				fi
392				SH="${TEST_COMMAND%% *}"
393				if test -n "$ONLY_SHELL" && test "$ONLY_SHELL" != "$SH" ; then
394					continue
395				fi
396				if ! test -x "$TEST_ROOT/path/$SH" ; then
397					continue
398				fi
399				echo ">>> $(readlink "$TEST_ROOT/path/$SH")"
400				if ! run_test $TEST_TYPE $TEST_CLIENT $TEST_COMMAND ; then
401					fail "$SH-$TEST_TYPE-$TEST_CLIENT:test" F \
402						"Failed checking $TEST_COMMAND"
403				fi
404			done
405		done
406		if test $TEST_TYPE = daemon ; then
407			"$PYTHON" ./scripts/powerline-daemon -s"$ADDRESS" -k
408			wait $(cat "$TEST_ROOT/daemon_pid")
409			if ! test -z "$(cat "$TEST_ROOT/daemon_log")" ; then
410				echo '____________________________________________________________'
411				echo "Daemon log:"
412				echo '============================================================'
413				cat "$TEST_ROOT/daemon_log"
414				fail "$SH-$TEST_TYPE-$TEST_CLIENT:log" E \
415					"Non-empty daemon log for ${TEST_COMMAND}"
416			fi
417		fi
418	done
419fi
420
421if "$PYTHON" scripts/powerline-daemon -s"$ADDRESS" \
422	> "$TEST_ROOT/daemon_log_2" 2>&1
423then
424	sleep 1
425	"$PYTHON" scripts/powerline-daemon -s"$ADDRESS" -k
426else
427	fail "daemon:run" F "Daemon exited with status $?"
428fi
429
430if ! test -z "$(cat "$TEST_ROOT/daemon_log_2")" ; then
431	echo '____________________________________________________________'
432	echo "Daemon log (2nd):"
433	echo '============================================================'
434	cat "$TEST_ROOT/daemon_log_2"
435	fail "daemon:log" E "Daemon run with non-empty log"
436fi
437
438if ( test -z "${ONLY_SHELL}" || test "${ONLY_SHELL}" = "zsh" ) \
439	&& ( test -z "${ONLY_TEST_TYPE}" || test "${ONLY_TEST_TYPE}" = "zpython" ) \
440	&& "$TEST_ROOT/path/zsh" "$ROOT/tests/test_shells/zsh_test_script.zsh"
441then
442	echo "> zpython"
443	if ! run_test zpython zpython zsh -f -i ; then
444		fail "zsh-zpython:test" F "Failed checking zsh -f -i"
445	fi
446fi
447
448if  test -z "${ONLY_SHELL}" || test "${ONLY_SHELL}" = "pdb" ; then
449	if test "$PYTHON_IMPLEMENTATION" != "PyPy" ; then
450		if test -z "${ONLY_TEST_TYPE}" || test "${ONLY_TEST_TYPE}" = "subclass"
451		then
452			echo "> pdb subclass"
453			if ! run_test subclass python $PDB_PYTHON \
454				"$ROOT/tests/test_shells/pdb-main.py"
455			then
456				fail --allow-failure "pdb-subclass:test" F \
457					"Failed checking $PDB_PYTHON $ROOT/tests/test_shells/pdb-main.py"
458			fi
459		fi
460		if test -z "${ONLY_TEST_TYPE}" || test "${ONLY_TEST_TYPE}" = "module" ; then
461			echo "> pdb module"
462			MODULE="powerline.bindings.pdb"
463			if test "$PYTHON_MM" = "2.6" ; then
464				MODULE="powerline.bindings.pdb.__main__"
465			fi
466			if ! run_test module python "$PDB_PYTHON" -m"$MODULE" \
467				"$ROOT/tests/test_shells/pdb-script.py"
468			then
469				fail --allow-failure "pdb-module:test" F \
470					"Failed checking $PDB_PYTHON -m$MODULE $ROOT/tests/test_shells/pdb-script"
471			fi
472		fi
473	fi
474fi
475
476if test -z "${ONLY_SHELL}" || test "${ONLY_SHELL}" = "ipython" ; then
477	if "${PYTHON}" -c "try: import IPython${NL}except ImportError: raise SystemExit(1)" ; then
478		# Define some overrides which should be ignored by IPython.
479		export POWERLINE_CONFIG_OVERRIDES='common.term_escape_style=fbterm'
480		export POWERLINE_THEME_OVERRIDES='in.segments.left=[]'
481		echo "> ipython"
482		if ! run_test ipython ipython ${IPYTHON_PYTHON} -mIPython ; then
483			# Do not allow ipython tests to spoil the build
484			fail --allow-failure "ipython:test" F "Failed checking ${IPYTHON_PYTHON} -mIPython"
485		fi
486		unset POWERLINE_THEME_OVERRIDES
487		unset POWERLINE_CONFIG_OVERRIDES
488	fi
489fi
490
491exit_suite
492