1#!perl -T 2 3BEGIN { 4 use Config; 5 use Test::More; 6 plan skip_all => "POSIX is unavailable" if $Config{'extensions'} !~ m!\bPOSIX\b!; 7} 8 9use strict; 10use warnings; 11use File::Spec; 12use POSIX; 13 14sub check(@) { 15 grep { eval "&$_;1" or $@!~/vendor has not defined POSIX macro/ } @_ 16} 17 18my @path_consts = check qw( 19 _PC_CHOWN_RESTRICTED _PC_LINK_MAX _PC_NAME_MAX 20 _PC_NO_TRUNC _PC_PATH_MAX 21); 22 23my @path_consts_terminal = check qw( 24 _PC_MAX_CANON _PC_MAX_INPUT _PC_VDISABLE 25); 26 27my @path_consts_fifo = check qw( 28 _PC_PIPE_BUF 29); 30 31my @sys_consts = check qw( 32 _SC_ARG_MAX _SC_CHILD_MAX _SC_CLK_TCK _SC_JOB_CONTROL 33 _SC_NGROUPS_MAX _SC_OPEN_MAX _SC_PAGESIZE _SC_SAVED_IDS 34 _SC_STREAM_MAX _SC_VERSION _SC_TZNAME_MAX 35); 36 37my $tests = 2 * 2 * @path_consts + 38 2 * 2 * @path_consts_terminal + 39 2 * 2 * @path_consts_fifo + 40 1 * @sys_consts; 41plan $tests 42 ? (tests => $tests) 43 : (skip_all => "No tests to run on this OS") 44; 45 46# Don't test on "." as it can be networked storage which returns EINVAL 47# Testing on "/" may not be portable to non-Unix as it may not be readable 48# "/tmp" should be readable and likely also local. 49my $testdir = File::Spec->tmpdir; 50$testdir = VMS::Filespec::fileify($testdir) if $^O eq 'VMS'; 51 52my $r; 53 54my $TTY = "/dev/tty"; 55 56sub _check_and_report { 57 my ($sub, $constant, $description) = @_; 58 $! = 0; 59 my $return_val = eval {$sub->(eval "$constant()")}; 60 my $errno = $!; # Grab this before anything else changes it. 61 is($@, '', $description); 62 63 # We can't test sysconf further without investigating the type of argument 64 # provided 65 return if $description =~ /sysconf/; 66 67 if (defined $return_val) { 68 like($return_val, qr/\A(?:-?[1-9][0-9]*|0 but true)\z/, 69 'the returned value should be a signed integer'); 70 } else { 71 SKIP: 72 { 73 # POSIX specifies EINVAL is returned if the f?pathconf() 74 # isn't implemented for the specific path 75 skip "$description not implemented for this path", 1 76 if $errno == EINVAL && $description =~ /pathconf/; 77 cmp_ok($errno, '==', 0, 'errno should be 0 as before the call') 78 or diag("\$!: $errno"); 79 } 80 } 81} 82 83# testing fpathconf() on a non-terminal file 84SKIP: { 85 my $fd = POSIX::open($testdir, O_RDONLY) 86 or skip "could not open test directory '$testdir' ($!)", 87 2 * @path_consts; 88 89 for my $constant (@path_consts) { 90 SKIP: { 91 skip "pathconf($constant) hangs on Android", 2 if $constant eq '_PC_LINK_MAX' && $^O =~ /android/; 92 _check_and_report(sub { fpathconf($fd, shift) }, $constant, 93 "calling fpathconf($fd, $constant)"); 94 } 95 } 96 97 POSIX::close($fd); 98} 99 100# testing pathconf() on a non-terminal file 101for my $constant (@path_consts) { 102 SKIP: { 103 skip "pathconf($constant) hangs on Android", 2 if $constant eq '_PC_LINK_MAX' && $^O =~ /android/; 104 _check_and_report(sub { pathconf($testdir, shift) }, $constant, 105 "calling pathconf('$testdir', $constant)"); 106 } 107} 108 109SKIP: { 110 my $n = 2 * 2 * @path_consts_terminal; 111 112 -c $TTY 113 or skip("$TTY not a character file", $n); 114 open(my $LEXTTY, '<', $TTY) 115 or skip("failed to open $TTY: $!", $n); 116 -t $LEXTTY 117 or skip("$LEXTTY ($TTY) not a terminal file", $n); 118 119 my $fd = fileno($LEXTTY); 120 121 # testing fpathconf() on a terminal file 122 for my $constant (@path_consts_terminal) { 123 _check_and_report(sub { fpathconf($fd, shift) }, $constant, 124 "calling fpathconf($fd, $constant) ($TTY)"); 125 } 126 127 close($LEXTTY); 128 # testing pathconf() on a terminal file 129 for my $constant (@path_consts_terminal) { 130 _check_and_report(sub { pathconf($TTY, shift) }, $constant, 131 "calling pathconf($TTY, $constant)"); 132 } 133} 134 135my $fifo = "fifo$$"; 136 137SKIP: { 138 eval { mkfifo($fifo, 0666) } 139 or skip("could not create fifo $fifo ($!)", 2 * 2 * @path_consts_fifo); 140 141 SKIP: { 142 my $fd = POSIX::open($fifo, O_RDONLY | O_NONBLOCK) 143 or skip("could not open $fifo ($!)", 2 * @path_consts_fifo); 144 145 for my $constant (@path_consts_fifo) { 146 _check_and_report(sub { fpathconf($fd, shift) }, $constant, 147 "calling fpathconf($fd, $constant) ($fifo)"); 148 } 149 150 POSIX::close($fd); 151 } 152 153 # testing pathconf() on a fifo file 154 for my $constant (@path_consts_fifo) { 155 _check_and_report(sub { pathconf($fifo, shift) }, $constant, 156 "calling pathconf($fifo, $constant"); 157 } 158} 159 160END { 161 if ($fifo) { 162 1 while unlink($fifo); 163 } 164} 165 166SKIP: { 167 if($^O eq 'cygwin') { 168 pop @sys_consts; 169 skip("No _SC_TZNAME_MAX on Cygwin", 1); 170 } 171 172} 173# testing sysconf() 174for my $constant (@sys_consts) { 175 _check_and_report(sub {sysconf(shift)}, $constant, 176 "calling sysconf($constant)"); 177} 178