1 # $Id: File.pm,v 1.1 2007/01/16 23:01:44 gumpu Exp $
6 use vars qw(@EXPORT $VERSION);
12 file_exists_ok file_not_exists_ok
13 file_empty_ok file_not_empty_ok file_size_ok file_max_size_ok
14 file_min_size_ok file_readable_ok file_not_readable_ok file_writeable_ok
15 file_not_writeable_ok file_executable_ok file_not_executable_ok
16 file_mode_is file_mode_isnt
18 symlink_target_exists_ok
19 symlink_target_dangles_ok
20 link_count_is_ok link_count_gt_ok link_count_lt_ok
25 $VERSION = sprintf "%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/;
27 my $Test = Test::Builder->new();
31 Test::File -- test file attributes
39 This modules provides a collection of test utilities for file
42 Some file attributes depend on the owner of the process testing the
43 file in the same way the file test operators do. For instance, root
44 (or super-user or Administrator) may always be able to read files no
45 matter the permissions.
47 Some attributes don't make sense outside of Unix, either, so some
48 tests automatically skip if they think they won't work on the
49 platform. If you have a way to make these functions work on Windows,
50 for instance, please send me a patch. :)
59 return unless defined $file;
62 ? File::Spec->catfile( split m|/|, $file )
68 return 0 if $^O eq 'darwin';
72 sub _no_symlinks_here { ! eval { symlink("",""); 1 } }
74 # owner_is and owner_isn't should skip on OS where the question makes no
75 # sence. I really don't know a good way to test for that, so I'm going
76 # to skip on the two OS's that I KNOW aren't multi-user. I'd love to add
77 # more if anyone knows of any
78 # Note: I don't have a dos or mac os < 10 machine to test this on
79 sub _obviously_non_multi_user
89 eval { my $holder = getpwuid(0) };
92 eval { my $holder = getgrgid(0) };
100 =item file_exists_ok( FILENAME [, NAME ] )
102 Ok if the file exists, and not ok otherwise.
106 sub file_exists_ok($;$)
108 my $filename = _normalize( shift );
109 my $name = shift || "$filename exists";
111 my $ok = -e $filename;
119 $Test->diag("File [$filename] does not exist");
124 =item file_not_exists_ok( FILENAME [, NAME ] )
126 Ok if the file does not exist, and not okay if it does exist.
130 sub file_not_exists_ok($;$)
132 my $filename = _normalize( shift );
133 my $name = shift || "$filename does not exist";
135 my $ok = not -e $filename;
143 $Test->diag("File [$filename] exists");
148 =item file_empty_ok( FILENAME [, NAME ] )
150 Ok if the file exists and has empty size, not ok if the
151 file does not exist or exists with non-zero size.
155 sub file_empty_ok($;$)
157 my $filename = _normalize( shift );
158 my $name = shift || "$filename is empty";
160 my $ok = -z $filename;
170 my $size = -s $filename;
171 $Test->diag( "File exists with non-zero size [$size] b");
175 $Test->diag( 'File does not exist');
182 =item file_not_empty_ok( FILENAME [, NAME ] )
184 Ok if the file exists and has non-zero size, not ok if the
185 file does not exist or exists with zero size.
189 sub file_not_empty_ok($;$)
191 my $filename = _normalize( shift );
192 my $name = shift || "$filename is not empty";
194 my $ok = not -z $filename;
202 if( -e $filename and -z $filename )
204 $Test->diag( "File [$filename] exists with zero size" );
208 $Test->diag( "File [$filename] does not exist" );
215 =item file_size_ok( FILENAME, SIZE [, NAME ] )
217 Ok if the file exists and has SIZE size in bytes (exactly), not ok if
218 the file does not exist or exists with size other than SIZE.
222 sub file_size_ok($$;$)
224 my $filename = _normalize( shift );
225 my $expected = int shift;
226 my $name = shift || "$filename has right size";
228 my $ok = ( -s $filename ) == $expected;
236 unless( -e $filename )
238 $Test->diag( "File [$filename] does not exist" );
242 my $actual = -s $filename;
244 "File [$filename] has actual size [$actual] not [$expected]" );
251 =item file_max_size_ok( FILENAME, MAX [, NAME ] )
253 Ok if the file exists and has size less than or equal to MAX bytes, not
254 ok if the file does not exist or exists with size greater than MAX
259 sub file_max_size_ok($$;$)
261 my $filename = _normalize( shift );
263 my $name = shift || "$filename is under $max bytes";
265 my $ok = ( -s $filename ) <= $max;
273 unless( -e $filename )
275 $Test->diag( "File [$filename] does not exist" );
279 my $actual = -s $filename;
281 "File [$filename] has actual size [$actual] " .
282 "greater than [$max]"
290 =item file_min_size_ok( FILENAME, MIN [, NAME ] )
292 Ok if the file exists and has size greater than or equal to MIN bytes,
293 not ok if the file does not exist or exists with size less than MIN
298 sub file_min_size_ok($$;$)
300 my $filename = _normalize( shift );
302 my $name = shift || "$filename is over $min bytes";
304 my $ok = ( -s $filename ) >= $min;
312 unless( -e $filename )
314 $Test->diag( "File [$filename] does not exist" );
318 my $actual = -s $filename;
320 "File [$filename] has actual size ".
321 "[$actual] less than [$min]"
329 =item file_readable_ok( FILENAME [, NAME ] )
331 Ok if the file exists and is readable, not ok
332 if the file does not exist or is not readable.
336 sub file_readable_ok($;$)
338 my $filename = _normalize( shift );
339 my $name = shift || "$filename is readable";
341 my $ok = -r $filename;
349 $Test->diag( "File [$filename] is not readable" );
354 =item file_not_readable_ok( FILENAME [, NAME ] )
356 Ok if the file exists and is not readable, not ok
357 if the file does not exist or is readable.
361 sub file_not_readable_ok($;$)
363 my $filename = _normalize( shift );
364 my $name = shift || "$filename is not readable";
366 my $ok = not -r $filename;
374 $Test->diag( "File [$filename] is readable" );
379 =item file_writeable_ok( FILENAME [, NAME ] )
381 Ok if the file exists and is writeable, not ok
382 if the file does not exist or is not writeable.
386 sub file_writeable_ok($;$)
388 my $filename = _normalize( shift );
389 my $name = shift || "$filename is writeable";
391 my $ok = -w $filename;
399 $Test->diag( "File [$filename] is not writeable" );
404 =item file_not_writeable_ok( FILENAME [, NAME ] )
406 Ok if the file exists and is not writeable, not ok
407 if the file does not exist or is writeable.
411 sub file_not_writeable_ok($;$)
413 my $filename = _normalize( shift );
414 my $name = shift || "$filename is not writeable";
416 my $ok = not -w $filename;
424 $Test->diag("File [$filename] is writeable");
429 =item file_executable_ok( FILENAME [, NAME ] )
431 Ok if the file exists and is executable, not ok
432 if the file does not exist or is not executable.
434 This test automatically skips if it thinks it is on a
439 sub file_executable_ok($;$)
443 $Test->skip( "file_executable_ok doesn't work on Windows" );
447 my $filename = _normalize( shift );
448 my $name = shift || "$filename is executable";
450 my $ok = -x $filename;
458 $Test->diag("File [$filename] is not executable");
463 =item file_not_executable_ok( FILENAME [, NAME ] )
465 Ok if the file exists and is not executable, not ok
466 if the file does not exist or is executable.
468 This test automatically skips if it thinks it is on a
473 sub file_not_executable_ok($;$)
477 $Test->skip( "file_not_executable_ok doesn't work on Windows" );
481 my $filename = _normalize( shift );
482 my $name = shift || "$filename is not executable";
484 my $ok = not -x $filename;
492 $Test->diag("File [$filename] is executable");
497 =item file_mode_is( FILENAME, MODE [, NAME ] )
499 Ok if the file exists and the mode matches, not ok
500 if the file does not exist or the mode does not match.
502 This test automatically skips if it thinks it is on a
505 Contributed by Shawn Sorichetti C<< <ssoriche@coloredblocks.net> >>
509 sub file_mode_is($$;$)
513 $Test->skip( "file_mode_is doesn't work on Windows" );
517 my $filename = _normalize( shift );
520 my $name = shift || sprintf("%s mode is %04o", $filename, $mode);
522 my $ok = -e $filename && ((stat($filename))[2] & 07777) == $mode;
530 $Test->diag(sprintf("File [%s] mode is not %04o", $filename, $mode) );
535 =item file_mode_isnt( FILENAME, MODE [, NAME ] )
537 Ok if the file exists and mode does not match, not ok
538 if the file does not exist or mode does match.
540 This test automatically skips if it thinks it is on a
543 Contributed by Shawn Sorichetti C<< <ssoriche@coloredblocks.net> >>
547 sub file_mode_isnt($$;$)
551 $Test->skip( "file_mode_isnt doesn't work on Windows" );
555 my $filename = _normalize( shift );
558 my $name = shift || sprintf("%s mode is not %04o",$filename,$mode);
560 my $ok = not (-e $filename && ((stat($filename))[2] & 07777) == $mode);
568 $Test->diag(sprintf("File [%s] mode is %04o",$filename,$mode));
573 =item file_is_symlink_ok( FILENAME [, NAME] )
575 Ok is FILENAME is a symlink, even if it points to a non-existent
576 file. This test automatically skips if the operating system does
577 not support symlinks. If the file does not exist, the test fails.
579 The optional NAME parameter is the name of the test.
583 sub file_is_symlink_ok
585 if( _no_symlinks_here() )
588 "file_is_symlink_ok doesn't work on systems without symlinks" );
593 my $name = shift || "$file is a symlink";
601 $Test->diag( "File [$file] is not a symlink!" );
606 =item symlink_target_exists_ok( SYMLINK [, TARGET] [, NAME] )
608 Ok is FILENAME is a symlink and it points to a existing file. With the
609 optional TARGET argument, the test fails if SYMLINK's target is not
610 TARGET. This test automatically skips if the operating system does not
611 support symlinks. If the file does not exist, the test fails.
613 The optional NAME parameter is the name of the test.
617 sub symlink_target_exists_ok
619 if( _no_symlinks_here() )
622 "symlink_target_exists_ok doesn't work on systems without symlinks"
628 my $dest = shift || readlink( $file );
629 my $name = shift || "$file is a symlink";
633 $Test->diag( "File [$file] is not a symlink!" );
634 return $Test->ok( 0, $name );
639 $Test->diag( "Symlink [$file] points to non-existent target [$dest]!" );
640 return $Test->ok( 0, $name );
643 my $actual = readlink( $file );
644 unless( $dest eq $actual )
647 "Symlink [$file] points to\n\t$actual\nexpected\n\t$dest\n\n" );
648 return $Test->ok( 0, $name );
651 $Test->ok( 1, $name );
654 =item symlink_target_dangles_ok( SYMLINK [, NAME] )
656 Ok if FILENAME is a symlink and if it doesn't point to a existing
657 file. This test automatically skips if the operating system does not
658 support symlinks. If the file does not exist, the test fails.
660 The optional NAME parameter is the name of the test.
664 sub symlink_target_dangles_ok
666 if( _no_symlinks_here() )
669 "symlink_target_exists_ok doesn't work on systems without symlinks" );
674 my $dest = readlink( $file );
675 my $name = shift || "$file is a symlink";
679 $Test->diag( "File [$file] is not a symlink!" );
680 return $Test->ok( 0, $name );
686 "Symlink [$file] points to existing file [$dest] but shouldn't!" );
687 return $Test->ok( 0, $name );
690 $Test->ok( 1, $name );
693 =item link_count_is_ok( FILE, LINK_COUNT [, NAME] )
695 Ok if the link count to FILE is LINK_COUNT. LINK_COUNT is interpreted
696 as an integer. A LINK_COUNT that evaluates to 0 returns Ok if the file
697 does not exist. This test automatically skips if the operating system
698 does not support symlinks. If the file does not exist, the test fails.
700 The optional NAME parameter is the name of the test.
707 if( _no_symlinks_here() )
710 "link_count_is_ok doesn't work on systems without symlinks" );
715 my $count = int( 0 + shift );
717 my $name = shift || "$file has a link count of [$count]";
719 my $actual = (stat $file )[3];
721 unless( $actual == $count )
724 "File [$file] points has [$actual] links: expected [$count]!" );
725 return $Test->ok( 0, $name );
728 $Test->ok( 1, $name );
731 =item link_count_gt_ok( FILE, LINK_COUNT [, NAME] )
733 Ok if the link count to FILE is greater than LINK_COUNT. LINK_COUNT is
734 interpreted as an integer. A LINK_COUNT that evaluates to 0 returns Ok
735 if the file has at least one link. This test automatically skips if
736 the operating system does not support symlinks. If the file does not
737 exist, the test fails.
739 The optional NAME parameter is the name of the test.
745 if( _no_symlinks_here() )
748 "link_count_gt_ok doesn't work on systems without symlinks" );
753 my $count = int( 0 + shift );
755 my $name = shift || "$file has a link count of [$count]";
757 my $actual = (stat $file )[3];
759 unless( $actual > $count )
762 "File [$file] points has [$actual] links: ".
763 "expected more than [$count]!" );
764 return $Test->ok( 0, $name );
767 $Test->ok( 1, $name );
770 =item link_count_lt_ok( FILE, LINK_COUNT [, NAME] )
772 Ok if the link count to FILE is less than LINK_COUNT. LINK_COUNT is
773 interpreted as an integer. A LINK_COUNT that evaluates to 0 returns Ok
774 if the file has at least one link. This test automatically skips if
775 the operating system does not support symlinks. If the file does not
776 exist, the test fails.
778 The optional NAME parameter is the name of the test.
784 if( _no_symlinks_here() )
787 "link_count_lt_ok doesn't work on systems without symlinks" );
792 my $count = int( 0 + shift );
794 my $name = shift || "$file has a link count of [$count]";
796 my $actual = (stat $file )[3];
798 unless( $actual < $count )
801 "File [$file] points has [$actual] links: ".
802 "expected more than [$count]!" );
803 return $Test->ok( 0, $name );
806 $Test->ok( 1, $name );
810 # owner_is, owner_isnt, group_is and group_isnt are almost
811 # identical in the beginning, so I'm writing a skeleton they can all use.
812 # I can't think of a better name...
815 if( _obviously_non_multi_user() )
817 my $calling_sub = (caller(1))[3];
818 $Test->skip( $calling_sub . " only works on a multi-user OS" );
822 my $filename = _normalize( shift );
823 my $testing_for = shift;
826 unless( defined $filename )
828 $Test->diag( "File name not specified" );
829 return $Test->ok( 0, $name );
832 unless( -e $filename )
834 $Test->diag( "File [$filename] does not exist" );
835 return $Test->ok( 0, $name );
841 =item owner_is( FILE , OWNER [, NAME] )
843 Ok if FILE's owner is the same as OWNER. OWNER may be a text user name
844 or a numeric userid. Test skips on Dos, and Mac OS <= 9.
845 If the file does not exist, the test fails.
847 The optional NAME parameter is the name of the test.
849 Contributed by Dylan Martin
855 my $filename = shift;
857 my $name = shift || "$filename belongs to $owner";
859 my $err = _dm_skeleton( $filename, $owner, $name );
860 return if( defined( $err ) && $err eq 'skip' );
861 return $err if defined($err);
863 my $owner_uid = _get_uid( $owner );
865 my $file_uid = ( stat $filename )[4];
867 unless( defined $file_uid )
869 $Test->skip("stat failed to return owner uid for $filename");
873 return $Test->ok( 1, $name ) if $file_uid == $owner_uid;
875 my $real_owner = ( getpwuid $file_uid )[0];
876 unless( defined $real_owner )
878 $Test->diag("File does not belong to $owner");
879 return $Test->ok( 0, $name );
882 $Test->diag( "File [$filename] belongs to $real_owner ($file_uid), ".
883 "not $owner ($owner_uid)" );
884 return $Test->ok( 0, $name );
887 =item owner_isnt( FILE, OWNER [, NAME] )
889 Ok if FILE's owner is not the same as OWNER. OWNER may be a text user name
890 or a numeric userid. Test skips on Dos and Mac OS <= 9. If the file
891 does not exist, the test fails.
893 The optional NAME parameter is the name of the test.
895 Contributed by Dylan Martin
901 my $filename = shift;
903 my $name = shift || "$filename belongs to $owner";
905 my $err = _dm_skeleton( $filename, $owner, $name );
906 return if( defined( $err ) && $err eq 'skip' );
907 return $err if defined($err);
909 my $owner_uid = _get_uid( $owner );
910 my $file_uid = ( stat $filename )[4];
912 return $Test->ok( 1, $name ) if $file_uid != $owner_uid;
914 $Test->diag( "File [$filename] belongs to $owner ($owner_uid)" );
915 return $Test->ok( 0, $name );
918 =item group_is( FILE , GROUP [, NAME] )
920 Ok if FILE's group is the same as GROUP. GROUP may be a text group name or
921 a numeric group id. Test skips on Dos, Mac OS <= 9 and any other operating
922 systems that do not support getpwuid() and friends. If the file does not
923 exist, the test fails.
925 The optional NAME parameter is the name of the test.
927 Contributed by Dylan Martin
933 my $filename = shift;
935 my $name = ( shift || "$filename belongs to group $group" );
937 my $err = _dm_skeleton( $filename, $group, $name );
938 return if( defined( $err ) && $err eq 'skip' );
939 return $err if defined($err);
941 my $group_gid = _get_gid( $group );
942 my $file_gid = ( stat $filename )[5];
944 unless( defined $file_gid )
946 $Test->skip("stat failed to return group gid for $filename");
950 return $Test->ok( 1, $name ) if $file_gid == $group_gid;
952 my $real_group = ( getgrgid $file_gid )[0];
953 unless( defined $real_group )
955 $Test->diag("File does not belong to $group");
956 return $Test->ok( 0, $name );
959 $Test->diag( "File [$filename] belongs to $real_group ($file_gid), ".
960 "not $group ($group_gid)" );
962 return $Test->ok( 0, $name );
965 =item group_isnt( FILE , GROUP [, NAME] )
967 Ok if FILE's group is not the same as GROUP. GROUP may be a text group name or
968 a numeric group id. Test skips on Dos, Mac OS <= 9 and any other operating
969 systems that do not support getpwuid() and friends. If the file does not
970 exist, the test fails.
972 The optional NAME parameter is the name of the test.
974 Contributed by Dylan Martin
980 my $filename = shift;
982 my $name = shift || "$filename does not belong to group $group";
984 my $err = _dm_skeleton( $filename, $group, $name );
985 return if( defined( $err ) && $err eq 'skip' );
986 return $err if defined($err);
988 my $group_gid = _get_gid( $group );
989 my $file_gid = ( stat $filename )[5];
991 unless( defined $file_gid )
993 $Test->skip("stat failed to return group gid for $filename");
997 return $Test->ok( 1, $name ) if $file_gid != $group_gid;
999 $Test->diag( "File [$filename] belongs to $group ($group_gid)" );
1000 return $Test->ok( 0, $name );
1008 if ($owner =~ /^\d+/)
1010 $owner_uid = $owner;
1011 $owner = ( getpwuid $owner )[0];
1015 $owner_uid = (getpwnam($owner))[2];
1026 if ($group =~ /^\d+/)
1028 $group_uid = $group;
1029 $group = ( getgrgid $group )[0];
1033 $group_uid = (getgrnam($group))[2];
1043 * check properties for other users (readable_by_root, for instance)
1047 * check number of links to file
1049 * check path parts (directory, filename, extension)
1056 =head1 SOURCE AVAILABILITY
1058 This source is part of a SourceForge project which always has the
1059 latest sources in CVS, as well as all of the previous releases.
1061 http://sourceforge.net/projects/brian-d-foy/
1063 If, for some reason, I disappear from the world, one of the other
1064 members of the project can shepherd this module appropriately.
1068 brian d foy, C<< <bdfoy@cpan.org> >>
1072 Shawn Sorichetti C<< <ssoriche@coloredblocks.net> >> provided
1075 Tom Metro helped me figure out some Windows capabilities.
1077 Dylan Martin added C<owner_is> and C<owner_isnt>
1081 Copyright 2002-2007, brian d foy, All Rights Reserved
1085 You may use, modify, and distribute this under the same terms
1090 "The quick brown fox jumped over the lazy dog";