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