aboutsummaryrefslogtreecommitdiff
path: root/src/bin/psql/t/010_tab_completion.pl
blob: 1c7610ffac4f2958eb6ada8d44d58f7946f2054f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use strict;
use warnings;

use PostgresNode;
use TestLib;
use Test::More;
use IPC::Run qw(pump finish timer);

if ($ENV{with_readline} ne 'yes')
{
	plan skip_all => 'readline is not supported by this build';
}

# If we don't have IO::Pty, forget it, because IPC::Run depends on that
# to support pty connections
eval { require IO::Pty; };
if ($@)
{
	plan skip_all => 'IO::Pty is needed to run this test';
}

# start a new server
my $node = get_new_node('main');
$node->init;
$node->start;

# set up a few database objects
$node->safe_psql('postgres',
	    "CREATE TABLE tab1 (f1 int, f2 text);\n"
	  . "CREATE TABLE mytab123 (f1 int, f2 text);\n"
	  . "CREATE TABLE mytab246 (f1 int, f2 text);\n");

# Developers would not appreciate this test adding a bunch of junk to
# their ~/.psql_history, so be sure to redirect history into a temp file.
# We might as well put it in the test log directory, so that buildfarm runs
# capture the result for possible debugging purposes.
my $historyfile = "${TestLib::log_path}/010_psql_history.txt";
$ENV{PSQL_HISTORY} = $historyfile;

# fire up an interactive psql session
my $in  = '';
my $out = '';

my $timer = timer(5);

my $h = $node->interactive_psql('postgres', \$in, \$out, $timer);

ok($out =~ /psql/, "print startup banner");

# Simple test case: type something and see if psql responds as expected
sub check_completion
{
	my ($send, $pattern, $annotation) = @_;

	# reset output collector
	$out = "";
	# restart per-command timer
	$timer->start(5);
	# send the data to be sent
	$in .= $send;
	# wait ...
	pump $h until ($out =~ m/$pattern/ || $timer->is_expired);
	my $okay = ($out =~ m/$pattern/ && !$timer->is_expired);
	ok($okay, $annotation);
	# for debugging, log actual output if it didn't match
	note 'Actual output was "' . $out . "\"\n" if !$okay;
}

# Clear query buffer to start over
# (won't work if we are inside a string literal!)
sub clear_query
{
	check_completion("\\r\n", "postgres=# ", "\\r works");
}

# check basic command completion: SEL<tab> produces SELECT<space>
check_completion("SEL\t", "SELECT ", "complete SEL<tab> to SELECT");

clear_query();

# check case variation is honored
check_completion("sel\t", "select ", "complete sel<tab> to select");

# check basic table name completion
check_completion("* from t\t", "\\* from tab1 ", "complete t<tab> to tab1");

clear_query();

# check table name completion with multiple alternatives
# note: readline might print a bell before the completion
check_completion(
	"select * from my\t",
	"select \\* from my\a?tab",
	"complete my<tab> to mytab when there are multiple choices");

# some versions of readline/libedit require two tabs here, some only need one
check_completion("\t\t", "mytab123 +mytab246",
	"offer multiple table choices");

check_completion("2\t", "246 ",
	"finish completion of one of multiple table choices");

clear_query();

# check case-sensitive keyword replacement
# XXX the output here might vary across readline versions
check_completion(
	"\\DRD\t",
	"\\DRD\b\b\bdrds ",
	"complete \\DRD<tab> to \\drds");

clear_query();

# send psql an explicit \q to shut it down, else pty won't close properly
$timer->start(5);
$in .= "\\q\n";
finish $h or die "psql returned $?";
$timer->reset;

# done
$node->stop;
done_testing();