@@ -73,6 +73,7 @@ export ASAN_OPTIONS=detect_leaks=false
73
73
export TEST_OPTS=" ${TEST_OPTS:- } "
74
74
# Used by tig_script to set the test "scope" used by test_tig.
75
75
export TEST_NAME=
76
+ export TEST_KEYSTROKES=
76
77
77
78
[ -e " $output_dir " ] && rm -rf -- " $output_dir "
78
79
mkdir -p -- " $output_dir /$work_dir "
@@ -174,8 +175,15 @@ tig_script() {
174
175
export TIG_SCRIPT=" $HOME /${prefix} steps"
175
176
export TEST_NAME=" $name "
176
177
177
- # Ensure that the steps finish by quitting
178
- printf ' %s\n:quit\n' " $* " \
178
+ if [ -z " ${TEST_KEYSTROKES:- } " ]; then
179
+ # ensure that the steps finish by quitting
180
+ quit_str=' :quit'
181
+ else
182
+ # unless simulated keystrokes are also to be sent
183
+ quit_str=' '
184
+ fi
185
+
186
+ printf ' %s\n%s\n' " $* " " $quit_str " \
179
187
| sed -e ' s/^[ ]*//' \
180
188
| sed " s|:save-display[ ]\{1,\}\([^ ]\{1,\}\)|:save-display $HOME /\1|" \
181
189
| sed " s|:save-options[ ]\{1,\}\([^ ]\{1,\}\)|:save-options $HOME /\1|" \
@@ -187,6 +195,84 @@ steps() {
187
195
tig_script " " " $@ "
188
196
}
189
197
198
+ _tig_keystrokes_driver ()
199
+ {
200
+ file=" $1 " ; shift
201
+ append_mode=" $1 " ; shift
202
+
203
+ if [ -n " $append_mode " ]; then
204
+ printf ' %s' " $* " >> " $file "
205
+ else
206
+ printf ' %s' " $* " > " $file "
207
+ fi
208
+ }
209
+
210
+ tig_keystrokes ()
211
+ {
212
+ name=" $1 " ; shift
213
+ prefix=" ${name: +$name .} "
214
+
215
+ export TEST_KEYSTROKES=" $HOME /${prefix} keystrokes"
216
+ export TEST_NAME=" $name "
217
+
218
+ append_mode=' '
219
+ keysym_mode=' '
220
+ repeat_mode=' '
221
+ while [ " $# " -gt 0 ]; do
222
+ case " $1 " in
223
+ -append|--append) append_mode=yes && shift ;;
224
+ -keysym|--keysym|-keysyms|--keysyms) keysym_mode=yes && shift ;;
225
+ -repeat=* |--repeat=* ) repeat_mode=" $( expr " $1 " : ' --*repeat=\([0-9][0-9]*\)' ) " && shift || die " bad value $1 " ;;
226
+ * ) break ;;
227
+ esac
228
+ done
229
+
230
+ if [ -n " ${TIG_SCRIPT:- } " ] && [ -s " $TIG_SCRIPT " ] && [ " $( tail -1 < " ${TIG_SCRIPT} " ) " = ' :quit' ]; then
231
+ # remove the trailing :quit from a script if it already was defined
232
+ head -n " $( expr " $( grep -c ' ^' < " $TIG_SCRIPT " ) " - 1) " < " ${TIG_SCRIPT} " > " ${TIG_SCRIPT} .tmp"
233
+ mv -f -- " ${TIG_SCRIPT} .tmp" " $TIG_SCRIPT "
234
+ fi
235
+
236
+ if [ -n " $repeat_mode " ] && [ " $# " -gt 1 ]; then
237
+ die " tig_keystrokes -repeat can only be used with a single argument"
238
+ fi
239
+
240
+ if [ -n " $repeat_mode " ]; then
241
+ test " $# " -gt 1 && die " tig_keystrokes -repeat can only be used with a single key-sequence argument"
242
+ test " $repeat_mode " -lt 1 && repeat_mode=1
243
+
244
+ chunk=" $1 "
245
+ if [ -n " $keysym_mode " ]; then
246
+ chunk=" %(keysym:$1 )"
247
+ fi
248
+
249
+ while [ " $repeat_mode " -gt 0 ]; do
250
+ _tig_keystrokes_driver " $TEST_KEYSTROKES " " $append_mode " " $chunk "
251
+ append_mode=yes
252
+ repeat_mode=" $(( repeat_mode - 1 )) "
253
+ done
254
+ elif [ -n " $keysym_mode " ]; then
255
+ for chunk in " $@ " ; do
256
+ _tig_keystrokes_driver " $TEST_KEYSTROKES " " $append_mode " " %(keysym:$chunk )"
257
+ append_mode=yes
258
+ done
259
+ else
260
+ _tig_keystrokes_driver " $TEST_KEYSTROKES " " $append_mode " " $@ "
261
+ fi
262
+
263
+ if [ -n " $valgrind " ]; then
264
+ test_skip " simulated keystrokes are not yet reliable under valgrind"
265
+ fi
266
+
267
+ test_require python
268
+ test_require python-termios
269
+ }
270
+
271
+ keystrokes ()
272
+ {
273
+ tig_keystrokes " " " $@ "
274
+ }
275
+
190
276
stdin () {
191
277
file " stdin" " $@ "
192
278
}
@@ -276,6 +362,44 @@ process_tree()
276
362
done
277
363
}
278
364
365
+ descend_to_pg_leader ()
366
+ {
367
+ parent_pid=" $1 " ; shift
368
+ enforce_shortcmd=" ${1:- } "
369
+
370
+ leader_pgid=' -1'
371
+ leader_shortcmd=' '
372
+
373
+ # A short delay is enough to ensure that all relevant processes are up,
374
+ # have completed any initial fork/execs, and allows for some irrelevant
375
+ # processes to be cleared.
376
+ sleep 1
377
+
378
+ for pid in $( process_tree " $parent_pid " ) ; do
379
+ test " $pid " -lt 1 && continue
380
+ ORIG_IFS=" $IFS " ; IFS=' '
381
+ set -- $( ps -o pgid=,command= " $pid " 2> /dev/null)
382
+ IFS=" $ORIG_IFS "
383
+ test " $# " -lt 2 && continue
384
+
385
+ # By convention a process-group leader uses its own PID as PGID
386
+ test " $pid " -ne " $1 " && continue
387
+
388
+ leader_pgid=" $1 "
389
+ leader_shortcmd=" $( basename -- " $2 " ) "
390
+ break
391
+ done
392
+
393
+ if [ " $leader_pgid " -lt 1 ]; then
394
+ die " could not find a process-group leader"
395
+ fi
396
+ if [ -n " $enforce_shortcmd " ] && [ " $leader_shortcmd " != " $enforce_shortcmd " ]; then
397
+ die " expected process-group leader named $enforce_shortcmd "
398
+ fi
399
+
400
+ printf ' %s\n' " $leader_pgid "
401
+ }
402
+
279
403
#
280
404
# Parse TEST_OPTS
281
405
#
@@ -288,6 +412,7 @@ indent=' '
288
412
verbose=
289
413
debugger=
290
414
runner=exec
415
+ trace_keys=
291
416
trace=
292
417
todos=
293
418
valgrind=
@@ -307,6 +432,7 @@ for arg in ${MAKE_TEST_OPTS:-} ${TEST_OPTS:-}; do
307
432
debugger=* ) debugger=" $( expr " $arg " : ' debugger=\(.*\)' ) " ;;
308
433
debugger) debugger=" $( auto_detect_debugger) " ;;
309
434
timeout=* ) timeout=" $( expr " $arg " : ' timeout=\(.*\)' ) " ;;
435
+ trace[-_]keys|trace[-_]keystrokes) trace_keys=yes ;;
310
436
trace) trace=yes ;;
311
437
todo|todos) todos=yes ;;
312
438
valgrind) valgrind=" $HOME /valgrind.log" ;;
@@ -614,6 +740,40 @@ install_pid_timeout() {
614
740
) > /dev/null 2>&1 &
615
741
}
616
742
743
+ simulate_keystrokes ()
744
+ {
745
+ if [ -z " ${TEST_KEYSTROKES:- } " ] || ! [ -s " $TEST_KEYSTROKES " ]; then
746
+ return
747
+ fi
748
+
749
+ if ! [ " ${1:- } " -gt 1 ]; then
750
+ die " simulate_keystrokes requires an argument: the pgid to attach to"
751
+ else
752
+ # We were probably passed the PID, and can assume PID == PGID.
753
+ # Calling descend_to_pg_leader is safe but not usually needed.
754
+ tig_pgid=" $1 " ; shift
755
+ fi
756
+
757
+ if [ -n " $valgrind " ]; then
758
+
759
+ # valgrind needs a generous delay to warm up
760
+ # todo: it might need extra time on its first run
761
+ sleep 5
762
+
763
+ tig_pgid=" $( descend_to_pg_leader " $tig_pgid " valgrind 2> /dev/null) "
764
+ if [ -z " $tig_pgid " ]; then
765
+ die " could not find a process-group leader"
766
+ fi
767
+ fi
768
+
769
+ if [ -n " $trace_keys " ]; then
770
+ printf ' %s%s %s %s %s\n' " $indent " keystroke-stuffer --with-shutdown " $tig_pgid " " $TEST_KEYSTROKES "
771
+ keystroke-stuffer --debug --debug " $tig_pgid " " $TEST_KEYSTROKES " | sed " s/^/$indent$indent /"
772
+ fi
773
+
774
+ keystroke-stuffer --with-shutdown " $tig_pgid " " $TEST_KEYSTROKES "
775
+ }
776
+
617
777
valgrind_exec ()
618
778
{
619
779
kernel=" $( uname -s 2> /dev/null || printf ' unknown\n' ) "
@@ -686,6 +846,7 @@ test_tig()
686
846
tig_pid=" $! "
687
847
signal=14
688
848
install_pid_timeout " $tig_pid " " $signal "
849
+ simulate_keystrokes " $tig_pid "
689
850
wait " $tig_pid "
690
851
fi
691
852
status_code=" $? "
@@ -726,15 +887,16 @@ test_case()
726
887
printf ' %s\n' " $name " >> test-cases
727
888
cat > " $name .expected"
728
889
729
- touch -- " $name -before" " $name -after" " $name -script" " $name -args" " $name -tigrc" " $name -assert-stderr" " $name -todo" " $name -subshell" " $name -timeout"
890
+ touch -- " $name -before" " $name -after" " $name -script" " $name -args" " $name -tigrc" " $name -assert-stderr" \
891
+ " $name -todo" " $name -subshell" " $name -timeout" " $name -keystrokes"
730
892
731
893
while [ " $# " -gt 0 ]; do
732
894
arg=" $1 " ; shift
733
895
key=" $( expr " X$arg " : ' X--\([^=]*\).*' ) "
734
896
value=" $( expr " X$arg " : ' X--[^=]*=\(.*\)' ) "
735
897
736
898
case " $key " in
737
- before|after|script|args|cwd|tigrc|assert-stderr|todo|subshell|timeout)
899
+ before|after|script|args|cwd|tigrc|assert-stderr|todo|subshell|timeout|keystrokes )
738
900
printf ' %s\n' " $value " > " $name -$key " ;;
739
901
assert-equals)
740
902
filename=" $( expr " X$value " : ' X\([^=]*\)' ) "
@@ -744,6 +906,12 @@ test_case()
744
906
* ) die " Unknown test_case argument: $arg "
745
907
esac
746
908
done
909
+
910
+ # hack to stop tests from wedging. unsatisfactory that the script
911
+ # file is modified implicitly in multiple places.
912
+ if ! [ -s " $name -script" ] && ! [ -s " $name -keystrokes" ]; then
913
+ printf ' :none\n' > " $name -script"
914
+ fi
747
915
}
748
916
749
917
run_test_cases ()
@@ -781,10 +949,15 @@ run_test_cases()
781
949
test_exec_work_dir " $SHELL " " $HOME /$name -before"
782
950
fi
783
951
(
784
- tig_script " $name " "
785
- $( if [ -e " $name -script" ]; then cat < " $name -script" ; fi)
786
- :save-display $name .screen
787
- "
952
+ if [ -s " $name -script" ]; then
953
+ tig_script " $name " "
954
+ $( cat < " $name -script" )
955
+ :save-display $name .screen
956
+ "
957
+ fi
958
+ if [ -s " $name -keystrokes" ]; then
959
+ tig_keystrokes " $name " " $( cat < " $name -keystrokes" ) "
960
+ fi
788
961
if [ -e " $name -cwd" ]; then
789
962
work_dir=" $work_dir /$( cat < " $name -cwd" ) "
790
963
fi
@@ -800,8 +973,9 @@ run_test_cases()
800
973
if [ -e " $name -after" ]; then
801
974
test_exec_work_dir " $SHELL " " $HOME /$name -after"
802
975
fi
803
-
804
- assert_equals " $name .screen" < " $name .expected"
976
+ if [ -s " $name -script" ]; then
977
+ assert_equals " $name .screen" < " $name .expected"
978
+ fi
805
979
if [ -s " $name -assert-stderr" ]; then
806
980
assert_equals " $name .stderr" < " $name -assert-stderr"
807
981
else
0 commit comments