From 8ebcbb73caa9fea5caf0012831758c9e9591ac3d Mon Sep 17 00:00:00 2001 From: Pavel Stejskal Date: Wed, 22 Feb 2023 09:45:47 +0100 Subject: [PATCH] Fixed StreamWrapper invalid schema --- CHANGELOG.md | 4 + phpunit.xml | 3 +- src/StreamWrapper.php | 16 ++-- tests/CachingStreamTest.php | 3 + tests/FileTest.php | 3 + tests/StreamTest.php | 3 + tests/StreamWrapperTest.php | 150 ++++++++++++++++++++++++++++++++++++ tests/TempFileTest.php | 3 + 8 files changed, 176 insertions(+), 9 deletions(-) create mode 100644 tests/StreamWrapperTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 21fd64c..a6d6621 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes will be documented in this file. Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles. +## [0.2.1] 2022-02-22 +### Fixed +- Fixed StreamWrapper invalid schema + ## [0.2.0] 2022-02-22 ### Changed - Refactor Stream to implement PSR-7 StreamInterface diff --git a/phpunit.xml b/phpunit.xml index 17b072f..51a44d6 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,8 +1,9 @@ diff --git a/src/StreamWrapper.php b/src/StreamWrapper.php index 97a1a10..b492d8f 100644 --- a/src/StreamWrapper.php +++ b/src/StreamWrapper.php @@ -12,7 +12,7 @@ final class StreamWrapper { /** @var resource */ - public $resource; + public $context; private StreamInterface $stream; private string $mode; @@ -35,7 +35,7 @@ public static function from(StreamInterface $stream) throw new InvalidArgumentException('The stream must be readable, writable, or both.'); } - $resource = fopen('digitalcz_streams://stream', $mode, false, self::createStreamContext($stream)); + $resource = fopen('digitalcz-streams://stream', $mode, false, self::createStreamContext($stream)); if (!is_resource($resource)) { throw new StreamException('Unable to create StreamWrapper'); @@ -52,7 +52,7 @@ public static function from(StreamInterface $stream) public static function createStreamContext(StreamInterface $stream) { return stream_context_create([ - 'digitalcz_streams' => ['stream' => $stream], + 'digitalcz-streams' => ['stream' => $stream], ]); } @@ -61,22 +61,22 @@ public static function createStreamContext(StreamInterface $stream) */ public static function register(): void { - if (!in_array('digitalcz_streams', stream_get_wrappers(), true)) { - stream_wrapper_register('digitalcz_streams', self::class); + if (!in_array('digitalcz-streams', stream_get_wrappers(), true)) { + stream_wrapper_register('digitalcz-streams', self::class); } } // phpcs:ignore public function stream_open(string $path, string $mode, int $options, ?string &$opened_path = null): bool { - $options = stream_context_get_options($this->resource); + $options = stream_context_get_options($this->context); - if (!isset($options['digitalcz_streams']['stream'])) { + if (!isset($options['digitalcz-streams']['stream'])) { return false; } $this->mode = $mode; - $this->stream = $options['digitalcz_streams']['stream']; + $this->stream = $options['digitalcz-streams']['stream']; return true; } diff --git a/tests/CachingStreamTest.php b/tests/CachingStreamTest.php index 1954395..2c2fd82 100644 --- a/tests/CachingStreamTest.php +++ b/tests/CachingStreamTest.php @@ -6,6 +6,9 @@ use PHPUnit\Framework\TestCase; +/** + * @covers \DigitalCz\Streams\CachingStream + */ class CachingStreamTest extends TestCase { public function testUseOriginalIfAvailable(): void diff --git a/tests/FileTest.php b/tests/FileTest.php index e35cc08..9f45aa6 100644 --- a/tests/FileTest.php +++ b/tests/FileTest.php @@ -6,6 +6,9 @@ use PHPUnit\Framework\TestCase; +/** + * @covers \DigitalCz\Streams\File + */ class FileTest extends TestCase { public function testOpenNonExistentFile(): void diff --git a/tests/StreamTest.php b/tests/StreamTest.php index 7cfae47..6822ab8 100644 --- a/tests/StreamTest.php +++ b/tests/StreamTest.php @@ -9,6 +9,9 @@ use LogicException; use Throwable; +/** + * @covers \DigitalCz\Streams\Stream + */ class StreamTest extends StreamIntegrationTest { public function testConstructorThrowsExceptionOnInvalidArgument(): void diff --git a/tests/StreamWrapperTest.php b/tests/StreamWrapperTest.php new file mode 100644 index 0000000..ca3ceae --- /dev/null +++ b/tests/StreamWrapperTest.php @@ -0,0 +1,150 @@ + 0, + 'ino' => 0, + 'mode' => 33206, + 'nlink' => 0, + 'uid' => 0, + 'gid' => 0, + 'rdev' => 0, + 'size' => 6, + 'atime' => 0, + 'mtime' => 0, + 'ctime' => 0, + 'blksize' => $stBlksize, + 'blocks' => $stBlksize, + 0 => 0, + 1 => 0, + 2 => 33206, + 3 => 0, + 4 => 0, + 5 => 0, + 6 => 0, + 7 => 6, + 8 => 0, + 9 => 0, + 10 => 0, + 11 => $stBlksize, + 12 => $stBlksize, + ], fstat($handle)); + + self::assertTrue(fclose($handle)); + self::assertSame('foobar', (string) $stream); + } + + public function testStreamContext(): void + { + StreamWrapper::register(); + $stream = Stream::from('foo'); + + self::assertSame( + 'foo', + file_get_contents('digitalcz-streams://stream', false, StreamWrapper::createStreamContext($stream)), + ); + } + + public function testStreamCast(): void + { + $streams = [ + StreamWrapper::from(Stream::from('foo')), + StreamWrapper::from(Stream::from('bar')), + ]; + $write = null; + $except = null; + self::assertIsInt(stream_select($streams, $write, $except, 0)); + } + + public function testValidatesStream(): void + { + $stream = $this->createMock(StreamInterface::class); + $stream->expects(self::once()) + ->method('isReadable') + ->willReturn(false); + $stream->expects(self::once()) + ->method('isWritable') + ->willReturn(false); + + $this->expectException(InvalidArgumentException::class); + StreamWrapper::from($stream); + } + + public function testCanOpenReadonlyStream(): void + { + $stream = $this->createMock(StreamInterface::class); + $stream->expects(self::once()) + ->method('isReadable') + ->willReturn(false); + $stream->expects(self::once()) + ->method('isWritable') + ->willReturn(true); + $r = StreamWrapper::from($stream); + self::assertIsResource($r); + fclose($r); + } + + public function testUrlStat(): void + { + StreamWrapper::register(); + + $stBlksize = defined('PHP_WINDOWS_VERSION_BUILD') ? -1 : 0; + + self::assertEquals( + [ + 'dev' => 0, + 'ino' => 0, + 'mode' => 0, + 'nlink' => 0, + 'uid' => 0, + 'gid' => 0, + 'rdev' => 0, + 'size' => 0, + 'atime' => 0, + 'mtime' => 0, + 'ctime' => 0, + 'blksize' => $stBlksize, + 'blocks' => $stBlksize, + 0 => 0, + 1 => 0, + 2 => 0, + 3 => 0, + 4 => 0, + 5 => 0, + 6 => 0, + 7 => 0, + 8 => 0, + 9 => 0, + 10 => 0, + 11 => $stBlksize, + 12 => $stBlksize, + ], + stat('digitalcz-streams://stream'), + ); + } +} diff --git a/tests/TempFileTest.php b/tests/TempFileTest.php index a061b61..42c872d 100644 --- a/tests/TempFileTest.php +++ b/tests/TempFileTest.php @@ -6,6 +6,9 @@ use PHPUnit\Framework\TestCase; +/** + * @covers \DigitalCz\Streams\TempFile + */ class TempFileTest extends TestCase { public function testCreateAndDelete(): void