Test-MockFile
view release on metacpan or search on metacpan
my $parent = Test::MockFile->new_dir( '/perms/mdir', { mode => 0755, uid => 1000, gid => 1000 } );
my $target = Test::MockFile->dir('/perms/mdir/newdir');
with_user {
ok( mkdir('/perms/mdir/newdir'), 'parent owner can mkdir' );
} 1000, 1000;
# Clean up and re-mock for next test
my $parent2 = Test::MockFile->new_dir( '/perms/mdir2', { mode => 0555, uid => 1000, gid => 1000 } );
my $target2 = Test::MockFile->dir('/perms/mdir2/newdir2');
with_user {
ok( !mkdir('/perms/mdir2/newdir2'), 'cannot mkdir in 0555 dir (no write)' );
is( $! + 0, EACCES, 'mkdir errno is EACCES' );
} 1000, 1000;
};
# =========================================================================
# rmdir permission checks (needs write+exec on parent)
# =========================================================================
subtest 'rmdir permission checks on parent directory' => sub {
my $parent = Test::MockFile->new_dir( '/perms/rdir', { mode => 0755, uid => 1000, gid => 1000 } );
my $target = Test::MockFile->new_dir('/perms/rdir/empty');
with_user {
ok( rmdir('/perms/rdir/empty'), 'parent owner can rmdir empty dir' );
} 1000, 1000;
my $parent2 = Test::MockFile->new_dir( '/perms/rdir2', { mode => 0555, uid => 1000, gid => 1000 } );
my $target2 = Test::MockFile->new_dir('/perms/rdir2/empty2');
with_user {
ok( !rmdir('/perms/rdir2/empty2'), 'cannot rmdir in 0555 dir (no write)' );
is( $! + 0, EACCES, 'rmdir errno is EACCES' );
} 1000, 1000;
};
# =========================================================================
# chmod permission checks (only owner or root)
# =========================================================================
subtest 'chmod permission checks' => sub {
my $f = Test::MockFile->file( '/perms/chm', 'data', { mode => 0644, uid => 1000, gid => 1000 } );
with_user {
is( chmod( 0600, '/perms/chm' ), 1, 'owner can chmod' );
} 1000, 1000;
with_user {
is( chmod( 0777, '/perms/chm' ), 0, 'non-owner cannot chmod' );
is( $! + 0, EPERM, 'chmod errno is EPERM' );
} 2000, 2000;
with_user {
is( chmod( 0777, '/perms/chm' ), 1, 'root can chmod any file' );
} 0, 0;
};
# =========================================================================
# chown with mock user
# =========================================================================
subtest 'chown uses mock user identity' => sub {
my $f = Test::MockFile->file( '/perms/cho', 'data', { mode => 0644, uid => 1000, gid => 1000 } );
# Non-root mock user cannot chown to a different user
with_user {
is( chown( 2000, 2000, '/perms/cho' ), 0, 'non-root mock user cannot chown to different user' );
is( $! + 0, EPERM, 'chown errno is EPERM' );
} 1000, 1000;
# Root mock user can chown
with_user {
is( chown( 2000, 2000, '/perms/cho' ), 1, 'root mock user can chown' );
} 0, 0;
};
# =========================================================================
# Non-existent file bypasses permission checks (ENOENT takes priority)
# =========================================================================
subtest 'non-existent file returns ENOENT not EACCES' => sub {
my $f = Test::MockFile->file('/perms/noexist');
with_user {
ok( !open( my $fh, '<', '/perms/noexist' ), 'cannot open non-existent file' );
# ENOENT should come before permission check
} 1000, 1000;
};
# =========================================================================
# Multiple group membership
# =========================================================================
subtest 'user with multiple groups' => sub {
skip_all 'umask strips group bits' if $restrictive_umask;
my $f = Test::MockFile->file( '/perms/multigrp', 'data', { mode => 0040, uid => 1000, gid => 500 } );
# User in secondary group 500
with_user {
ok( open( my $fh, '<', '/perms/multigrp' ), 'user in secondary group can read' );
close $fh if $fh;
} 2000, 100, 500, 600;
# User NOT in group 500
with_user {
ok( !open( my $fh, '<', '/perms/multigrp' ), 'user not in any matching group cannot read' );
} 2000, 100, 200, 300;
};
# =========================================================================
# open with write-creating modes checks parent perms
# =========================================================================
subtest 'open > on new file checks parent directory perms' => sub {
my $parent = Test::MockFile->new_dir( '/perms/wdir', { mode => 0555, uid => 1000, gid => 1000 } );
my $child = Test::MockFile->file('/perms/wdir/newfile');
with_user {
ok( !open( my $fh, '>', '/perms/wdir/newfile' ), 'cannot create file in read-only parent dir' );
is( $! + 0, EACCES, 'errno is EACCES' );
} 1000, 1000;
my $parent2 = Test::MockFile->new_dir( '/perms/wdir2', { mode => 0755, uid => 1000, gid => 1000 } );
my $child2 = Test::MockFile->file('/perms/wdir2/newfile2');
with_user {
ok( open( my $fh, '>', '/perms/wdir2/newfile2' ), 'can create file in writable parent dir' );
close $fh if $fh;
} 1000, 1000;
};
done_testing();
( run in 0.676 second using v1.01-cache-2.11-cpan-5511b514fd6 )