xref: /openbsd-src/gnu/usr.bin/perl/t/op/try.t (revision 5486feefcc8cb79b19e014ab332cc5dfd05b3b33)
1256a93a4Safresh1#!./perl
2256a93a4Safresh1
3256a93a4Safresh1BEGIN {
4256a93a4Safresh1    chdir 't' if -d 't';
5256a93a4Safresh1    require './test.pl';
6256a93a4Safresh1    set_up_inc('../lib');
7256a93a4Safresh1    require Config;
8256a93a4Safresh1}
9256a93a4Safresh1
10256a93a4Safresh1use strict;
11256a93a4Safresh1use warnings;
12256a93a4Safresh1use feature 'try';
13256a93a4Safresh1
14256a93a4Safresh1{
15256a93a4Safresh1    my $x;
16256a93a4Safresh1    try {
17256a93a4Safresh1        $x .= "try";
18256a93a4Safresh1    }
19256a93a4Safresh1    catch ($e) {
20256a93a4Safresh1        $x .= "catch";
21256a93a4Safresh1    }
22256a93a4Safresh1    is($x, "try", 'successful try/catch runs try but not catch');
23256a93a4Safresh1}
24256a93a4Safresh1
25256a93a4Safresh1{
26256a93a4Safresh1    my $x;
27256a93a4Safresh1    my $caught;
28256a93a4Safresh1    try {
29256a93a4Safresh1        $x .= "try";
30256a93a4Safresh1        die "Oopsie\n";
31256a93a4Safresh1    }
32256a93a4Safresh1    catch ($e) {
33256a93a4Safresh1        $x .= "catch";
34256a93a4Safresh1        $caught = $e;
35256a93a4Safresh1        is($@, "", '$@ is empty within catch block');
36256a93a4Safresh1    }
37256a93a4Safresh1    is($x, "trycatch", 'die in try runs catch block');
38256a93a4Safresh1    is($caught, "Oopsie\n", 'catch block saw exception value');
39256a93a4Safresh1}
40256a93a4Safresh1
41256a93a4Safresh1# return inside try {} makes containing function return
42256a93a4Safresh1{
43256a93a4Safresh1    sub f
44256a93a4Safresh1    {
45256a93a4Safresh1        try {
46256a93a4Safresh1            return "return inside try";
47256a93a4Safresh1        }
48256a93a4Safresh1        catch ($e) { }
49256a93a4Safresh1        return "return from func";
50256a93a4Safresh1    }
51256a93a4Safresh1    is(f(), "return inside try", 'return inside try');
52256a93a4Safresh1}
53256a93a4Safresh1
54256a93a4Safresh1# wantarray inside try
55256a93a4Safresh1{
56256a93a4Safresh1    my $context;
57256a93a4Safresh1    sub whatcontext
58256a93a4Safresh1    {
59256a93a4Safresh1        try {
60256a93a4Safresh1            $context = wantarray ? "list" :
61256a93a4Safresh1                defined wantarray ? "scalar" : "void";
62256a93a4Safresh1        }
63256a93a4Safresh1        catch ($e) { }
64256a93a4Safresh1    }
65256a93a4Safresh1
66256a93a4Safresh1    whatcontext();
67256a93a4Safresh1    is($context, "void", 'sub {try} in void');
68256a93a4Safresh1
69256a93a4Safresh1    my $scalar = whatcontext();
70256a93a4Safresh1    is($context, "scalar", 'sub {try} in scalar');
71256a93a4Safresh1
72256a93a4Safresh1    my @array = whatcontext();
73256a93a4Safresh1    is($context, "list", 'sub {try} in list');
74256a93a4Safresh1}
75256a93a4Safresh1
76256a93a4Safresh1# Loop controls inside try {} do not emit warnings
77256a93a4Safresh1{
78256a93a4Safresh1    my $warnings = "";
79256a93a4Safresh1    local $SIG{__WARN__} = sub { $warnings .= $_[0] };
80256a93a4Safresh1
81256a93a4Safresh1    {
82256a93a4Safresh1        try {
83256a93a4Safresh1            last;
84256a93a4Safresh1        }
85256a93a4Safresh1        catch ($e) { }
86256a93a4Safresh1    }
87256a93a4Safresh1
88256a93a4Safresh1    {
89256a93a4Safresh1        try {
90256a93a4Safresh1            next;
91256a93a4Safresh1        }
92256a93a4Safresh1        catch ($e) { }
93256a93a4Safresh1    }
94256a93a4Safresh1
95256a93a4Safresh1    my $count = 0;
96256a93a4Safresh1    {
97256a93a4Safresh1        try {
98256a93a4Safresh1            $count++;
99256a93a4Safresh1            redo if $count < 2;
100256a93a4Safresh1        }
101256a93a4Safresh1        catch ($e) { }
102256a93a4Safresh1    }
103256a93a4Safresh1
104256a93a4Safresh1    is($warnings, "", 'No warnings emitted by next/last/redo inside try');
105256a93a4Safresh1
106256a93a4Safresh1    $warnings = "";
107256a93a4Safresh1
108256a93a4Safresh1    LOOP_L: {
109256a93a4Safresh1        try {
110256a93a4Safresh1            last LOOP_L;
111256a93a4Safresh1        }
112256a93a4Safresh1        catch ($e) { }
113256a93a4Safresh1    }
114256a93a4Safresh1
115256a93a4Safresh1    LOOP_N: {
116256a93a4Safresh1        try {
117256a93a4Safresh1            next LOOP_N;
118256a93a4Safresh1        }
119256a93a4Safresh1        catch ($e) { }
120256a93a4Safresh1    }
121256a93a4Safresh1
122256a93a4Safresh1    $count = 0;
123256a93a4Safresh1    LOOP_R: {
124256a93a4Safresh1        try {
125256a93a4Safresh1            $count++;
126256a93a4Safresh1            redo LOOP_R if $count < 2;
127256a93a4Safresh1        }
128256a93a4Safresh1        catch ($e) { }
129256a93a4Safresh1    }
130256a93a4Safresh1
131256a93a4Safresh1    is($warnings, "", 'No warnings emitted by next/last/redo LABEL inside try');
132256a93a4Safresh1}
133256a93a4Safresh1
134256a93a4Safresh1# try/catch should localise $@
135256a93a4Safresh1{
136256a93a4Safresh1    eval { die "Value before\n"; };
137256a93a4Safresh1
138256a93a4Safresh1    try { die "Localized value\n" } catch ($e) {}
139256a93a4Safresh1
140256a93a4Safresh1    is($@, "Value before\n", 'try/catch localized $@');
141256a93a4Safresh1}
142256a93a4Safresh1
143256a93a4Safresh1# try/catch is not confused by false values
144256a93a4Safresh1{
145256a93a4Safresh1    my $caught;
146256a93a4Safresh1    try {
147256a93a4Safresh1        die 0;
148256a93a4Safresh1    }
149256a93a4Safresh1    catch ($e) {
150256a93a4Safresh1        $caught++;
151256a93a4Safresh1    }
152256a93a4Safresh1
153256a93a4Safresh1    ok( $caught, 'catch{} sees a false exception' );
154256a93a4Safresh1}
155256a93a4Safresh1
156256a93a4Safresh1# try/catch is not confused by always-false objects
157256a93a4Safresh1{
158256a93a4Safresh1    my $caught;
159256a93a4Safresh1    try {
160256a93a4Safresh1        die FALSE->new;
161256a93a4Safresh1    }
162256a93a4Safresh1    catch ($e) {
163256a93a4Safresh1        $caught++;
164256a93a4Safresh1    }
165256a93a4Safresh1
166256a93a4Safresh1    ok( $caught, 'catch{} sees a false-overload exception object' );
167256a93a4Safresh1
168256a93a4Safresh1    {
169256a93a4Safresh1        package FALSE;
170256a93a4Safresh1        use overload 'bool' => sub { 0 };
171256a93a4Safresh1        sub new { bless [], shift }
172256a93a4Safresh1    }
173256a93a4Safresh1}
174256a93a4Safresh1
175256a93a4Safresh1# return from try is correct even for :lvalue subs
176256a93a4Safresh1#   https://github.com/Perl/perl5/issues/18553
177256a93a4Safresh1{
178256a93a4Safresh1    my $scalar;
179256a93a4Safresh1    sub fscalar :lvalue
180256a93a4Safresh1    {
181256a93a4Safresh1        try { return $scalar }
182256a93a4Safresh1        catch ($e) { }
183256a93a4Safresh1    }
184256a93a4Safresh1
185256a93a4Safresh1    fscalar = 123;
186256a93a4Safresh1    is($scalar, 123, 'try { return } in :lvalue sub in scalar context' );
187256a93a4Safresh1
188256a93a4Safresh1    my @array;
189256a93a4Safresh1    sub flist :lvalue
190256a93a4Safresh1    {
191256a93a4Safresh1        try { return @array }
192256a93a4Safresh1        catch ($e) { }
193256a93a4Safresh1    }
194256a93a4Safresh1
195256a93a4Safresh1    (flist) = (4, 5, 6);
196256a93a4Safresh1    ok(eq_array(\@array, [4, 5, 6]), 'try { return } in :lvalue sub in list context' );
197256a93a4Safresh1}
198256a93a4Safresh1
199256a93a4Safresh1# try as final expression yields correct value
200256a93a4Safresh1{
201256a93a4Safresh1    my $scalar = do {
202256a93a4Safresh1        try { 123 }
203256a93a4Safresh1        catch ($e) { 456 }
204256a93a4Safresh1    };
205256a93a4Safresh1    is($scalar, 123, 'do { try } in scalar context');
206256a93a4Safresh1
207256a93a4Safresh1    my @list = do {
208256a93a4Safresh1        try { 1, 2, 3 }
209256a93a4Safresh1        catch ($e) { 4, 5, 6 }
210256a93a4Safresh1    };
211256a93a4Safresh1    ok(eq_array(\@list, [1, 2, 3]), 'do { try } in list context');
212256a93a4Safresh1
213256a93a4Safresh1    # Regression test related to
214256a93a4Safresh1    #   https://github.com/Perl/perl5/issues/18855
215256a93a4Safresh1    $scalar = do {
216256a93a4Safresh1        try { my $x = 123; 456 }
217256a93a4Safresh1        catch ($e) { 789 }
218256a93a4Safresh1    };
219256a93a4Safresh1    is($scalar, 456, 'do { try } with multiple statements');
220256a93a4Safresh1}
221256a93a4Safresh1
222256a93a4Safresh1# catch as final expression yields correct value
223256a93a4Safresh1{
224256a93a4Safresh1    my $scalar = do {
225256a93a4Safresh1        try { die "Oops" }
226256a93a4Safresh1        catch ($e) { 456 }
227256a93a4Safresh1    };
228256a93a4Safresh1    is($scalar, 456, 'do { try/catch } in scalar context');
229256a93a4Safresh1
230256a93a4Safresh1    my @list = do {
231256a93a4Safresh1        try { die "Oops" }
232256a93a4Safresh1        catch ($e) { 4, 5, 6 }
233256a93a4Safresh1    };
234256a93a4Safresh1    ok(eq_array(\@list, [4, 5, 6]), 'do { try/catch } in list context');
235256a93a4Safresh1
236256a93a4Safresh1    # Regression test
237256a93a4Safresh1    #   https://github.com/Perl/perl5/issues/18855
238256a93a4Safresh1    $scalar = do {
239256a93a4Safresh1        try { die "Oops" }
240256a93a4Safresh1        catch ($e) { my $x = 123; "result" }
241256a93a4Safresh1    };
242256a93a4Safresh1    is($scalar, "result", 'do { try/catch } with multiple statements');
243256a93a4Safresh1}
244256a93a4Safresh1
245256a93a4Safresh1# try{} blocks should be invisible to caller()
246256a93a4Safresh1{
247256a93a4Safresh1    my $caller;
248256a93a4Safresh1    sub A { $caller = sprintf "%s (%s line %d)", (caller 1)[3,1,2]; }
249256a93a4Safresh1
250256a93a4Safresh1    sub B {
251256a93a4Safresh1        try { A(); }
252256a93a4Safresh1        catch ($e) {}
253256a93a4Safresh1    }
254256a93a4Safresh1
255256a93a4Safresh1    my $LINE = __LINE__+1;
256256a93a4Safresh1    B();
257256a93a4Safresh1
258256a93a4Safresh1    is($caller, "main::B ($0 line $LINE)", 'try {} block is invisible to caller()');
259256a93a4Safresh1}
260256a93a4Safresh1
261256a93a4Safresh1# try/catch/finally
262*5486feefSafresh1
263*5486feefSafresh1# experimental warnings
264*5486feefSafresh1{
265*5486feefSafresh1    my $warnings;
266*5486feefSafresh1    BEGIN { $SIG{__WARN__} = sub { $warnings .= shift; }; }
267*5486feefSafresh1
268*5486feefSafresh1    my ($lfinally) = (__LINE__+5);
269*5486feefSafresh1    try {
270*5486feefSafresh1    }
271*5486feefSafresh1    catch ($e) {
272*5486feefSafresh1    }
273*5486feefSafresh1    finally {
274*5486feefSafresh1    }
275*5486feefSafresh1
276*5486feefSafresh1    is($warnings, "try/catch/finally is experimental at $0 line $lfinally.\n",
277*5486feefSafresh1        'compiletime warnings');
278*5486feefSafresh1    BEGIN { undef $SIG{__WARN__}; }
279*5486feefSafresh1}
280*5486feefSafresh1
281*5486feefSafresh1no warnings 'experimental::try';
282*5486feefSafresh1
283256a93a4Safresh1{
284256a93a4Safresh1    my $x;
285256a93a4Safresh1    try {
286256a93a4Safresh1        $x .= "try";
287256a93a4Safresh1    }
288256a93a4Safresh1    catch ($e) {
289256a93a4Safresh1        $x .= "catch";
290256a93a4Safresh1    }
291256a93a4Safresh1    finally {
292256a93a4Safresh1        $x .= "finally";
293256a93a4Safresh1    }
294256a93a4Safresh1    is($x, "tryfinally", 'successful try/catch/finally runs try+finally but not catch');
295256a93a4Safresh1}
296256a93a4Safresh1
297256a93a4Safresh1{
298256a93a4Safresh1    my $x;
299256a93a4Safresh1    try {
300256a93a4Safresh1        $x .= "try";
301256a93a4Safresh1        die "Oopsie\n";
302256a93a4Safresh1    }
303256a93a4Safresh1    catch ($e) {
304256a93a4Safresh1        $x .= "catch";
305256a93a4Safresh1    }
306256a93a4Safresh1    finally {
307256a93a4Safresh1        $x .= "finally";
308256a93a4Safresh1    }
309256a93a4Safresh1    is($x, "trycatchfinally", 'try/catch/finally runs try+catch+finally on failure');
310256a93a4Safresh1}
311256a93a4Safresh1
312256a93a4Safresh1{
313256a93a4Safresh1    my $finally_invoked;
314256a93a4Safresh1    sub ff
315256a93a4Safresh1    {
316256a93a4Safresh1        try {
317256a93a4Safresh1            return "return inside try+finally";
318256a93a4Safresh1        }
319256a93a4Safresh1        catch ($e) {}
320256a93a4Safresh1        finally { $finally_invoked++; "last value" }
321256a93a4Safresh1        return "return from func";
322256a93a4Safresh1    }
323256a93a4Safresh1    is(ff(), "return inside try+finally", 'return inside try+finally');
324256a93a4Safresh1    ok($finally_invoked, 'finally block still invoked for side-effects');
325256a93a4Safresh1}
326256a93a4Safresh1
327f2a19305Safresh1# Nicer compiletime errors
328256a93a4Safresh1{
329256a93a4Safresh1    my $e;
330256a93a4Safresh1
331f2a19305Safresh1    $e = defined eval 'try { A() } catch { B() }; 1;' ? undef : $@;
332f2a19305Safresh1    like($e, qr/^catch block requires a \(VAR\) at /,
333f2a19305Safresh1        'Parse error for catch without (VAR)');
334256a93a4Safresh1}
335256a93a4Safresh1
336256a93a4Safresh1done_testing;
337