1b8851fccSafresh1use strict; 2b8851fccSafresh1 3b8851fccSafresh1BEGIN { 4b8851fccSafresh1 require Time::HiRes; 5b8851fccSafresh1 unless(&Time::HiRes::d_hires_stat) { 6b8851fccSafresh1 require Test::More; 7b8851fccSafresh1 Test::More::plan(skip_all => "no hi-res stat"); 8b8851fccSafresh1 } 9b8851fccSafresh1 if($^O =~ /\A(?:cygwin|MSWin)/) { 10b8851fccSafresh1 require Test::More; 11b8851fccSafresh1 Test::More::plan(skip_all => 12b8851fccSafresh1 "$^O file timestamps not reliable enough for stat test"); 13b8851fccSafresh1 } 14b8851fccSafresh1} 15b8851fccSafresh1 16014083a1Safresh1use Test::More tests => 43; 179f11ffb7Safresh1BEGIN { push @INC, '.' } 18b8851fccSafresh1use t::Watchdog; 19b8851fccSafresh1 20b8851fccSafresh1my @atime; 21b8851fccSafresh1my @mtime; 22b8851fccSafresh1for (1..5) { 23eac174f2Safresh1 note "cycle $_"; 24b8851fccSafresh1 Time::HiRes::sleep(rand(0.1) + 0.1); 259f11ffb7Safresh1 open(X, '>', $$); 26b8851fccSafresh1 print X $$; 27b8851fccSafresh1 close(X); 28b8851fccSafresh1 my($a, $stat, $b) = ("a", [Time::HiRes::stat($$)], "b"); 29eac174f2Safresh1 is $a, "a", "stat stack discipline"; 30eac174f2Safresh1 is $b, "b", "stat stack discipline"; 31eac174f2Safresh1 is ref($stat), "ARRAY", "stat returned array"; 32b8851fccSafresh1 push @mtime, $stat->[9]; 33b8851fccSafresh1 ($a, my $lstat, $b) = ("a", [Time::HiRes::lstat($$)], "b"); 34eac174f2Safresh1 is $a, "a", "lstat stack discipline"; 35eac174f2Safresh1 is $b, "b", "lstat stack discipline"; 36eac174f2Safresh1 SKIP: { 37eac174f2Safresh1 if($^O eq "haiku") { 38eac174f2Safresh1 skip "testing stat access time on Haiku", 2; 39eac174f2Safresh1 } 40*e0680481Safresh1 if ($ENV{PERL_FILE_ATIME_CHANGES}) { 41*e0680481Safresh1 # something else might access the file, changing atime 42*e0680481Safresh1 $lstat->[8] = $stat->[8]; 43*e0680481Safresh1 } 44eac174f2Safresh1 is_deeply $lstat, $stat, "write: stat and lstat returned same values"; 45b8851fccSafresh1 Time::HiRes::sleep(rand(0.1) + 0.1); 469f11ffb7Safresh1 open(X, '<', $$); 47b8851fccSafresh1 <X>; 48b8851fccSafresh1 close(X); 49b8851fccSafresh1 $stat = [Time::HiRes::stat($$)]; 50b8851fccSafresh1 push @atime, $stat->[8]; 51b8851fccSafresh1 $lstat = [Time::HiRes::lstat($$)]; 52eac174f2Safresh1 is_deeply $lstat, $stat, "read: stat and lstat returned same values"; 53eac174f2Safresh1 } 54b8851fccSafresh1} 55b8851fccSafresh11 while unlink $$; 56eac174f2Safresh1note ("mtime = @mtime"); 57eac174f2Safresh1note ("atime = @atime"); 58b8851fccSafresh1my $ai = 0; 59b8851fccSafresh1my $mi = 0; 60b8851fccSafresh1my $ss = 0; 61b8851fccSafresh1for (my $i = 1; $i < @atime; $i++) { 62b8851fccSafresh1 if ($atime[$i] >= $atime[$i-1]) { 63b8851fccSafresh1 $ai++; 64b8851fccSafresh1 } 65b8851fccSafresh1 if ($atime[$i] > int($atime[$i])) { 66b8851fccSafresh1 $ss++; 67b8851fccSafresh1 } 68b8851fccSafresh1} 69b8851fccSafresh1for (my $i = 1; $i < @mtime; $i++) { 70b8851fccSafresh1 if ($mtime[$i] >= $mtime[$i-1]) { 71b8851fccSafresh1 $mi++; 72b8851fccSafresh1 } 73b8851fccSafresh1 if ($mtime[$i] > int($mtime[$i])) { 74b8851fccSafresh1 $ss++; 75b8851fccSafresh1 } 76b8851fccSafresh1} 77eac174f2Safresh1note ("ai = $ai, mi = $mi, ss = $ss"); 78b8851fccSafresh1# Need at least 75% of monotonical increase and 79b8851fccSafresh1# 20% of subsecond results. Yes, this is guessing. 80b8851fccSafresh1SKIP: { 81b8851fccSafresh1 skip "no subsecond timestamps detected", 1 if $ss == 0; 82eac174f2Safresh1 skip "testing stat access on Haiku", 1 if $^O eq "haiku"; 83b8851fccSafresh1 ok $mi/(@mtime-1) >= 0.75 && $ai/(@atime-1) >= 0.75 && 84eac174f2Safresh1 $ss/(@mtime+@atime) >= 0.2, 85eac174f2Safresh1 "monotonical increase and subsecond results within expected parameters"; 86b8851fccSafresh1} 87b8851fccSafresh1 88b8851fccSafresh1my $targetname = "tgt$$"; 89b8851fccSafresh1my $linkname = "link$$"; 90b8851fccSafresh1SKIP: { 919f11ffb7Safresh1 open(X, '>', $targetname); 92b8851fccSafresh1 print X $$; 93b8851fccSafresh1 close(X); 94b8851fccSafresh1 eval { symlink $targetname, $linkname or die "can't symlink: $!"; }; 95b8851fccSafresh1 skip "can't symlink", 7 if $@ ne ""; 96eac174f2Safresh1 note "compare Time::HiRes::stat with ::lstat"; 97b8851fccSafresh1 my @tgt_stat = Time::HiRes::stat($targetname); 98b8851fccSafresh1 my @tgt_lstat = Time::HiRes::lstat($targetname); 99b8851fccSafresh1 my @lnk_stat = Time::HiRes::stat($linkname); 100b8851fccSafresh1 my @lnk_lstat = Time::HiRes::lstat($linkname); 101eac174f2Safresh1 my $exp = 13; 102eac174f2Safresh1 is scalar(@tgt_stat), $exp, "stat on target"; 103eac174f2Safresh1 is scalar(@tgt_lstat), $exp, "lstat on target"; 104eac174f2Safresh1 is scalar(@lnk_stat), $exp, "stat on link"; 105eac174f2Safresh1 is scalar(@lnk_lstat), $exp, "lstat on link"; 106eac174f2Safresh1 skip "testing stat access on Haiku", 3 if $^O eq "haiku"; 107eac174f2Safresh1 is_deeply \@tgt_stat, \@tgt_lstat, "stat and lstat return same values on target"; 108eac174f2Safresh1 is_deeply \@tgt_stat, \@lnk_stat, "stat and lstat return same values on link"; 109eac174f2Safresh1 isnt $lnk_lstat[2], $tgt_stat[2], 110eac174f2Safresh1 "target stat mode value differs from link lstat mode value"; 111b8851fccSafresh1} 112b8851fccSafresh11 while unlink $linkname; 113b8851fccSafresh11 while unlink $targetname; 114b8851fccSafresh1 115b8851fccSafresh11; 116