diff --git a/UnitTestContrib/test/unit/FileClassTests.pm b/UnitTestContrib/test/unit/FileClassTests.pm index 6c4d2863bf..c84f257ae3 100644 --- a/UnitTestContrib/test/unit/FileClassTests.pm +++ b/UnitTestContrib/test/unit/FileClassTests.pm @@ -5,18 +5,27 @@ use Try::Tiny; use Foswiki::File; -use File::Temp qw(tempfile); +use File::Temp qw(tempfile tempdir); use Foswiki::Class; extends qw(FoswikiTestCase); has tempFile => ( - is => 'rw', + is => 'ro', lazy => 1, clearer => 1, builder => 'prepareTempFile', ); +# tempSubDir allows for a temporary subdir in tempDir where it would be +# guaranteed that it is empty. +has tempSubDir => ( + is => 'ro', + lazy => 1, + clearer => 1, + builder => 'prepareTempSubDir', +); + around set_up => sub { my $orig = shift; my $this = shift; @@ -24,6 +33,7 @@ around set_up => sub { $orig->( $this, @_ ); $this->clear_tempFile; + $this->clear_tempSubDir; }; sub prepareTempFile { @@ -37,6 +47,17 @@ sub prepareTempFile { return $fname; } +sub prepareTempSubDir { + my $this = shift; + + my $tmpSubDir = File::Temp->newdir( + DIR => $this->tempDir, + TEMPLATE => $this->testSuite . '.XXXXXX', + ); + + return $tmpSubDir; +} + sub test_read { my $this = shift; @@ -81,4 +102,64 @@ EOT $this->assert_equals( $testContent, $fobj->content ); } +sub test_autoCreate { + my $this = shift; + + my $newFileName = File::Spec->catfile( $this->tempSubDir, "ANewFile" ); + + my $fobj = $this->create( + 'Foswiki::File', + path => $newFileName, + autoCreate => 1, + ); + + $this->assert_equals( $fobj->stat, undef, "" ); + + $fobj->content("Anything"); + $fobj->flush; + + $this->assert( defined $fobj->stat, + "stat attribute must be defined after flush" ); + + $this->assert( -e $newFileName, "can't find auto-created file" ); +} + +sub test_statOnUnreadable { + my $this = shift; + + my $oldMask = umask(0477); + + my $unreadFile = File::Spec->catfile( $this->tempSubDir, "UnreadableFile" ); + + $this->assert( + open( my $fh, ">", $unreadFile ), + "can't create " . $unreadFile . ": " . $! + ); + close $fh; + + umask($oldMask); + + try { + $this->assert( + !-r $unreadFile, + "test code failed: cannot create unreadable file in " . $unreadFile + ); + + my $fobj = $this->create( "Foswiki::File", path => $unreadFile, ); + $fobj->stat; + + $this->assert( 0, + "File object has been created instead of raising an exception" ); + } + catch { + my $e = Foswiki::Exception::Fatal->transmute( $_, 0 ); + $this->assert( $e->isa('Foswiki::Exception::FileOp'), + "wrong exception " + . ref($e) + . ": Foswiki::Exception::FileOp is excepted" ); + $this->assert_matches( 'Failed to stat .*: don\'t have read access to ', + $e->stringify, "wrong exception text" ); + }; +} + 1; diff --git a/core/lib/Foswiki/File.pm b/core/lib/Foswiki/File.pm index 9434e9061d..b89db0a9a5 100644 --- a/core/lib/Foswiki/File.pm +++ b/core/lib/Foswiki/File.pm @@ -278,6 +278,7 @@ sub flush { or $this->throwFileOp( op => "write", ); $this->modified(0); + $this->clear_stat; } catch { $this->exception( Foswiki::Exception::Fatal->transmute( $_, 0 ) ); @@ -319,12 +320,12 @@ sub prepareStat { my $path = $this->path; - unless ( -r $path ) { + if ( ( -e $path || !$this->autoCreate ) && !-r $path ) { $this->exception( $this->_createException( exception => 'Foswiki::Exception::FileOp', - text => "Don't have read access to " . $path . ", cannot stat", - op => "stat", + text => "don't have read access to " . $path, + op => "stat", ) ); return undef;