This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Make cmp() work on EBCDIC with both UTF-8 operands
[perl5.git] / t / io / pipe.t
1 #!./perl
2
3 BEGIN {
4     chdir 't' if -d 't';
5     @INC = '../lib';
6     require Config; import Config;
7     require './test.pl';
8
9     if (!$Config{'d_fork'}) {
10         skip_all("fork required to pipe");
11     }
12     else {
13         plan(tests => 24);
14     }
15 }
16
17 my $Perl = which_perl();
18
19
20 $| = 1;
21
22 open(PIPE, "|-") || exec $Perl, '-pe', 'tr/YX/ko/';
23
24 printf PIPE "Xk %d - open |- || exec\n", curr_test();
25 next_test();
26 printf PIPE "oY %d -    again\n", curr_test();
27 next_test();
28 close PIPE;
29
30 {
31     if (open(PIPE, "-|")) {
32         while(<PIPE>) {
33             s/^not //;
34             print;
35         }
36         close PIPE;        # avoid zombies
37     }
38     else {
39         printf STDOUT "not ok %d - open -|\n", curr_test();
40         next_test();
41         my $tnum = curr_test;
42         next_test();
43         exec $Perl, '-le', "print q{not ok $tnum -     again}";
44     }
45
46     # This has to be *outside* the fork
47     next_test() for 1..2;
48
49     my $raw = "abc\nrst\rxyz\r\nfoo\n";
50     if (open(PIPE, "-|")) {
51         $_ = join '', <PIPE>;
52         (my $raw1 = $_) =~ s/not ok \d+ - //;
53         my @r  = map ord, split //, $raw;
54         my @r1 = map ord, split //, $raw1;
55         if ($raw1 eq $raw) {
56             s/^not (ok \d+ -) .*/$1 '@r1' passes through '-|'\n/s;
57         } else {
58             s/^(not ok \d+ -) .*/$1 expect '@r', got '@r1'\n/s;
59         }
60         print;
61         close PIPE;        # avoid zombies
62     }
63     else {
64         printf STDOUT "not ok %d - $raw", curr_test();
65         exec $Perl, '-e0';      # Do not run END()...
66     }
67
68     # This has to be *outside* the fork
69     next_test();
70
71     if (open(PIPE, "|-")) {
72         printf PIPE "not ok %d - $raw", curr_test();
73         close PIPE;        # avoid zombies
74     }
75     else {
76         $_ = join '', <STDIN>;
77         (my $raw1 = $_) =~ s/not ok \d+ - //;
78         my @r  = map ord, split //, $raw;
79         my @r1 = map ord, split //, $raw1;
80         if ($raw1 eq $raw) {
81             s/^not (ok \d+ -) .*/$1 '@r1' passes through '|-'\n/s;
82         } else {
83             s/^(not ok \d+ -) .*/$1 expect '@r', got '@r1'\n/s;
84         }
85         print;
86         exec $Perl, '-e0';      # Do not run END()...
87     }
88
89     # This has to be *outside* the fork
90     next_test();
91
92     SKIP: {
93         skip "fork required", 2 unless $Config{d_fork};
94
95         pipe(READER,WRITER) || die "Can't open pipe";
96
97         if ($pid = fork) {
98             close WRITER;
99             while(<READER>) {
100                 s/^not //;
101                 y/A-Z/a-z/;
102                 print;
103             }
104             close READER;     # avoid zombies
105         }
106         else {
107             die "Couldn't fork" unless defined $pid;
108             close READER;
109             printf WRITER "not ok %d - pipe & fork\n", curr_test;
110             next_test;
111
112             open(STDOUT,">&WRITER") || die "Can't dup WRITER to STDOUT";
113             close WRITER;
114             
115             my $tnum = curr_test;
116             next_test;
117             exec $Perl, '-le', "print q{not ok $tnum -     with fh dup }";
118         }
119
120         # This has to be done *outside* the fork.
121         next_test() for 1..2;
122     }
123
124 wait;                           # Collect from $pid
125
126 pipe(READER,WRITER) || die "Can't open pipe";
127 close READER;
128
129 $SIG{'PIPE'} = 'broken_pipe';
130
131 sub broken_pipe {
132     $SIG{'PIPE'} = 'IGNORE';       # loop preventer
133     printf "ok %d - SIGPIPE\n", curr_test;
134 }
135
136 printf WRITER "not ok %d - SIGPIPE\n", curr_test;
137 close WRITER;
138 sleep 1;
139 next_test;
140 pass();
141
142 # VMS doesn't like spawning subprocesses that are still connected to
143 # STDOUT.  Someone should modify these tests to work with VMS.
144
145 SKIP: {
146     skip "doesn't like spawning subprocesses that are still connected", 10
147       if $^O eq 'VMS';
148
149     SKIP: {
150         # POSIX-BC doesn't report failure when closing a broken pipe
151         # that has pending output.  Go figure.
152         skip "Won't report failure on broken pipe", 1
153           if $^O eq 'posix-bc';
154
155         local $SIG{PIPE} = 'IGNORE';
156         open NIL, qq{|$Perl -e "exit 0"} or die "open failed: $!";
157         sleep 5;
158         if (print NIL 'foo') {
159             # If print was allowed we had better get an error on close
160             ok( !close NIL,     'close error on broken pipe' );
161         }
162         else {
163             ok(close NIL,       'print failed on broken pipe');
164         }
165     }
166
167     {
168         # check that errno gets forced to 0 if the piped program exited 
169         # non-zero
170         open NIL, qq{|$Perl -e "exit 23";} or die "fork failed: $!";
171         $! = 1;
172         ok(!close NIL,  'close failure on non-zero piped exit');
173         is($!, '',      '       errno');
174         isnt($?, 0,     '       status');
175
176         # Former skip block:
177         {
178             # check that status for the correct process is collected
179             my $zombie;
180             unless( $zombie = fork ) {
181                 $NO_ENDING=1;
182                 exit 37;
183             }
184             my $pipe = open *FH, "sleep 2;exit 13|" or die "Open: $!\n";
185             $SIG{ALRM} = sub { return };
186             alarm(1);
187             is( close FH, '',   'close failure for... umm, something' );
188             is( $?, 13*256,     '       status' );
189             is( $!, '',         '       errno');
190
191             my $wait = wait;
192             is( $?, 37*256,     'status correct after wait' );
193             is( $wait, $zombie, '       wait pid' );
194             is( $!, '',         '       errno');
195         }
196     }
197 }
198
199 # Test new semantics for missing command in piped open
200 # 19990114 M-J. Dominus mjd@plover.com
201 { local *P;
202   no warnings 'pipe';
203   ok( !open(P, "|    "),        'missing command in piped open input' );
204   ok( !open(P, "     |"),       '                              output');
205 }
206
207 # check that status is unaffected by implicit close
208 {
209     local(*NIL);
210     open NIL, qq{|$Perl -e "exit 23"} or die "fork failed: $!";
211     $? = 42;
212     # NIL implicitly closed here
213 }
214 is($?, 42,      'status unaffected by implicit close');
215 $? = 0;
216
217 # check that child is reaped if the piped program can't be executed
218 SKIP: {
219   skip "/no_such_process exists", 1 if -e "/no_such_process";
220   open NIL, '/no_such_process |';
221   close NIL;
222
223   my $child = 0;
224   eval {
225     local $SIG{ALRM} = sub { die; };
226     alarm 2;
227     $child = wait;
228     alarm 0;
229   };
230
231   is($child, -1, 'child reaped if piped program cannot be executed');
232 }