<?php // ScopedStreamTest.php // Created: 2025-03-12 // Updated: 2025-03-12 declare(strict_types=1); use PHPUnit\Framework\TestCase; use PHPUnit\Framework\Attributes\{CoversClass,UsesClass}; use Index\Http\Streams\{ScopedStream,Stream}; #[CoversClass(ScopedStream::class)] #[UsesClass(Stream::class)] final class ScopedStreamTest extends TestCase { public function testScopedStream(): void { // why use test data when you can just use the source file $stream = Stream::createStreamFromFile(__FILE__, 'rb'); $stream->seek(5, SEEK_SET); // potentially account for Windows moments $offset = $stream->read(2) === "\r\n" ? 7 : 6; $length = 23; $scoped = new ScopedStream($stream, $offset, $length); $this->assertEquals('// ScopedStreamTest.php', (string)$scoped); $this->assertEquals($length, $scoped->getSize()); // rewind the underlying stream, scoped should should account for tell() < 0 $stream->rewind(); $read = $scoped->read(100); $this->assertEquals($length, strlen($read)); $this->assertEquals('// ScopedStreamTest.php', $read); // read beyond end + eof $stream->seek(-50, SEEK_END); $read = $scoped->read(100); $this->assertEmpty($read); $this->assertTrue($scoped->eof()); // SEEK_SET $scoped->seek(5); $this->assertEquals($offset + 5, $stream->tell()); $read = $scoped->read(5); $this->assertEquals($offset + 10, $stream->tell()); $this->assertEquals('opedS', $read); $scoped->rewind(); // calls seek(offset) internally $this->assertEquals($offset, $stream->tell()); // SEEK_CUR $scoped->seek(4, SEEK_CUR); $read = $scoped->read(4); $this->assertEquals('cope', $read); $read = $stream->read(4); $this->assertEquals('dStr', $read); $this->assertEquals(12, $scoped->tell()); $this->assertEquals($offset + 12, $stream->tell()); $scoped->seek(100, SEEK_CUR); $read = $scoped->read(100); $this->assertEmpty($read); $this->assertTrue($scoped->eof()); $this->assertFalse($stream->eof()); $scoped->seek(-100, SEEK_CUR); $read = $scoped->read(5); $this->assertEquals('// Sc', $read); // SEEK_END + eof behaviour $stream->seek(0, SEEK_END); $read = $stream->read(1); $this->assertTrue($scoped->eof()); $this->assertTrue($stream->eof()); $scoped->seek(0, SEEK_END); $this->assertFalse($scoped->eof()); $this->assertFalse($stream->eof()); // double wrap to test the alternate path in getContents $double = new ScopedStream($scoped, 5, 12); $double->seek(5, SEEK_CUR); $this->assertEquals('tre', $double->read(3)); $this->assertEquals('opedStreamTe', (string)$double); // now you're scoping with scopes $triple = ScopedStream::scopeTo($double, 2, 12); $this->assertInstanceOf(ScopedStream::class, $double->stream); $this->assertInstanceOf(Stream::class, $triple->stream); $this->assertEquals($offset + 7, $triple->offset); $this->assertEquals('edStreamTe', (string)$triple); $triple->rewind(); $this->assertEquals('edStreamTe', $triple->read(100)); $this->assertTrue($triple->eof()); } }