For the last 20 minutes I've been scratching my head about why one of my unit tests was failing. It was for the truncate method of little file class. The code for both the offending method and the unit test (and the unit test's setUp method) are listed below. Can any of you see what the problem is? Well, apparently the result of certain file related functions are cached by PHP and [man]filesize[/man] is one of them. This means that if I truncate a file I then have to clear this cache with [man]clearstatcache[/man] before I can get the correct size of the file. It's quite clearly documented in the [man]filesize[/man] manual page, I was just surprised I've managed to play with PHP for this long without coming across this before. Is this news to anyone else?
The truncate method
/**{{{truncate
*
* Truncate the file
*/
function truncate( $length=0 ) {
return ftruncate($this->fh, $length) && rewind($this->fh);
}//}}}
The unit test and associated setUp method
/**{{{setUp
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*
* @access protected
*/
protected function setUp() {
// Create a file with some data in it
$filename = '/tmp/FileTest_data';
$fh = fopen($filename, 'w+');
$data = <<<END_TEXT
I am a lovely random line
No you\'re not, you make perfect toenails
I think he means his order is random
You\'re all wrong, regardless of your meaning, we can only ever be sudo-random
Wow man, that\'s deep
Like, my head feels super sudo-random at the moment duuuude
Awesome
END_TEXT;
fwrite($fh, $data);
fclose($fh);
// Create a readonly File object
$this->data_filename = $filename;
$lines = explode("\n", $data);
$this->data_firstline = $lines[0];
$this->datafile = new File( $filename );
// Create an empty writable File object
$filename = '/tmp/FileTest_put';
$this->put_filename = $filename;
$this->putfile = new File( $filename, 'w+');
}//}}}
/**{{{testTruncate
* Test the truncate method. Be sure that readonly files cannot be truncated and that writable
* files can and are when the truncate method is called
*/
public function testTruncate() {
// Test that readonly files cannot be truncated
$this->assertFalse($this->datafile->truncate(), "Should fail on readonly files");
$this->assertNotEquals( filesize($this->data_filename), 0, "You can't truncate readonly files");
// Test that writable files can be truncated
$fh = fopen($this->put_filename, 'w+');
fwrite($fh, 'blah blah blah');
fclose($fh);
$this->assertNotEquals( filesize($this->put_filename), 0, "The file has some data in to start with");
$this->assertTrue( $this->putfile->truncate(), "The truncate method reports success" );
// clear the stat cache so that filesize returns the expected result
$this->assertEquals( filesize($this->put_filename), 0, "The file has no data in afterwards");
}//}}}