Commit | Line | Data |
---|---|---|
a0d0e21e LW |
1 | #!./perl |
2 | ||
3 | BEGIN { | |
a0d0e21e | 4 | require Config; import Config; |
fa6b8193 | 5 | if ($^O ne 'VMS' and $Config{'extensions'} !~ /\bPOSIX\b/) { |
c764b42b | 6 | print "1..0\n"; |
a0d0e21e LW |
7 | exit 0; |
8 | } | |
9 | } | |
c07a80fd | 10 | |
a64f08cb | 11 | use Test::More tests => 109; |
e6c299c8 | 12 | |
212caf55 | 13 | use POSIX qw(fcntl_h signal_h limits_h _exit getcwd open read strftime write |
792480b6 | 14 | errno localeconv dup dup2 lseek access); |
e6c299c8 | 15 | use strict 'subs'; |
a0d0e21e | 16 | |
849ddec1 NC |
17 | sub next_test { |
18 | my $builder = Test::More->builder; | |
19 | $builder->current_test($builder->current_test() + 1); | |
20 | } | |
21 | ||
c07a80fd | 22 | $| = 1; |
a0d0e21e | 23 | |
e6c299c8 JH |
24 | $Is_W32 = $^O eq 'MSWin32'; |
25 | $Is_Dos = $^O eq 'dos'; | |
e6c299c8 JH |
26 | $Is_MacOS = $^O eq 'MacOS'; |
27 | $Is_VMS = $^O eq 'VMS'; | |
28 | $Is_OS2 = $^O eq 'os2'; | |
29 | $Is_UWin = $^O eq 'uwin'; | |
30 | $Is_OS390 = $^O eq 'os390'; | |
6dead956 | 31 | |
6a164b5b JM |
32 | my $vms_unix_rpt = 0; |
33 | my $vms_efs = 0; | |
34 | my $unix_mode = 1; | |
35 | ||
36 | if ($Is_VMS) { | |
37 | $unix_mode = 0; | |
38 | if (eval 'require VMS::Feature') { | |
39 | $vms_unix_rpt = VMS::Feature::current("filename_unix_report"); | |
40 | $vms_efs = VMS::Feature::current("efs_charset"); | |
41 | } else { | |
42 | my $unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || ''; | |
43 | my $efs_charset = $ENV{'DECC$EFS_CHARSET'} || ''; | |
44 | $vms_unix_rpt = $unix_rpt =~ /^[ET1]/i; | |
45 | $vms_efs = $efs_charset =~ /^[ET1]/i; | |
46 | } | |
47 | ||
48 | # Traditional VMS mode only if VMS is not in UNIX compatible mode. | |
49 | $unix_mode = ($vms_efs && $vms_unix_rpt); | |
50 | ||
51 | } | |
52 | ||
a572b909 NC |
53 | my $testfd = open("Makefile.PL", O_RDONLY, 0); |
54 | like($testfd, qr/\A\d+\z/, 'O_RDONLY with open'); | |
7814eec4 | 55 | read($testfd, $buffer, 4) if $testfd > 2; |
2adbc9b6 | 56 | is( $buffer, "# Ex", ' with read' ); |
c07a80fd | 57 | |
7814eec4 PM |
58 | TODO: |
59 | { | |
60 | local $TODO = "read to array element not working"; | |
61 | ||
62 | read($testfd, $buffer[1], 5) if $testfd > 2; | |
63 | is( $buffer[1], "perl\n", ' read to array element' ); | |
64 | } | |
65 | ||
a572b909 NC |
66 | my $test = next_test(); |
67 | write(1,"ok $test\nnot ok $test\n", 5); | |
e6c299c8 JH |
68 | |
69 | SKIP: { | |
70 | skip("no pipe() support on DOS", 2) if $Is_Dos; | |
a0d0e21e | 71 | |
10de532f | 72 | @fds = POSIX::pipe(); |
a572b909 | 73 | cmp_ok($fds[0], '>', $testfd, 'POSIX::pipe'); |
e6c299c8 | 74 | |
10de532f JH |
75 | CORE::open($reader = \*READER, "<&=".$fds[0]); |
76 | CORE::open($writer = \*WRITER, ">&=".$fds[1]); | |
a572b909 NC |
77 | my $test = next_test(); |
78 | print $writer "ok $test\n"; | |
10de532f JH |
79 | close $writer; |
80 | print <$reader>; | |
81 | close $reader; | |
6bbf1b34 | 82 | } |
a0d0e21e | 83 | |
e6c299c8 JH |
84 | SKIP: { |
85 | skip("no sigaction support on win32/dos", 6) if $Is_W32 || $Is_Dos; | |
86 | ||
87 | my $sigset = new POSIX::SigSet 1, 3; | |
88 | $sigset->delset(1); | |
89 | ok(! $sigset->ismember(1), 'POSIX::SigSet->delset' ); | |
90 | ok( $sigset->ismember(3), 'POSIX::SigSet->ismember' ); | |
be4e88b6 | 91 | |
e6c299c8 JH |
92 | SKIP: { |
93 | skip("no kill() support on Mac OS", 4) if $Is_MacOS; | |
94 | ||
be4e88b6 MS |
95 | my $sigint_called = 0; |
96 | ||
e6c299c8 JH |
97 | my $mask = new POSIX::SigSet &SIGINT; |
98 | my $action = new POSIX::SigAction 'main::SigHUP', $mask, 0; | |
10de532f JH |
99 | sigaction(&SIGHUP, $action); |
100 | $SIG{'INT'} = 'SigINT'; | |
7eb03357 AB |
101 | |
102 | # At least OpenBSD/i386 3.3 is okay, as is NetBSD 1.5. | |
103 | # But not NetBSD 1.6 & 1.6.1: the test makes perl crash. | |
104 | # So the kill() must not be done with this config in order to | |
105 | # finish the test. | |
106 | # For others (darwin & freebsd), let the test fail without crashing. | |
d188ff5f | 107 | # the test passes at least from freebsd 8.1 |
7eb03357 | 108 | my $todo = $^O eq 'netbsd' && $Config{osvers}=~/^1\.6/; |
e6b15316 | 109 | my $why_todo = "# TODO $^O $Config{osvers} seems to lose blocked signals"; |
22f20764 AB |
110 | if (!$todo) { |
111 | kill 'HUP', $$; | |
112 | } else { | |
113 | print "not ok 9 - sigaction SIGHUP ",$why_todo,"\n"; | |
114 | print "not ok 10 - sig mask delayed SIGINT ",$why_todo,"\n"; | |
115 | } | |
10de532f | 116 | sleep 1; |
be4e88b6 | 117 | |
d188ff5f | 118 | $todo = 1 if ($^O eq 'freebsd' && $Config{osvers} < 8) |
78385c2e | 119 | || ($^O eq 'darwin' && $Config{osvers} < '6.6'); |
22f20764 | 120 | printf "%s 11 - masked SIGINT received %s\n", |
7eb03357 | 121 | $sigint_called ? "ok" : "not ok", |
22f20764 | 122 | $todo ? $why_todo : ''; |
be4e88b6 | 123 | |
7814eec4 | 124 | print "ok 12 - signal masks successful\n"; |
10de532f JH |
125 | |
126 | sub SigHUP { | |
7814eec4 | 127 | print "ok 9 - sigaction SIGHUP\n"; |
10de532f JH |
128 | kill 'INT', $$; |
129 | sleep 2; | |
7814eec4 | 130 | print "ok 10 - sig mask delayed SIGINT\n"; |
10de532f JH |
131 | } |
132 | ||
133 | sub SigINT { | |
be4e88b6 | 134 | $sigint_called++; |
10de532f | 135 | } |
e6c299c8 JH |
136 | |
137 | # The order of the above tests is very important, so | |
138 | # we use literal prints and hard coded numbers. | |
139 | next_test() for 1..4; | |
d536870a | 140 | } |
6dead956 | 141 | } |
a0d0e21e | 142 | |
e6c299c8 | 143 | SKIP: { |
e6c299c8 JH |
144 | skip("_POSIX_OPEN_MAX undefined ($fds[1])", 1) unless &_POSIX_OPEN_MAX; |
145 | ||
a572b909 NC |
146 | cmp_ok(&_POSIX_OPEN_MAX, '>=', 16, |
147 | "The minimum allowed values according to susv2" ); | |
4e0f6e8c | 148 | |
c9ff6e92 | 149 | } |
a0d0e21e | 150 | |
d536870a | 151 | my $pat; |
2adbc9b6 NC |
152 | if ( $unix_mode ) { |
153 | $pat = qr#[\\/]POSIX$#i; | |
e6c299c8 JH |
154 | } |
155 | else { | |
2adbc9b6 | 156 | $pat = qr/\.POSIX]/i; |
d536870a | 157 | } |
e6c299c8 | 158 | like( getcwd(), qr/$pat/, 'getcwd' ); |
a0d0e21e | 159 | |
a89d8a78 DH |
160 | # Check string conversion functions. |
161 | ||
e6c299c8 | 162 | SKIP: { |
a572b909 | 163 | skip("strtod() not present", 2) unless $Config{d_strtod}; |
e6c299c8 | 164 | |
ff68c719 | 165 | $lc = &POSIX::setlocale(&POSIX::LC_NUMERIC, 'C') if $Config{d_setlocale}; |
e6c299c8 JH |
166 | |
167 | # we're just checking that strtod works, not how accurate it is | |
a89d8a78 | 168 | ($n, $x) = &POSIX::strtod('3.14159_OR_SO'); |
a572b909 NC |
169 | cmp_ok(abs("3.14159" - $n), '<', 1e-6, 'strtod works'); |
170 | is($x, 6, 'strtod works'); | |
e6c299c8 | 171 | |
ff68c719 | 172 | &POSIX::setlocale(&POSIX::LC_NUMERIC, $lc) if $Config{d_setlocale}; |
e6c299c8 JH |
173 | } |
174 | ||
175 | SKIP: { | |
176 | skip("strtol() not present", 2) unless $Config{d_strtol}; | |
a89d8a78 | 177 | |
a89d8a78 | 178 | ($n, $x) = &POSIX::strtol('21_PENGUINS'); |
e6c299c8 JH |
179 | is($n, 21, 'strtol() number'); |
180 | is($x, 9, ' unparsed chars'); | |
181 | } | |
182 | ||
183 | SKIP: { | |
184 | skip("strtoul() not present", 2) unless $Config{d_strtoul}; | |
a89d8a78 | 185 | |
a89d8a78 | 186 | ($n, $x) = &POSIX::strtoul('88_TEARS'); |
e6c299c8 JH |
187 | is($n, 88, 'strtoul() number'); |
188 | is($x, 6, ' unparsed chars'); | |
189 | } | |
a89d8a78 | 190 | |
a0d0e21e | 191 | # Pick up whether we're really able to dynamically load everything. |
a572b909 | 192 | cmp_ok(&POSIX::acos(1.0), '==', 0.0, 'dynamic loading'); |
a0d0e21e | 193 | |
84ef74c4 AD |
194 | # This can coredump if struct tm has a timezone field and we |
195 | # didn't detect it. If this fails, try adding | |
196 | # -DSTRUCT_TM_HASZONE to your cflags when compiling ext/POSIX/POSIX.c. | |
197 | # See ext/POSIX/hints/sunos_4.pl and ext/POSIX/hints/linux.pl | |
a572b909 NC |
198 | $test = next_test(); |
199 | print POSIX::strftime("ok $test # %H:%M, on %m/%d/%y\n", localtime()); | |
84ef74c4 | 200 | |
33c0e3ec SB |
201 | # If that worked, validate the mini_mktime() routine's normalisation of |
202 | # input fields to strftime(). | |
203 | sub try_strftime { | |
33c0e3ec SB |
204 | my $expect = shift; |
205 | my $got = POSIX::strftime("%a %b %d %H:%M:%S %Y %j", @_); | |
61a515a6 | 206 | is($got, $expect, "validating mini_mktime() and strftime(): $expect"); |
33c0e3ec SB |
207 | } |
208 | ||
209 | $lc = &POSIX::setlocale(&POSIX::LC_TIME, 'C') if $Config{d_setlocale}; | |
e6c299c8 | 210 | try_strftime("Wed Feb 28 00:00:00 1996 059", 0,0,0, 28,1,96); |
53059177 | 211 | SKIP: { |
abbe0d1a | 212 | skip("VC++ 8 and Vista's CRTs regard 60 seconds as an invalid parameter", 1) |
6fa15125 | 213 | if ($Is_W32 and (($Config{cc} eq 'cl' and |
abbe0d1a | 214 | $Config{ccversion} =~ /^(\d+)/ and $1 >= 14) or |
6fa15125 | 215 | (Win32::GetOSVersion())[1] >= 6)); |
53059177 SH |
216 | |
217 | try_strftime("Thu Feb 29 00:00:60 1996 060", 60,0,-24, 30,1,96); | |
218 | } | |
e6c299c8 JH |
219 | try_strftime("Fri Mar 01 00:00:00 1996 061", 0,0,-24, 31,1,96); |
220 | try_strftime("Sun Feb 28 00:00:00 1999 059", 0,0,0, 28,1,99); | |
221 | try_strftime("Mon Mar 01 00:00:00 1999 060", 0,0,24, 28,1,99); | |
222 | try_strftime("Mon Feb 28 00:00:00 2000 059", 0,0,0, 28,1,100); | |
223 | try_strftime("Tue Feb 29 00:00:00 2000 060", 0,0,0, 0,2,100); | |
224 | try_strftime("Wed Mar 01 00:00:00 2000 061", 0,0,0, 1,2,100); | |
225 | try_strftime("Fri Mar 31 00:00:00 2000 091", 0,0,0, 31,2,100); | |
a64f08cb TC |
226 | |
227 | { # rt 72232 | |
228 | ||
229 | # Std C/POSIX allows day/month to be negative and requires that | |
230 | # wday/yday be adjusted as needed | |
231 | # previously mini_mktime() would allow yday to dominate if mday and | |
232 | # month were both non-positive | |
233 | # check that yday doesn't dominate | |
234 | try_strftime("Thu Dec 30 00:00:00 1999 364", 0,0,0, -1,0,100); | |
235 | try_strftime("Thu Dec 30 00:00:00 1999 364", 0,0,0, -1,0,100,-1,10); | |
236 | # it would also allow a positive wday to override the calculated value | |
237 | # check that wday is recalculated too | |
238 | try_strftime("Thu Dec 30 00:00:00 1999 364", 0,0,0, -1,0,100,0,10); | |
239 | } | |
240 | ||
33c0e3ec SB |
241 | &POSIX::setlocale(&POSIX::LC_TIME, $lc) if $Config{d_setlocale}; |
242 | ||
212caf55 TS |
243 | { |
244 | for my $test (0, 1) { | |
245 | $! = 0; | |
246 | # POSIX::errno is autoloaded. | |
247 | # Autoloading requires many system calls. | |
248 | # errno() looks at $! to generate its result. | |
249 | # Autoloading should not munge the value. | |
250 | my $foo = $!; | |
251 | my $errno = POSIX::errno(); | |
e6c299c8 | 252 | |
e6c299c8 JH |
253 | # Force numeric context. |
254 | is( $errno + 0, $foo + 0, 'autoloading and errno() mix' ); | |
212caf55 TS |
255 | } |
256 | } | |
257 | ||
d4742b2c NC |
258 | SKIP: { |
259 | skip("no kill() support on Mac OS", 1) if $Is_MacOS; | |
260 | is (eval "kill 0", 0, "check we have CORE::kill") | |
261 | or print "\$\@ is " . _qq($@) . "\n"; | |
262 | } | |
263 | ||
264 | # Check that we can import the POSIX kill routine | |
265 | POSIX->import ('kill'); | |
266 | my $result = eval "kill 0"; | |
267 | is ($result, undef, "we should now have POSIX::kill"); | |
268 | # Check usage. | |
269 | like ($@, qr/^Usage: POSIX::kill\(pid, sig\)/, "check its usage message"); | |
270 | ||
271 | # Check unimplemented. | |
272 | $result = eval {POSIX::offsetof}; | |
273 | is ($result, undef, "offsetof should fail"); | |
274 | like ($@, qr/^Unimplemented: POSIX::offsetof\(\) is C-specific/, | |
275 | "check its unimplemented message"); | |
276 | ||
277 | # Check reimplemented. | |
278 | $result = eval {POSIX::fgets}; | |
279 | is ($result, undef, "fgets should fail"); | |
280 | like ($@, qr/^Use method IO::Handle::gets\(\) instead/, | |
281 | "check its redef message"); | |
282 | ||
4b3c6531 RGS |
283 | # Simplistic tests for the isXXX() functions (bug #16799) |
284 | ok( POSIX::isalnum('1'), 'isalnum' ); | |
285 | ok(!POSIX::isalnum('*'), 'isalnum' ); | |
286 | ok( POSIX::isalpha('f'), 'isalpha' ); | |
287 | ok(!POSIX::isalpha('7'), 'isalpha' ); | |
288 | ok( POSIX::iscntrl("\cA"),'iscntrl' ); | |
289 | ok(!POSIX::iscntrl("A"), 'iscntrl' ); | |
290 | ok( POSIX::isdigit('1'), 'isdigit' ); | |
291 | ok(!POSIX::isdigit('z'), 'isdigit' ); | |
292 | ok( POSIX::isgraph('@'), 'isgraph' ); | |
293 | ok(!POSIX::isgraph(' '), 'isgraph' ); | |
294 | ok( POSIX::islower('l'), 'islower' ); | |
295 | ok(!POSIX::islower('L'), 'islower' ); | |
296 | ok( POSIX::isupper('U'), 'isupper' ); | |
297 | ok(!POSIX::isupper('u'), 'isupper' ); | |
298 | ok( POSIX::isprint('$'), 'isprint' ); | |
299 | ok(!POSIX::isprint("\n"), 'isprint' ); | |
300 | ok( POSIX::ispunct('%'), 'ispunct' ); | |
301 | ok(!POSIX::ispunct('u'), 'ispunct' ); | |
302 | ok( POSIX::isspace("\t"), 'isspace' ); | |
303 | ok(!POSIX::isspace('_'), 'isspace' ); | |
304 | ok( POSIX::isxdigit('f'), 'isxdigit' ); | |
305 | ok(!POSIX::isxdigit('g'), 'isxdigit' ); | |
117206bb RGS |
306 | # metaphysical question : what should be returned for an empty string ? |
307 | # anyway this shouldn't segfault (bug #24554) | |
308 | ok( POSIX::isalnum(''), 'isalnum empty string' ); | |
309 | ok( POSIX::isalnum(undef),'isalnum undef' ); | |
767bb2e0 TS |
310 | # those functions should stringify their arguments |
311 | ok(!POSIX::isalpha([]), 'isalpha []' ); | |
312 | ok( POSIX::isprint([]), 'isprint []' ); | |
2ae48df0 RGS |
313 | |
314 | eval { use strict; POSIX->import("S_ISBLK"); my $x = S_ISBLK }; | |
315 | unlike( $@, qr/Can't use string .* as a symbol ref/, "Can import autoloaded constants" ); | |
4a948f3f NC |
316 | |
317 | SKIP: { | |
318 | skip("localeconv() not present", 20) unless $Config{d_locconv}; | |
319 | my $conv = localeconv; | |
320 | is(ref $conv, 'HASH', 'localconv returns a hash reference'); | |
321 | ||
322 | foreach (qw(decimal_point thousands_sep grouping int_curr_symbol | |
323 | currency_symbol mon_decimal_point mon_thousands_sep | |
324 | mon_grouping positive_sign negative_sign)) { | |
325 | SKIP: { | |
326 | skip("localeconv has no result for $_", 1) | |
327 | unless exists $conv->{$_}; | |
328 | unlike(delete $conv->{$_}, qr/\A\z/, | |
329 | "localeconv returned a non-empty string for $_"); | |
330 | } | |
331 | } | |
332 | ||
333 | foreach (qw(int_frac_digits frac_digits p_cs_precedes p_sep_by_space | |
334 | n_cs_precedes n_sep_by_space p_sign_posn n_sign_posn)) { | |
335 | SKIP: { | |
336 | skip("localeconv has no result for $_", 1) | |
337 | unless exists $conv->{$_}; | |
338 | like(delete $conv->{$_}, qr/\A-?\d+\z/, | |
339 | "localeconv returned an integer for $_"); | |
340 | } | |
341 | } | |
342 | is_deeply([%$conv], [], 'no unexpected keys returned by localeconv'); | |
343 | } | |
344 | ||
792480b6 NC |
345 | my $fd1 = open("Makefile.PL", O_RDONLY, 0); |
346 | like($fd1, qr/\A\d+\z/, 'O_RDONLY with open'); | |
347 | cmp_ok($fd1, '>', $testfd); | |
348 | my $fd2 = dup($fd1); | |
349 | like($fd2, qr/\A\d+\z/, 'dup'); | |
350 | cmp_ok($fd2, '>', $fd1); | |
351 | is(POSIX::close($fd1), '0 but true', 'close'); | |
352 | is(POSIX::close($testfd), '0 but true', 'close'); | |
353 | $! = 0; | |
354 | undef $buffer; | |
355 | is(read($fd1, $buffer, 4), undef, 'read on closed file handle fails'); | |
356 | cmp_ok($!, '==', POSIX::EBADF); | |
357 | undef $buffer; | |
358 | read($fd2, $buffer, 4) if $fd2 > 2; | |
359 | is($buffer, "# Ex", 'read'); | |
360 | # The descriptor $testfd was using is now free, and is lower than that which | |
361 | # $fd1 was using. Hence if dup2() behaves as dup(), we'll know :-) | |
362 | { | |
792480b6 NC |
363 | $testfd = dup2($fd2, $fd1); |
364 | is($testfd, $fd1, 'dup2'); | |
365 | undef $buffer; | |
366 | read($testfd, $buffer, 4) if $testfd > 2; | |
367 | is($buffer, 'pect', 'read'); | |
368 | is(lseek($testfd, 0, 0), 0, 'lseek back'); | |
369 | # The two should share file position: | |
370 | undef $buffer; | |
371 | read($fd2, $buffer, 4) if $fd2 > 2; | |
372 | is($buffer, "# Ex", 'read'); | |
373 | } | |
374 | ||
375 | # The FreeBSD man page warns: | |
376 | # The access() system call is a potential security hole due to race | |
377 | # conditions and should never be used. | |
378 | is(access('Makefile.PL', POSIX::F_OK), '0 but true', 'access'); | |
379 | is(access('Makefile.PL', POSIX::R_OK), '0 but true', 'access'); | |
380 | $! = 0; | |
381 | is(access('no such file', POSIX::F_OK), undef, 'access on missing file'); | |
382 | cmp_ok($!, '==', POSIX::ENOENT); | |
383 | is(access('Makefile.PL/nonsense', POSIX::F_OK), undef, | |
384 | 'access on not-a-directory'); | |
385 | SKIP: { | |
386 | skip("$^O is insufficiently POSIX", 1) | |
e5da71f2 | 387 | if $Is_W32 || $Is_VMS; |
792480b6 NC |
388 | cmp_ok($!, '==', POSIX::ENOTDIR); |
389 | } | |
390 | ||
404d038e PG |
391 | # Check that output is not flushed by _exit. This test should be last |
392 | # in the file, and is not counted in the total number of tests. | |
393 | if ($^O eq 'vos') { | |
394 | print "# TODO - hit VOS bug posix-885 - _exit flushes output buffers.\n"; | |
395 | } else { | |
396 | $| = 0; | |
397 | # The following line assumes buffered output, which may be not true: | |
398 | print '@#!*$@(!@#$' unless ($Is_MacOS || $Is_OS2 || $Is_UWin || $Is_OS390 || | |
e6c299c8 | 399 | $Is_VMS || |
601f2d16 SB |
400 | (defined $ENV{PERLIO} && |
401 | $ENV{PERLIO} eq 'unix' && | |
402 | $Config::Config{useperlio})); | |
404d038e PG |
403 | _exit(0); |
404 | } |