Safe-Hole
view release on metacpan or search on metacpan
t/01-hole.t view on Meta::CPAN
use strict;
use warnings;
use Test::More tests => 41;
use_ok('Safe::Hole');
use Safe;
use Opcode qw( opmask_add opset );
# Test construction
my $safe = Safe->new;
isa_ok( $safe, 'Safe' );
my $hole = Safe::Hole->new( {} );
isa_ok( $hole, 'Safe::Hole' );
# Test visibility of root namespace
our $v;
isnt( \$v, $safe->reval('\$v'), 'Test visibility of root namespace' );
is( $@, '', "Reval \$v" );
sub v { eval '\$v' }
is( \$v, $hole->call( \&v ), "\$hole->call returns \\\$v" );
$hole->wrap( sub { eval '\$v' }, $safe, '&v_wrapped' );
$safe->share('&v');
isnt( \$v, $safe->reval('v()'), "\$save->reval('v()') returns \$v" );
is( $@, '', "No error on reval call" );
is( \$v, $safe->reval('v_wrapped()'), "\$safe->reval('v_wrapped()') returns \$v" );
is( $@, '', "No error on reval(vrwapped) call" );
# First check Safe works as we expect
my $op = '"Somthing innocuous"';
sub do_op { eval $op; $@ }
$safe->share('&do_op');
ok( !$safe->reval('do_op()'), q{$safe->reval('do_op()') returns false} );
$op = 'eval "#Something forbidden"';
ok( $safe->reval('do_op()'), q{$safe->reval('do_op()') retuns true after doing an invalid eval} );
# Check Safe::Hole clears the opmask
$hole->wrap( \&do_op, $safe, '&do_op_wrapped' );
ok( !$safe->reval('do_op_wrapped()'), q{Check Safe::Hole clears the opmask} );
# Reality: check eof allowed
$op = 'eof';
ok( $safe->reval('do_op()'), 'Reality: check eof allowed' );
# Disable one opcode
opmask_add( opset('eof') );
# Make sure that opmask is restored
$hole->call( sub { } );
# Disabled opcode propagates into Safe compartment
ok( $safe->reval('do_op()'), 'Disabled opcode propagates into Safe compartment' );
# Disabled opcode is not disabled via $hole
ok( !$hole->call( \&do_op ), 'Disabled opcode is not disabled via $hole' );
# Now create a Safe::Hole with a saved opmask
my $hole2 = Safe::Hole->new( {} );
isa_ok( $hole2, "Safe::Hole", '$hole2' );
# Sanity check it works at all
is( 666, $hole2->call( sub { 666 } ), '$hole2->call(sub{ 666 }) returns 666' );
$op = 'length';
ok( !$hole2->call( \&do_op ), '$hole2->call(do_op) returns false' );
$op = 'eof';
ok( $hole2->call( \&do_op ), '$hole2->call(\&do_op) returns true' );
$hole2->wrap( \&do_op, $safe, '&do_op_wrapped2' );
# We can still get at forbidden op via $hole...
ok( !$safe->reval('do_op_wrapped()'), 'We can still get at forbidden op via $hole' );
# ...but not via $hole2
ok( $safe->reval('do_op_wrapped2()'), '...but not via $hole2' );
# Check argument and return passing
is( $hole2->call( sub { @{ $_[2] } }, undef, undef, [ 11 .. 15 ] ), 5, 'Check argument and return passing (5)' );
is(
(
$hole->call(
sub {
map { $_ + shift } 10 .. 15;
},
20 .. 25
)
)[2],
34,
'Check argument and return passing (34)'
);
# Check exception handling of die
my $did_not_die;
eval {
$hole2->call( sub { die "XXX\n" } );
$did_not_die++;
};
is( $did_not_die, undef, 'Check exception handling of die - eval doesn\'t cause die' );
is( $@, "XXX\n", "\$\@ is populated" );
##############################
# Backward compatible mode
###############################
my $old_hole = new Safe::Hole;
( run in 0.581 second using v1.01-cache-2.11-cpan-5511b514fd6 )