Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simulated keystrokes in test suite #736

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
44 changes: 29 additions & 15 deletions src/display.c
Original file line number Diff line number Diff line change
@@ -611,7 +611,6 @@ init_display(void)
{
bool no_display = !!getenv("TIG_NO_DISPLAY");
const char *term;
int x, y;

if (!opt_tty.file)
die("Can't initialize display without tty");
@@ -621,30 +620,45 @@ init_display(void)
die("Failed to register done_display");

/* Initialize the curses library */
if (!no_display && isatty(STDIN_FILENO)) {
if (no_display) {
FILE *null_file = fopen("/dev/null", "w+");

/* endwin() must not be called out of last-to-first order on instantiated
* SCREENs. Not typically an issue, since after this block, tig will not
* leave output_scr. */
SCREEN *input_scr = newterm(NULL, opt_tty.file, opt_tty.file);
SCREEN *output_scr = newterm(NULL, null_file, null_file);

if (!(cursed = input_scr && output_scr))
die("Failed to initialize curses");

set_term(input_scr);
/* buglet: unsafe for signals over next 5 statements due to endwin() in
* done_display(). */
raw();
nonl();
noecho();
status_win = newwin(1, 1, 0, 0);
set_term(output_scr);
} else if (isatty(STDIN_FILENO)) {
/* Needed for ncurses 5.4 compatibility. */
cursed = !!initscr();
} else {
/* Leave stdin and stdout alone when acting as a pager. */
FILE *out_tty;
int x, y;

out_tty = no_display ? fopen("/dev/null", "w+") : opt_tty.file;
if (!out_tty)
die("Failed to open tty for output");
cursed = !!newterm(NULL, out_tty, opt_tty.file);
if (!(cursed = !!newterm(NULL, opt_tty.file, opt_tty.file)))
die("Failed to initialize curses");

getmaxyx(stdscr, y, x);
status_win = newwin(1, x, y - 1, 0);
}

if (!cursed)
die("Failed to initialize curses");
if (!status_win)
die("Failed to create status window");

set_terminal_modes();
init_colors();

getmaxyx(stdscr, y, x);
status_win = newwin(1, x, y - 1, 0);
if (!status_win)
die("Failed to create status window");

/* Enable keyboard mapping */
keypad(status_win, true);
wbkgdset(status_win, get_line_attr(NULL, LINE_STATUS));
58 changes: 58 additions & 0 deletions test/API.adoc
Original file line number Diff line number Diff line change
@@ -7,6 +7,64 @@ tig_script(name, content, [content, ...])::

steps(content, [content, ...])::

keystrokes([-append | -keysym | -repeat=<int>] key-sequence, [key-sequence, ...])::

Key sequences are given as Python strings, and accept
https://docs.python.org/2.0/ref/strings.html[the same string escapes as
Python]. Example: `'\134'` encodes a literal backslash. +
+
The key sequence may also contain special embedded codes:
`%(keysym:<name>)`, `%(keypause:<seconds>)`, or `%(keysignal:<signal>)`. +
+
*`%(keysym:<name>)`* will be translated into the raw characters
associated with the symbolic key name. <name> may be any form accepted
by 'bind' in `~/.tigrc`, or any terminal capability name known to
`tput`. Examples: `%(keysym:Left)`, `%(keysym:Ctrl-A)`. +
+
As a convenience, the `-keysym` option causes subsequent arguments to
be interpreted as a series of keysym names. Example:
-----------------------------------------------------------------------------
keystrokes -keysym 'Down' 'Up'
-----------------------------------------------------------------------------
::
*`%(keypause:<seconds>)`* will insert a pause in the simulated
keystrokes. If pauses are added, the test timeout may also need to be
increased. +
+
*`%(keysignal:<signal>)`* will send a Unix signal to tig. The signal
may be given as a number or symbol. Example: `%(keysignal:SIGWINCH)` +
+
To send tig a literal sequence matching the characters of an embedded
code, escape it with a backslash: `\%(keypause:1)`. +
+
Exiting: The passed key sequence should always arrange a clean exit.
Tig will otherwise be shut down by a signal, which is less consistent
for the purpose of testing. +
+
Appending: keystrokes may be defined in multiple passes using `-append`.
This enables composing keystrokes with and without `-keysym`. The last
call to `keystrokes()` should arrange a clean exit from tig. +
+
Repeating: `-repeat=<int>` can be used to define repeated sequences.
Only one key-sequence argument may be used with `-repeat`. Example:
-----------------------------------------------------------------------------
keystrokes -keysym -repeat=20 'Down'
-----------------------------------------------------------------------------
::
Interaction with `steps()`: It is possible to use both `steps()` and
`keystrokes()` in the same test: during test execution, the `steps()`
script will run first, and the simulated keystrokes will be sent to tig
after the script finishes. When used together, `steps()` is modified so
that it does not imply `:quit`. +
+
Whitespace handling: The "Enter" key will be fed to tig as a carriage
return (`\r`). Interior newlines in key sequences, whether literal or
encoded, will be translated to carriage returns before sending them to
tig. But note that leading or trailing whitespace on the key-sequence
argument is ignored. To send "Enter", "Tab", or "Space" as the first or
last key in the sequence, use escape codes or keysyms (_ie_ `\r`,`\t`,
`\040`, `%(keysym:Enter)`, `%(keysym:Tab)`, or `%(keysym:Space)`.) +

stdin([content, ...]) [< content]::

tigrc([content, ...]) [< content]::
6 changes: 5 additions & 1 deletion test/README.adoc
Original file line number Diff line number Diff line change
@@ -57,7 +57,11 @@ filter=<file-glob>:<case-glob>::

trace::

Show trace information.
Show tig trace information.

trace_keys::

Show which keystrokes will be sent before each test.

todos::

2 changes: 0 additions & 2 deletions test/diff/diff-highlight-color-test
Original file line number Diff line number Diff line change
@@ -5,8 +5,6 @@

test_require diff-highlight

export PATH="$(dirname -- "$diff_highlight_path"):$PATH"

gitconfig <<EOF
[color.diff-highlight]
oldnormal=red bold
51 changes: 51 additions & 0 deletions test/prompt/history-cases-test
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/sh

. libtest.sh
. libgit.sh

export LINES=3
export COLUMNS=80

test_require readline

in_work_dir create_repo_from_tgz "$base_dir/files/scala-js-benchmarks.tgz"

test_case one \
--before='rm -f -- "$HOME/.tig_history"' \
--tigrc='set history-size = 10' \
--keystrokes=':echo keys_one\r:quit\r' \
--assert-equals=".tig_history"='echo keys_one
quit
' \
<<EOF
2014-03-01 17:26 -0500 Jonas Fonseca o [master] WIP: Upgrade to 0.4-SNAPSHO
[main] ee912870202200a0b9cf4fd86ba57243212d341e - commit 1 of 48 2%
EOF

test_case two \
--before='rm -f -- "$HOME/.tig_history"' \
--tigrc='set history-size = 10' \
--keystrokes=':echo keys_two\r:quit\r' \
--assert-equals=".tig_history"="echo keys_two
quit
" \
--script=':echo first_line
:echo second_line' \
<<EOF
2014-03-01 17:26 -0500 Jonas Fonseca o [master] WIP: Upgrade to 0.4-SNAPSHO
[main] ee912870202200a0b9cf4fd86ba57243212d341e - commit 1 of 48 2%
EOF

test_case three \
--before='rm -f -- "$HOME/.tig_history"' \
--tigrc='set history-size = 10' \
--keystrokes=':echo keys_four\r:quit\r' \
--assert-equals=".tig_history"='echo keys_four
quit
' \
<<EOF
2014-03-01 17:26 -0500 Jonas Fonseca o [master] WIP: Upgrade to 0.4-SNAPSHO
[main] ee912870202200a0b9cf4fd86ba57243212d341e - commit 1 of 48 2%
EOF

run_test_cases
30 changes: 30 additions & 0 deletions test/prompt/history-test
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/sh

. libtest.sh
. libgit.sh

export LINES=3
export COLUMNS=80

test_require readline

in_work_dir create_repo_from_tgz "$base_dir/files/scala-js-benchmarks.tgz"

tigrc <<EOF
set history-size = 3
EOF

keystrokes ':none'
keystrokes -append -keysym 'Enter'
keystrokes -append ':quit'
keystrokes -append -keysym 'Enter'

test_tig

assert_equals stderr <<EOF
EOF

assert_equals "$HOME/.tig_history" <<EOF
none
quit
EOF
43 changes: 43 additions & 0 deletions test/tigrc/script-test
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/sh

. libtest.sh
. libgit.sh

LINES=12
COLUMNS=200

in_work_dir create_repo_from_tgz "$base_dir/files/scala-js-benchmarks.tgz"

export TIGRC_SYSTEM=does-not-exist

file "$HOME/.tigrc.bind.q.for.help.screen" <<EOF
:bind generic q quit
:view-help
:save-display $HOME/help.screen
EOF

tigrc <<EOF
bind generic : prompt # Must have prompt mapping to execute script
bind generic S :script $HOME/.tigrc.bind.q.for.help.screen
EOF

keystrokes 'Sq'

test_tig

assert_equals stderr <<EOF
EOF

assert_equals "$HOME/help.screen" <<EOF
Quick reference for tig keybindings:
[-] generic bindings
View manipulation
q quit Close all views and quit
Misc
: prompt Open the prompt
Internal commands:
S :script $HOME/.tigrc.bind.q.for.help.screen
[help] - line 1 of 9 100%
EOF
431 changes: 431 additions & 0 deletions test/tools/keystroke-stuffer

Large diffs are not rendered by default.

324 changes: 307 additions & 17 deletions test/tools/libtest.sh

Large diffs are not rendered by default.