xref: /openbsd-src/gnu/usr.bin/perl/ext/POSIX/t/termios.t (revision 256a93a44f36679bee503f12e49566c2183f6181)
1898184e3Ssthen#!perl -Tw
2850e2753Smillert
3898184e3Ssthenuse strict;
4850e2753Smillertuse Config;
5850e2753Smillertuse Test::More;
6898184e3Ssthen
7850e2753SmillertBEGIN {
8898184e3Ssthen    plan skip_all => "POSIX is unavailable"
9898184e3Ssthen	if $Config{extensions} !~ m!\bPOSIX\b!;
10850e2753Smillert}
11850e2753Smillert
12898184e3Ssthenuse POSIX ':termios_h';
13850e2753Smillert
14898184e3Ssthenplan skip_all => $@
15898184e3Ssthen    if !eval "POSIX::Termios->new; 1" && $@ =~ /termios not implemented/;
16850e2753Smillert
17850e2753Smillert
18898184e3Ssthen# A termios struct that we've successfully read from a terminal device:
19898184e3Ssthenmy $termios;
20850e2753Smillert
21898184e3Ssthenforeach (undef, qw(STDIN STDOUT STDERR)) {
22898184e3Ssthen SKIP:
23898184e3Ssthen    {
24898184e3Ssthen	my ($name, $handle);
25898184e3Ssthen	if (defined $_) {
26898184e3Ssthen	    $name = $_;
27898184e3Ssthen	    $handle = $::{$name};
28898184e3Ssthen	} else {
29898184e3Ssthen	    $name = POSIX::ctermid();
30898184e3Ssthen	    skip("Can't get name of controlling terminal", 4)
31898184e3Ssthen		unless defined $name;
32898184e3Ssthen	    open $handle, '<', $name or skip("can't open $name: $!", 4);
33898184e3Ssthen	}
34898184e3Ssthen
35898184e3Ssthen	skip("$name not a tty", 4) unless -t $handle;
36898184e3Ssthen
37898184e3Ssthen	my $t = eval { POSIX::Termios->new };
38850e2753Smillert	is($@, '', "calling POSIX::Termios->new");
39898184e3Ssthen	isa_ok($t, "POSIX::Termios", "checking the type of the object");
40850e2753Smillert
41898184e3Ssthen	my $fileno = fileno $handle;
42898184e3Ssthen	my $r = eval { $t->getattr($fileno) };
43898184e3Ssthen	is($@, '', "calling getattr($fileno) for $name");
44898184e3Ssthen	if(isnt($r, undef, "returned value ($r) is defined")) {
45898184e3Ssthen	    $termios = $t;
46898184e3Ssthen	}
47898184e3Ssthen    }
48850e2753Smillert}
49850e2753Smillert
50898184e3Ssthenopen my $not_a_tty, '<', $^X or die "Can't open $^X: $!";
51850e2753Smillert
52898184e3Ssthenif (defined $termios) {
53850e2753Smillert    # testing getcc()
54898184e3Ssthen    for my $i (0 .. NCCS-1) {
55898184e3Ssthen	my $r = eval { $termios->getcc($i) };
56850e2753Smillert	is($@, '', "calling getcc($i)");
57898184e3Ssthen	like($r, qr/\A-?[0-9]+\z/, 'returns an integer');
58898184e3Ssthen    }
59898184e3Ssthen    for my $i (NCCS, ~0) {
60898184e3Ssthen	my $r = eval { $termios->getcc($i) };
61898184e3Ssthen	like($@, qr/\ABad getcc subscript/, "calling getcc($i)");
62898184e3Ssthen	is($r, undef, 'returns undef')
63850e2753Smillert    }
64850e2753Smillert
65898184e3Ssthen    for my $method (qw(getcflag getiflag getispeed getlflag getoflag getospeed)) {
66898184e3Ssthen	my $r = eval { $termios->$method() };
67850e2753Smillert	is($@, '', "calling $method()");
68898184e3Ssthen	like($r, qr/\A-?[0-9]+\z/, 'returns an integer');
69850e2753Smillert    }
70850e2753Smillert
71898184e3Ssthen    $! = 0;
72898184e3Ssthen    is($termios->setattr(fileno $not_a_tty), undef,
73898184e3Ssthen       'setattr on a non tty should fail');
74*256a93a4Safresh1    {
75*256a93a4Safresh1        # https://bugs.dragonflybsd.org/issues/3252
76*256a93a4Safresh1        local $TODO = "dragonfly returns bad errno"
77*256a93a4Safresh1            if $^O eq 'dragonfly';
78898184e3Ssthen        cmp_ok($!, '==', POSIX::ENOTTY, 'and set errno to ENOTTY');
79*256a93a4Safresh1    }
80898184e3Ssthen
81898184e3Ssthen    $! = 0;
82898184e3Ssthen    is($termios->setattr(fileno $not_a_tty, TCSANOW), undef,
83898184e3Ssthen       'setattr on a non tty should fail');
84*256a93a4Safresh1    {
85*256a93a4Safresh1        # https://bugs.dragonflybsd.org/issues/3252
86*256a93a4Safresh1        local $TODO = "dragonfly returns bad errno"
87*256a93a4Safresh1            if $^O eq 'dragonfly';
88898184e3Ssthen        cmp_ok($!, '==', POSIX::ENOTTY, 'and set errno to ENOTTY');
89898184e3Ssthen    }
90*256a93a4Safresh1}
91898184e3Ssthen
92898184e3Ssthen{
93898184e3Ssthen    my $t = POSIX::Termios->new();
94898184e3Ssthen    isa_ok($t, "POSIX::Termios", "checking the type of the object");
95898184e3Ssthen
96898184e3Ssthen    # B0 is special
97898184e3Ssthen    my @baud = (B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800,
98898184e3Ssthen		B2400, B4800, B9600, B19200, B38400);
99898184e3Ssthen
100898184e3Ssthen    # On some platforms (eg Linux-that-I-tested), ispeed and ospeed are both
101898184e3Ssthen    # "stored" in the same bits of c_cflag (as the man page documents)
102898184e3Ssthen    # *as well as in struct members* (which you would assume obviates the need
103898184e3Ssthen    # for using c_cflag), and the get*() functions return the value encoded
104898184e3Ssthen    # within c_cflag, hence it's not possible to set/get them independently.
105898184e3Ssthen    foreach my $out (@baud) {
106898184e3Ssthen	is($t->setispeed(0), '0 but true', "setispeed(0)");
107898184e3Ssthen	is($t->setospeed($out), '0 but true', "setospeed($out)");
108898184e3Ssthen	is($t->getospeed(), $out, "getospeed() for $out");
109898184e3Ssthen    }
110898184e3Ssthen    foreach my $in (@baud) {
111898184e3Ssthen	is($t->setospeed(0), '0 but true', "setospeed(0)");
112898184e3Ssthen	is($t->setispeed($in), '0 but true', "setispeed($in)");
113898184e3Ssthen	is($t->getispeed(), $in, "getispeed() for $in");
114898184e3Ssthen    }
115898184e3Ssthen
116898184e3Ssthen    my %state;
117898184e3Ssthen    my @flags = qw(iflag oflag cflag lflag);
118898184e3Ssthen    # I'd prefer to use real values per flag, but can only find OPOST in
119898184e3Ssthen    # POSIX.pm for oflag
120898184e3Ssthen    my @values = (0, 6, 9, 42);
121898184e3Ssthen
122898184e3Ssthen    # initialise everything
123898184e3Ssthen    foreach (@flags) {
124898184e3Ssthen	my $method = 'set' . $_;
125898184e3Ssthen	$t->$method(0);
126898184e3Ssthen	$state{$_} = 0;
127898184e3Ssthen    }
128898184e3Ssthen
129898184e3Ssthen    sub testflags {
130898184e3Ssthen	my ($flag, $values, @rest) = @_;
131898184e3Ssthen	$! = 0;
132898184e3Ssthen	my $method = 'set' . $flag;
133898184e3Ssthen	foreach (@$values) {
134898184e3Ssthen	    $t->$method($_);
135898184e3Ssthen	    $state{$flag} = $_;
136898184e3Ssthen
137898184e3Ssthen	    my $state = join ', ', map {"$_=$state{$_}"} keys %state;
138898184e3Ssthen	    while (my ($flag, $expect) = each %state) {
139898184e3Ssthen		my $method = 'get' . $flag;
140898184e3Ssthen		is($t->$method(), $expect, "$method() for $state");
141898184e3Ssthen	    }
142898184e3Ssthen
143898184e3Ssthen	    testflags(@rest) if @rest;
144898184e3Ssthen	}
145898184e3Ssthen    }
146898184e3Ssthen
147898184e3Ssthen    testflags(map {($_, \@values)} @flags);
148898184e3Ssthen
149898184e3Ssthen    for my $i (0 .. NCCS-1) {
150898184e3Ssthen	$t->setcc($i, 0);
151898184e3Ssthen    }
152898184e3Ssthen    for my $i (0 .. NCCS-1) {
153898184e3Ssthen	is($t->getcc($i), 0, "getcc($i)");
154898184e3Ssthen    }
155898184e3Ssthen    my $c = 0;
156898184e3Ssthen    for my $i (0 .. NCCS-1) {
157898184e3Ssthen	$t->setcc($i, ++$c);
158898184e3Ssthen    }
159898184e3Ssthen    for my $i (reverse 0 .. NCCS-1) {
160898184e3Ssthen	is($t->getcc($i), $c--, "getcc($i)");
161898184e3Ssthen    }
162898184e3Ssthen    for my $i (reverse 0 .. NCCS-1) {
163898184e3Ssthen	$t->setcc($i, ++$c);
164898184e3Ssthen    }
165898184e3Ssthen    for my $i (0 .. NCCS-1) {
166898184e3Ssthen	is($t->getcc($i), $c--, "getcc($i)");
167898184e3Ssthen    }
168898184e3Ssthen
169898184e3Ssthen}
170898184e3Ssthen
171898184e3Ssthen$! = 0;
172898184e3Ssthenis(tcdrain(fileno $not_a_tty), undef, 'tcdrain on a non tty should fail');
173*256a93a4Safresh1{
174*256a93a4Safresh1    # https://bugs.dragonflybsd.org/issues/3252
175*256a93a4Safresh1    local $TODO = "dragonfly returns bad errno"
176*256a93a4Safresh1        if $^O eq 'dragonfly';
177898184e3Ssthen    cmp_ok($!, '==', POSIX::ENOTTY, 'and set errno to ENOTTY');
178*256a93a4Safresh1}
179898184e3Ssthen
180898184e3Ssthen$! = 0;
181898184e3Ssthenis(tcflow(fileno $not_a_tty, TCOON), undef, 'tcflow on a non tty should fail');
182*256a93a4Safresh1{
183*256a93a4Safresh1    # https://bugs.dragonflybsd.org/issues/3252
184*256a93a4Safresh1    local $TODO = "dragonfly returns bad errno"
185*256a93a4Safresh1        if $^O eq 'dragonfly';
186898184e3Ssthen    cmp_ok($!, '==', POSIX::ENOTTY, 'and set errno to ENOTTY');
187*256a93a4Safresh1}
188898184e3Ssthen
189898184e3Ssthen$! = 0;
190898184e3Ssthenis(tcflush(fileno $not_a_tty, TCOFLUSH), undef,
191898184e3Ssthen   'tcflush on a non tty should fail');
192*256a93a4Safresh1{
193*256a93a4Safresh1    # https://bugs.dragonflybsd.org/issues/3252
194*256a93a4Safresh1    local $TODO = "dragonfly returns bad errno"
195*256a93a4Safresh1        if $^O eq 'dragonfly';
196898184e3Ssthen    cmp_ok($!, '==', POSIX::ENOTTY, 'and set errno to ENOTTY');
197*256a93a4Safresh1}
198898184e3Ssthen
199898184e3Ssthen$! = 0;
200898184e3Ssthenis(tcsendbreak(fileno $not_a_tty, 0), undef,
201898184e3Ssthen       'tcsendbreak on a non tty should fail');
202*256a93a4Safresh1{
203*256a93a4Safresh1    # https://bugs.dragonflybsd.org/issues/3252
204*256a93a4Safresh1    local $TODO = "dragonfly returns bad errno"
205*256a93a4Safresh1        if $^O eq 'dragonfly';
206898184e3Ssthen    cmp_ok($!, '==', POSIX::ENOTTY, 'and set errno to ENOTTY');
207*256a93a4Safresh1}
208898184e3Ssthen
209898184e3Ssthendone_testing();
210