~ancarda/psr7-string-stream

0293ef3ccf6bcadfe67eefbbf7b9b27503344ee2 — Mark Dain 1 year, 9 months ago 836535d 1.1
Fix write() to not assume appending is correct

This commit rewrites the `write()' function to check if it's at EOF
before appending. Now the function is able to prepend if at SOF, and
can also overwrite data in the middle of a stream.
2 files changed, 60 insertions(+), 4 deletions(-)

M src/StringStream.php
M tests/StringStreamTest.php
M src/StringStream.php => src/StringStream.php +23 -2
@@ 175,8 175,29 @@ class StringStream implements StreamInterface
     */
    public function write($string): int
    {
        $this->data   .= $string;
        $this->length += strlen($string);
        // If we're at the end of the data, we can just append.
        if ($this->eof()) {
            $this->length += strlen($string);
            $this->data   .= $string;
            return strlen($string);
        }

        // If we're at the start of the data, we can just prepend.
        if ($this->pointer === 0) {
            $this->length += strlen($string);
            $this->data   = $string . $this->data;
            return strlen($string);
        }

        // If we're purely overwriting, we can do that with substr.
        // If we have more to write than we can fit, we'll just substr the start and then concatenate the rest.
        $this->data =
            substr($this->data, 0, $this->pointer) .
            $string .
            substr($this->data, $this->pointer + strlen($string));

        // Since we can do both overwriting and appending here, we'll just recalculate:
        $this->length = strlen($this->data);

        return strlen($string);
    }

M tests/StringStreamTest.php => tests/StringStreamTest.php +37 -2
@@ 72,13 72,48 @@ class StringStreamTest extends TestCase
    public function testWriting(): void
    {
        $stringStream = new StringStream('hello world');
        $fullString = 'hello world, isn\'t it a lovely day';

        static::assertTrue($stringStream->isWritable());

        // Can we write at the end of a string?
        $stringStream->seek(0, SEEK_END);
        $bytesWritten = $stringStream->write(', isn\'t it a lovely day');
        $fullString = 'hello world, isn\'t it a lovely day';
        static::assertSame(strlen($fullString), $stringStream->getSize());
        static::assertSame($fullString, (string) $stringStream);
        static::assertSame(strlen(', isn\'t it a lovely day'), $bytesWritten);

        // Can we write at the start of a string?
        $stringStream->seek(0);
        $bytesWritten = $stringStream->write('Oh! ');
        $fullString = 'Oh! hello world, isn\'t it a lovely day';
        static::assertSame(strlen($fullString), $stringStream->getSize());
        static::assertSame($fullString, (string) $stringStream);
        static::assertSame(4, $bytesWritten);

        // Can we write in the middle of the string to fix the capitalization?
        $stringStream->seek(4);
        $bytesWritten = $stringStream->write('H');
        $fullString = 'Oh! Hello world, isn\'t it a lovely day';
        static::assertSame(strlen($fullString), $stringStream->getSize());
        static::assertSame($fullString, (string) $stringStream);
        static::assertSame(1, $bytesWritten);

        // Can we make a multi-word replacement? We'll replace 2 bytes with 0x7F (DEL) which in a
        // real world application could be filtered out as deleted bytes.
        $stringStream->seek(4);
        $bytesWritten = $stringStream->write('Hey' . chr(127) . chr(127));
        $fullString = 'Oh! Hey' . chr(127) . chr(127) . ' world, isn\'t it a lovely day';
        static::assertSame(strlen($fullString), $stringStream->getSize());
        static::assertSame($fullString, (string) $stringStream);
        static::assertSame(5, $bytesWritten);

        // Finally, can we replace and append?
        $stringStream->seek(35);
        $bytesWritten = $stringStream->write('evening?');
        $fullString = 'Oh! Hey' . chr(127) . chr(127) . ' world, isn\'t it a lovely evening?';
        static::assertSame(strlen($fullString), $stringStream->getSize());
        static::assertSame($fullString, (string) $stringStream);
        static::assertSame(8, $bytesWritten);
    }

    public function testMiscFunctions(): void