Skip to content

Commit

Permalink
feat: console write using stream (#369)
Browse files Browse the repository at this point in the history
  • Loading branch information
SonyPradana committed Sep 3, 2024
1 parent 939e0f7 commit ea2d45d
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 0 deletions.
61 changes: 61 additions & 0 deletions src/System/Console/IO/ResourceOutputStream.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

declare(strict_types=1);

namespace System\Console\IO;

use System\Console\Interfaces\OutputStream;

/**
* inspire by Aydin Hassan <[email protected]>.
*
* @source https://github.com/php-school/terminal/blob/master/src/IO/OutputStream.php
*/
class ResourceOutputStream implements OutputStream
{
/**
* @var resource
*/
private $stream;

/**
* ResourceOutputStream constructor.
*
* @param resource $stream
*
* @throws \InvalidArgumentException if the stream is not a valid or writable resource
*/
public function __construct($stream = \STDOUT)
{
if (!is_resource($stream) || get_resource_type($stream) !== 'stream') {
throw new \InvalidArgumentException('Expected a valid stream');
}

$meta = stream_get_meta_data($stream);
if (str_contains($meta['mode'], 'r') && !str_contains($meta['mode'], '+')) {
throw new \InvalidArgumentException('Expected a writable stream');
}

$this->stream = $stream;
}

/**
* Writes the buffer to the stream.
*
* @throws \InvalidArgumentException if writing to the stream fails
*/
public function write(string $buffer): void
{
if (fwrite($this->stream, $buffer) === false) {
throw new \InvalidArgumentException('Failed to write to stream');
}
}

/**
* Checks whether the stream is interactive (connected to a terminal).
*/
public function isInteractive(): bool
{
return stream_isatty($this->stream);
}
}
17 changes: 17 additions & 0 deletions src/System/Console/Interfaces/OutputStream.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace System\Console\Interfaces;

/**
* inspire by Aydin Hassan <[email protected]>.
*
* @source https://github.com/php-school/terminal/blob/master/src/IO/OutputStream.php
*/
interface OutputStream
{
public function write(string $buffer): void;

public function isInteractive(): bool;
}
26 changes: 26 additions & 0 deletions src/System/Console/Style/Style.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace System\Console\Style;

use System\Console\Interfaces\OutputStream;
use System\Console\Interfaces\RuleInterface;
use System\Console\Style\Color\BackgroundColor;
use System\Console\Style\Color\ForegroundColor;
Expand Down Expand Up @@ -110,6 +111,8 @@ class Style
*/
private $ref = '';

private ?OutputStream $output_stream = null;

/**
* @param string|int $text set text to decorate
*/
Expand Down Expand Up @@ -354,6 +357,22 @@ public function yield()
return $this;
}

/**
* Write stream out.
*
* @param bool $new_line True if print with new line in end line
*
* @return void
*/
public function write($new_line = true)
{
$out = $this . ($new_line ? PHP_EOL : null);

if ($this->output_stream) {
$this->output_stream->write($out);
}
}

/**
* Clear curent line (original text is keep).
*/
Expand All @@ -370,6 +389,13 @@ public function replace(string $text, int $line = -1): void
$this->replaceLine($text, $line);
}

public function setOutputStream(OutputStream $resourceOutputStream): self
{
$this->output_stream = $resourceOutputStream;

return $this;
}

// style ------------------------------------------

/**
Expand Down
78 changes: 78 additions & 0 deletions tests/Console/IO/ResourceOutputStreamTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

declare(strict_types=1);

namespace System\Test\Console\IO;

use PHPUnit\Framework\TestCase;
use System\Console\IO\ResourceOutputStream;

class ResourceOutputStreamTest extends TestCase
{
/**
* Test constructing the ResourceOutputStream with valid stream.
*/
public function testConstructorWithValidStream(): void
{
$stream = fopen('php://memory', 'w+');
$outputStream = new ResourceOutputStream($stream);

$this->assertInstanceOf(ResourceOutputStream::class, $outputStream);
fclose($stream);
}

/**
* Test constructor throws exception for invalid stream.
*/
public function testConstructorThrowsForInvalidStream(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Expected a valid stream');

new ResourceOutputStream('invalid_stream');
}

/**
* Test constructor throws exception for non-writable stream.
*/
public function testConstructorThrowsForNonWritableStream(): void
{
$stream = fopen('php://memory', 'r');

$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Expected a writable stream');

new ResourceOutputStream($stream);

fclose($stream);
}

/**
* Test writing to a valid stream.
*/
public function testWriteToStream(): void
{
$stream = fopen('php://memory', 'w+');
$outputStream = new ResourceOutputStream($stream);

$outputStream->write('Hello, World!');

rewind($stream);
$this->assertEquals('Hello, World!', stream_get_contents($stream));

fclose($stream);
}

/**
* Test if the stream is interactive.
*/
public function testIsInteractive(): void
{
$stream = fopen('php://memory', 'w+');
$outputStream = new ResourceOutputStream($stream);

$this->assertFalse($outputStream->isInteractive());

fclose($stream);
}
}
18 changes: 18 additions & 0 deletions tests/Console/Style/StyleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
declare(strict_types=1);

use PHPUnit\Framework\TestCase;
use System\Console\IO\ResourceOutputStream;
use System\Console\Style\Colors;
use System\Console\Style\Style;

Expand Down Expand Up @@ -358,4 +359,21 @@ public function itOnlyPrintIfConditionTrue()

$this->assertEquals('', $text);
}

/**
* Test writing to a valid stream.
*/
public function testWriteToStream(): void
{
$stream = fopen('php://memory', 'w+');
$outputStream = new ResourceOutputStream($stream);
$style = new Style('');

$style->setOutputStream($outputStream);
$style->write(false);

rewind($stream);
$this->assertEquals('', stream_get_contents($stream));
fclose($stream);
}
}

0 comments on commit ea2d45d

Please sign in to comment.