6 use Test::More tests => 9 + 4 * 7 + 3 + ((5 * 4 * 4) * 3 + 1) + 5 + 3 + 2 + 6;
8 use Scope::Upper qw<uplevel HERE UP>;
13 uplevel { pass 'no @_: callback' };
14 is "@_", 'dummy', 'no @_: @_ outside';
18 uplevel { is "@_", '', "no arguments, no context" }
22 uplevel { is "@_", '', "no arguments, with context" } HERE
26 uplevel { is "@_", '1', "one const argument" } 1, HERE
31 uplevel { is "@_", '2', "one lexical argument" } $x, HERE
36 uplevel { is "@_", '3', "one global argument" } $y, HERE
40 uplevel { is "@_", '4 5', "two const arguments" } 4, 5, HERE
44 uplevel { is "@_", '1 2 3 4 5 6 7 8 9 10', "ten const arguments" }
54 is $r, 1, 'shift: result';
55 is_deeply \@_, [ 2 .. 10 ], 'shift: @_ inside';
57 is_deeply \@args, [ 1 .. 10 ], 'shift: args';
58 is_deeply \@_, [ 'dummy' ], 'shift: @_ outside';
65 is $r, 10, 'pop: result';
66 is_deeply \@_, [ 1 .. 9 ], 'pop: @_ inside';
68 is_deeply \@args, [ 1 .. 10 ], 'pop: args';
69 is_deeply \@_, [ 'dummy' ], 'pop: @_ outside';
75 my $r = unshift @_, 0;
76 is $r, 11, 'unshift: result';
77 is_deeply \@_, [ 0 .. 10 ], 'unshift: @_ inside';
79 is_deeply \@args, [ 1 .. 10 ], 'unshift: args';
80 is_deeply \@_, [ 'dummy' ], 'unshift: @_ outside';
87 is $r, 11, 'push: result';
88 is_deeply \@_, [ 1 .. 11 ], 'push: @_ inside';
90 is_deeply \@args, [ 1 .. 10 ], 'push: args';
91 is_deeply \@_, [ 'dummy' ], 'push: @_ outside';
97 my ($r) = splice @_, 4, 1;
98 is $r, 5, 'splice: result';
99 is_deeply \@_, [ 1 .. 4, 6 .. 10 ], 'splice: @_ inside';
101 is_deeply \@args, [ 1 .. 10 ], 'splice: args';
102 is_deeply \@_, [ 'dummy' ], 'splice: @_ outside';
106 my @args = (1 .. 10);
108 my ($r, $s, $t, @rest) = @_;
109 is_deeply [ $r, $s, $t, \@rest ], [ 1 .. 3, [ 4 .. 10 ] ], 'unpack 1: result';
110 is_deeply \@_, [ 1 .. 10 ], 'unpack 1: @_ inside';
112 is_deeply \@args, [ 1 .. 10 ], 'unpack 1: args';
113 is_deeply \@_, [ 'dummy' ], 'unpack 1: @_ outside';
119 my ($r, $s, $t, @rest) = @_;
120 is_deeply [ $r, $s, $t, \@rest ], [ 1, 2, undef, [ ] ], 'unpack 2: result';
121 is_deeply \@_, [ 1, 2 ], 'unpack 2: @_ inside';
123 is_deeply \@args, [ 1, 2 ], 'unpack 2: args';
124 is_deeply \@_, [ 'dummy' ], 'unpack 2: @_ outside';
134 is $s, 'xyz', 'aliasing, one layer';
143 is $_[0], 'xyz', 'aliasing, two layers 1';
145 is $s, 'xyz', 'aliasing, two layers 2';
154 [ [ 'b' ], [ 'n' ] ],
155 [ [ 'c' ], [ 'o', 'p' ] ],
156 [ [ 'd', 'e' ], [ 'q' ] ],
159 for my $args (@args) {
160 my ($out, $in) = @$args;
165 for my $reify_out (0, 1) {
166 for my $reify_in (0, 1) {
169 my $base_test = sub {
171 is_deeply \@_, $in, "$desc: \@_ inside";
173 is "@_", "@in", "$desc: \@_ inside";
177 my $goto_test = sub { goto $base_test };
178 my $uplevel_test = sub { &uplevel($base_test, @_, HERE) };
179 my $goto_uplevel_test = sub { &uplevel($goto_test, @_, HERE) };
182 [ 'goto' => sub { goto $base_test } ],
183 [ 'goto in goto' => sub { goto $goto_test } ],
184 [ 'uplevel in goto' => sub { goto $uplevel_test } ],
185 [ 'goto in uplevel in goto' => sub { goto $goto_uplevel_test } ],
188 for my $test (@tests) {
189 ($desc, my $cb) = @$test;
190 $desc .= ' (' . @out . ' out, ' . @in . ' in';
191 $desc .= ', reify out' if $reify_out;
192 $desc .= ', reify in' if $reify_in;
198 &uplevel($cb, @in, HERE);
200 is_deeply \@_, $out, "$desc: \@_ outside";
202 is "@_", "@out", "$desc: \@_ outside";
206 is $@, '', "$desc: no error";
222 is $s, 'brutus', 'aliasing and goto';
229 my $desc = 'uplevel() calling goto &uplevel';
233 my $outer_cxt = HERE;
235 my $inner_cxt = HERE;
238 is HERE, $inner_cxt, "$desc: context inside first uplevel";
239 is "@_", '1 2 3', "$desc: arguments inisde first uplevel";
243 is HERE, $outer_cxt, "$desc: context inside second uplevel";
244 is "@_", '0 1 2 3 4', "$desc: arguments inisde second uplevel";
253 is $@, '', "$desc: no error";
256 # uplevel() to uplevel()
259 my $desc = '\&uplevel as the uplevel() callback';
266 # Note that an XS call does not need a context, so after the first uplevel
267 # call UP will point to the scope above the first target.
268 uplevel(\&uplevel => (sub {
269 is "@_", '1 2 3', "$desc: arguments inisde";
270 is HERE, $cxt, "$desc: context inside";
271 } => 1 .. 3 => UP) => UP);
273 }->(sub { die 'wut' } => HERE);
276 is $@, '', "$desc: no error";
282 package Scope::Upper::TestMagic;
285 my ($class, $cb) = @_;
286 bless { cb => $cb }, $class;
289 sub FETCH { $_[0]->{cb}->(@_) }
291 sub STORE { die "Read only magic scalar" }
294 tie my $mg, 'Scope::Upper::TestMagic', sub { $$ };
296 uplevel { is_deeply \@_, [ $$ ], "one magical argument" } $mg, HERE
299 tie my $mg2, 'Scope::Upper::TestMagic', sub { $mg };
301 uplevel { is_deeply \@_, [ $$ ], "one double magical argument" } $mg2, HERE
307 package Scope::Upper::TestTimelyDestruction;
310 my ($class, $flag) = @_;
312 bless { flag => $flag }, $class;
321 skip 'This fails even with a plain subroutine call on 5.8.0' => 6
326 my $z = Scope::Upper::TestTimelyDestruction->new(\$destroyed);
327 is $destroyed, 0, 'destruction: not yet 1';
329 is $destroyed, 0, 'destruction: not yet 2';
331 is $destroyed, 0, 'destruction: not yet 3';
333 is $destroyed, 0, 'destruction: not yet 4';
335 is $destroyed, 0, 'destruction: not yet 5';
337 is $destroyed, 1, 'destruction: destroyed';