wiki.techinc.nl/tests/phpunit/unit/includes/libs/ParamValidator/Util/UploadedFileStreamTest.php
Timo Tijhof 128debb64b tests: Change use of AtEase to at operator
Follows-up I361fde0de7f4406bce6ed075ed397effa5be3359.

Per T253461, not mass-changing source code, but the use of the native
error silencing operator (@) is especially useful in tests because:

1. It requires any/all statements to be explicitly marked. The
   suppressWarnings/restoreWarnings sections encourage developers to
   be "lazy" and thus encapsulate more than needed if there are multiple
   ones near each other, which would ignore potentially important
   warnings in a test case, which is generally exactly the time when
   it is really useful to get warnings etc.

2. It avoids leaking state, for example in LBFactoryTest the
   assertFalse call would throw a PHPUnit assertion error (not meant
   to be caught by the local catch), and thus won't reach
   AtEase::restoreWarnings. This then causes later code to end up
   in a mismatching state and creates a confusing error_reporting
   state.

See .phpcs.xml, where the at operator is allowed for all test code.

Change-Id: I68d1725d685e0a7586468bc9de6dc29ceea31b8a
2022-02-24 21:29:51 +00:00

299 lines
8.1 KiB
PHP

<?php
namespace Wikimedia\ParamValidator\Util;
require_once __DIR__ . '/UploadedFileTestBase.php';
use RuntimeException;
use TypeError;
use Wikimedia\TestingAccessWrapper;
/**
* @covers Wikimedia\ParamValidator\Util\UploadedFileStream
*/
class UploadedFileStreamTest extends UploadedFileTestBase {
public function testConstruct_doesNotExist() {
$filename = $this->makeTemp( __FUNCTION__ );
unlink( $filename );
$this->assertFileNotExists( $filename, 'Non existence check' );
$this->expectException( RuntimeException::class );
$this->expectExceptionMessage( "Failed to open file:" );
$stream = new UploadedFileStream( $filename );
}
public function testConstruct_notReadable() {
if ( wfIsWindows() ) {
$this->markTestSkipped( "Skip test, since chmod does not work on windows" );
}
$filename = $this->makeTemp( __FUNCTION__ );
chmod( $filename, 0000 );
$this->expectException( RuntimeException::class );
$this->expectExceptionMessage( "Failed to open file:" );
$stream = new UploadedFileStream( $filename );
}
public function testCloseOnDestruct() {
$filename = $this->makeTemp( __FUNCTION__ );
$stream = new UploadedFileStream( $filename );
$fp = TestingAccessWrapper::newFromObject( $stream )->fp;
$this->assertSame( 'f', fread( $fp, 1 ), 'read check' );
unset( $stream );
try {
// PHP 7 raises warnings
$this->assertFalse( @fread( $fp, 1 ) );
} catch ( TypeError $ex ) {
// PHP 8 throws
}
}
public function testToString() {
$filename = $this->makeTemp( __FUNCTION__ );
$stream = new UploadedFileStream( $filename );
// Always starts at the start of the stream
$stream->seek( 3 );
$this->assertSame( 'foobar', (string)$stream );
// No exception when closed
$stream->close();
$this->assertSame( '', (string)$stream );
}
public function testToString_Error() {
if ( !class_exists( \Error::class ) ) {
$this->markTestSkipped( 'No PHP Error class' );
}
// ... Yeah
$filename = $this->makeTemp( __FUNCTION__ );
$stream = $this->getMockBuilder( UploadedFileStream::class )
->setConstructorArgs( [ $filename ] )
->onlyMethods( [ 'getContents' ] )
->getMock();
$stream->method( 'getContents' )->willReturnCallback( static function () {
throw new \Error( 'Bogus' );
} );
$this->assertSame( '', (string)$stream );
}
public function testClose() {
$filename = $this->makeTemp( __FUNCTION__ );
$stream = new UploadedFileStream( $filename );
$stream->close();
// Second call doesn't error
$stream->close();
}
public function testDetach() {
$filename = $this->makeTemp( __FUNCTION__ );
$stream = new UploadedFileStream( $filename );
// We got the file descriptor
$fp = $stream->detach();
$this->assertNotNull( $fp );
$this->assertSame( 'f', fread( $fp, 1 ) );
// Stream operations now fail.
try {
$stream->seek( 0 );
} catch ( \PHPUnit\Framework\AssertionFailedError $ex ) {
throw $ex;
} catch ( RuntimeException $ex ) {
}
// Stream close doesn't affect the file descriptor
$stream->close();
$this->assertSame( 'o', fread( $fp, 1 ) );
// Stream destruction doesn't affect the file descriptor
unset( $stream );
$this->assertSame( 'o', fread( $fp, 1 ) );
// On a closed stream, we don't get a file descriptor
$stream = new UploadedFileStream( $filename );
$stream->close();
$this->assertNull( $stream->detach() );
}
public function testGetSize() {
$filename = $this->makeTemp( __FUNCTION__ );
$stream = new UploadedFileStream( $filename );
file_put_contents( $filename, 'foobarbaz' );
$this->assertSame( 9, $stream->getSize() );
// Cached
file_put_contents( $filename, 'baz' );
clearstatcache();
$this->assertSame( 3, stat( $filename )['size'], 'size check' );
$this->assertSame( 9, $stream->getSize() );
// No error if closed
$stream = new UploadedFileStream( $filename );
$stream->close();
$this->assertSame( null, $stream->getSize() );
// No error even if the fd goes bad
$stream = new UploadedFileStream( $filename );
fclose( TestingAccessWrapper::newFromObject( $stream )->fp );
$this->assertSame( null, $stream->getSize() );
}
public function testSeekTell() {
$filename = $this->makeTemp( __FUNCTION__ );
$stream = new UploadedFileStream( $filename );
$stream->seek( 2 );
$this->assertSame( 2, $stream->tell() );
$stream->seek( 2, SEEK_CUR );
$this->assertSame( 4, $stream->tell() );
$stream->seek( -5, SEEK_END );
$this->assertSame( 1, $stream->tell() );
$stream->read( 2 );
$this->assertSame( 3, $stream->tell() );
$stream->close();
try {
$stream->seek( 0 );
} catch ( \PHPUnit\Framework\AssertionFailedError $ex ) {
throw $ex;
} catch ( RuntimeException $ex ) {
}
try {
$stream->tell();
} catch ( \PHPUnit\Framework\AssertionFailedError $ex ) {
throw $ex;
} catch ( RuntimeException $ex ) {
}
}
public function testEof() {
$filename = $this->makeTemp( __FUNCTION__ );
$stream = new UploadedFileStream( $filename );
$this->assertFalse( $stream->eof() );
$stream->getContents();
$this->assertTrue( $stream->eof() );
$stream->seek( -1, SEEK_END );
$this->assertFalse( $stream->eof() );
// No error if closed
$stream = new UploadedFileStream( $filename );
$stream->close();
$this->assertTrue( $stream->eof() );
// No error even if the fd goes bad
$stream = new UploadedFileStream( $filename );
fclose( TestingAccessWrapper::newFromObject( $stream )->fp );
$this->assertIsBool( $stream->eof() );
}
public function testIsFuncs() {
$filename = $this->makeTemp( __FUNCTION__ );
$stream = new UploadedFileStream( $filename );
$this->assertTrue( $stream->isSeekable() );
$this->assertTrue( $stream->isReadable() );
$this->assertFalse( $stream->isWritable() );
$stream->close();
$this->assertFalse( $stream->isSeekable() );
$this->assertFalse( $stream->isReadable() );
$this->assertFalse( $stream->isWritable() );
}
public function testRewind() {
$filename = $this->makeTemp( __FUNCTION__ );
$stream = new UploadedFileStream( $filename );
$stream->seek( 2 );
$this->assertSame( 2, $stream->tell() );
$stream->rewind();
$this->assertSame( 0, $stream->tell() );
$stream->close();
try {
$stream->rewind();
} catch ( \PHPUnit\Framework\AssertionFailedError $ex ) {
throw $ex;
} catch ( RuntimeException $ex ) {
}
}
public function testWrite() {
$filename = $this->makeTemp( __FUNCTION__ );
$stream = new UploadedFileStream( $filename );
try {
$stream->write( 'foo' );
} catch ( \PHPUnit\Framework\AssertionFailedError $ex ) {
throw $ex;
} catch ( RuntimeException $ex ) {
}
}
public function testRead() {
$filename = $this->makeTemp( __FUNCTION__ );
$stream = new UploadedFileStream( $filename );
$this->assertSame( 'foo', $stream->read( 3 ) );
$this->assertSame( 'bar', $stream->read( 10 ) );
$this->assertSame( '', $stream->read( 10 ) );
$stream->rewind();
$this->assertSame( 'foobar', $stream->read( 10 ) );
$stream->close();
try {
$stream->read( 1 );
} catch ( \PHPUnit\Framework\AssertionFailedError $ex ) {
throw $ex;
} catch ( RuntimeException $ex ) {
}
}
public function testGetContents() {
$filename = $this->makeTemp( __FUNCTION__ );
$stream = new UploadedFileStream( $filename );
$this->assertSame( 'foobar', $stream->getContents() );
$this->assertSame( '', $stream->getContents() );
$stream->seek( 3 );
$this->assertSame( 'bar', $stream->getContents() );
$stream->close();
try {
$stream->getContents();
} catch ( \PHPUnit\Framework\AssertionFailedError $ex ) {
throw $ex;
} catch ( RuntimeException $ex ) {
}
}
public function testGetMetadata() {
// Whatever
$filename = $this->makeTemp( __FUNCTION__ );
$fp = fopen( $filename, 'r' );
$expect = stream_get_meta_data( $fp );
fclose( $fp );
$stream = new UploadedFileStream( $filename );
$this->assertSame( $expect, $stream->getMetadata() );
foreach ( $expect as $k => $v ) {
$this->assertSame( $v, $stream->getMetadata( $k ) );
}
$this->assertNull( $stream->getMetadata( 'bogus' ) );
$stream->close();
try {
$stream->getMetadata();
} catch ( \PHPUnit\Framework\AssertionFailedError $ex ) {
throw $ex;
} catch ( RuntimeException $ex ) {
}
}
}