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