1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
|
use blib;
use strict;
use autobox::List::Util;
use Test::More tests => 19;
my $v = []->reduce(sub {});
is( $v, undef, 'no args');
$v = [756,3,7,4]->reduce(sub { $a / $b });
is( $v, 9, '4-arg divide');
$v = [6]->reduce( sub { $a / $b } );
is( $v, 6, 'one arg');
my @a = map { rand } 0 .. 20;
$v = @a->reduce( sub { $a < $b ? $a : $b });
is( $v, @a->min, 'min');
@a = map { pack("C", int(rand(256))) } 0 .. 20;
$v = @a->reduce( sub { $a . $b } );
is( $v, join("",@a), 'concat');
sub add {
my($aa, $bb) = @_;
return $aa + $bb;
}
$v = [3, 2, 1]->reduce( sub { my $t="$a $b\n"; 0+add($a, $b) } );
is( $v, 6, 'call sub');
# Check that eval{} inside the block works correctly
$v = [0,1,2,3,4]->reduce( sub { eval { die }; $a + $b } );
is( $v, 10, 'use eval{}');
$v = !defined eval { [0..4]->reduce( sub { die if $b > 2; $a + $b } ) };
ok($v, 'die');
sub foobar { [0..3]->reduce( sub { (defined(wantarray) && !wantarray) ? $a+1 : 0 } ) }
($v) = foobar();
is( $v, 3, 'scalar context');
sub add2 { $a + $b }
$v = [1,2,3]->reduce(\&add2);
is( $v, 6, 'sub reference');
$v = [3,4,5]->reduce(sub { add2() });
is( $v, 12, 'call sub');
$v = [1,2,3]->reduce( sub { eval "$a + $b" } );
is( $v, 6, 'eval string');
$a = 8; $b = 9;
$v = [1,2,3]->reduce(sub { $a * $b });
is( $a, 8, 'restore $a');
is( $b, 9, 'restore $b');
# Can we leave the sub with 'return'?
$v = [2,4,6]->reduce( sub {return $a+$b} );
is($v, 12, 'return');
# ... even in a loop?
$v = [2,4,6]->reduce(sub {while(1) {return $a+$b} });
is($v, 12, 'return from loop');
# Does it work from another package?
# FIXME: this doesn't work
#{
# package Foo;
# $a = $b;
# ::is([1..4]->reduce( sub {$a*$b} ), 24, 'other package');
#}
# Can we undefine a reduce sub while it's running?
sub self_immolate {undef &self_immolate; 1}
eval { $v = [1,2]->reduce(\&self_immolate) };
like($@, qr/^Can't undef active subroutine/, "undef active sub");
# Redefining an active sub should not fail, but whether the
# redefinition takes effect immediately depends on whether we're
# running the Perl or XS implementation.
sub self_updating { local $^W; *self_updating = sub{1} ;1 }
eval { $v = [1,2]->reduce(\&self_updating) };
is($@, '', 'redefine self');
{ my $failed = 0;
sub rec { my $n = shift;
if (!defined($n)) { # No arg means we're being called by reduce()
return 1; }
if ($n<5) { rec($n+1); }
else { $v = [1,2]->reduce(\&rec) }
$failed = 1 if !defined $n;
}
rec(1);
ok(!$failed, 'from active sub');
}
|