diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 7d9d61c..7eaf176 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -1,73 +1,36 @@
-name: "Continuous Integration"
-
-on:
- pull_request:
- push:
-
+name: CI
+on: [ push, pull_request ]
jobs:
- phpunit:
- name: "Unit Tests"
- runs-on: ubuntu-latest
+ ci:
+ name: "CI"
+ runs-on: ${{ matrix.operating-system }}
+ strategy:
+ matrix:
+ operating-system: [ ubuntu-latest, windows-latest, macos-latest ]
+ php-version: [ 8.3 ]
steps:
- - name: "Checkout"
- uses: actions/checkout@v3
-
- - name: "Install PHP"
- uses: shivammathur/setup-php@v2
- with:
- coverage: "pcov"
- php-version: "8.1"
- ini-values: memory_limit=-1
- extensions: sodium, fileinfo, redis
-
- - name: "Install dependencies"
- uses: ramsey/composer-install@v2
- with:
- dependency-versions: "locked"
-
- - name: "Run PHPUnit"
- run: composer test
- psalm:
- name: "Static Analysis"
- runs-on: ubuntu-latest
- steps:
+ # --------- Setup steps ---------
- name: "Checkout"
uses: actions/checkout@v3
- - name: "Install PHP"
+ - name: "Setup PHP"
uses: shivammathur/setup-php@v2
with:
- php-version: "8.1"
+ coverage: "pcov"
+ php-version: "${{ matrix.php-version }}"
ini-values: memory_limit=-1
- extensions: sodium, fileinfo, redis
+ extensions: pcov, xdebug
- name: "Install dependencies"
uses: ramsey/composer-install@v2
- with:
- dependency-versions: "locked"
-
- - name: "Run Psalm"
- run: composer psalm
-
- phpcs:
- name: "Code Style"
- runs-on: ubuntu-latest
- steps:
- - name: "Checkout"
- uses: actions/checkout@v3
- - name: "Install PHP"
- uses: shivammathur/setup-php@v2
- with:
- php-version: "8.1"
- ini-values: memory_limit=-1
- extensions: sodium, fileinfo, redis
+ # --------- Run steps ---------
+ - name: "Unit Tests"
+ run: "composer test"
- - name: "Install dependencies"
- uses: ramsey/composer-install@v2
- with:
- dependency-versions: "locked"
+ - name: "Coding Style"
+ run: "composer cs-fix"
- - name: "Run PHPCS"
- run: composer cs-check
+ - name: "Static code analysis"
+ run: "composer psalm"
diff --git a/docs/README.md b/docs/README.md
index dc523b6..170e0fe 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -157,14 +157,15 @@ if ($this->hasOption('queue')) {
## Writing output
-All helper methods from the Symfony `SymfonyStyle` class are available in the command class.
+The package provides a handy Console style that you can use to write output to the console:
+
```php
-$this->title('Lorem ipsum dolor sit amet');
-$this->section('Adding a new user');
-$this->text('Lorem ipsum dolor sit amet, consectetur adipiscing elit.');
-//And so on...
+$this->output->comment('This is a comment');
+$this->output->success('This is a success message');
+$this->output->error('This is an error message');
+$this->output->warning('This is an info message');
+$this->output->note('This is an info message');
+$this->output->info('This is an info message');
+$this->output->caution('This is a line message');
```
-
-You can find the full list of available methods in Symfony's
-documentation: [Helper methods](https://symfony.com/doc/current/console/style.html#helper-methods).
diff --git a/docs/output-style.png b/docs/output-style.png
new file mode 100644
index 0000000..702a2c6
Binary files /dev/null and b/docs/output-style.png differ
diff --git a/src/Command.php b/src/Command.php
index fa0fcc2..eb8fa98 100644
--- a/src/Command.php
+++ b/src/Command.php
@@ -4,12 +4,12 @@
namespace Symblaze\Console;
+use Symblaze\Console\IO\Helper\InputTrait;
+use Symblaze\Console\IO\Helper\OutputTrait;
+use Symblaze\Console\IO\Output;
use Symfony\Component\Console\Command\Command as SymfonyCommand;
-use Symfony\Component\Console\Helper\ProgressBar;
-use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-use Symfony\Component\Console\Style\SymfonyStyle;
/**
* @psalm-api - This file is part of the symblaze/console package.
@@ -18,16 +18,11 @@
*/
abstract class Command extends SymfonyCommand
{
- protected InputInterface $input;
- protected SymfonyStyle $output;
+ use InputTrait;
+ use OutputTrait;
- private const VERBOSITY_MAP = [
- 'v' => OutputInterface::VERBOSITY_VERBOSE,
- 'vv' => OutputInterface::VERBOSITY_VERY_VERBOSE,
- 'vvv' => OutputInterface::VERBOSITY_DEBUG,
- 'quiet' => OutputInterface::VERBOSITY_QUIET,
- 'normal' => OutputInterface::VERBOSITY_NORMAL,
- ];
+ protected InputInterface $input;
+ protected Output $output;
protected function configure(): void
{
@@ -40,185 +35,33 @@ protected function configure(): void
public function run(InputInterface $input, OutputInterface $output): int
{
- $this->input = $input;
- $this->output = StyleFactory::create($input, $output);
+ $this->setInput($input);
+ $this->setOutput(new Output($input, $output));
return parent::run($input, $output);
}
- /**
- * Determine if the given argument is present.
- */
- protected function hasArgument($name): bool
- {
- return $this->input->hasArgument($name) && ! is_null($this->argument($name));
- }
-
- /**
- * Determine if the given option is present.
- */
- protected function hasOption($name): bool
- {
- return $this->input->hasOption($name) && ! is_null($this->option($name));
- }
-
- protected function option(string $key): bool|array|string|null
- {
- return $this->input->getOption($key);
- }
-
- protected function options(): array
- {
- return $this->input->getOptions();
- }
-
- /**
- * Get the value of a command argument.
- */
- protected function argument(string $key): bool|array|string|null
- {
- return $this->input->getArgument($key);
- }
-
- /**
- * Get all the arguments passed to the command.
- */
- protected function arguments(): array
- {
- return $this->input->getArguments();
- }
-
- /**
- * Writes a message to the output and adds a newline at the end.
- */
- protected function line(string $message, ?string $style = null, string|int $verbosity = 'normal'): void
- {
- $styled = $style ? "<$style>$message$style>" : $message;
-
- $this->output->writeln($styled, $this->parseVerbosity($verbosity));
- }
-
- protected function info(string|array $message): void
- {
- $this->output->info($message);
- }
-
- protected function comment(string|array $message): void
- {
- $this->output->comment($message);
- }
-
- protected function question(string|array $message): void
- {
- $this->line($message, 'question');
- }
-
- protected function error(string|array $message): void
- {
- $this->output->error($message);
- }
-
- protected function warning(string|array $message): void
- {
- $this->output->warning($message);
- }
-
- protected function success(string|array $message): void
- {
- $this->output->success($message);
- }
-
- protected function title(string $message): void
+ public function getInput(): InputInterface
{
- $this->output->title($message);
+ return $this->input;
}
- protected function section(string $message): void
+ public function setInput(InputInterface $input): static
{
- $this->output->section($message);
- }
-
- protected function text(string|array $message): void
- {
- $this->output->text($message);
- }
-
- protected function listing(array $elements): void
- {
- $this->output->listing($elements);
- }
-
- protected function table(array $headers, array $rows): void
- {
- $this->output->table($headers, $rows);
- }
-
- protected function horizontalTable(array $headers, array $rows): void
- {
- $this->output->horizontalTable($headers, $rows);
- }
-
- protected function definitionList(string|array|TableSeparator ...$list): void
- {
- $this->output->definitionList(...$list);
- }
-
- protected function note(string|array $message): void
- {
- $this->output->note($message);
- }
-
- protected function caution(string|array $message): void
- {
- $this->output->caution($message);
- }
-
- protected function ask(string $question, ?string $default = null, ?callable $validator = null): mixed
- {
- return $this->output->ask($question, $default, $validator);
- }
-
- protected function askHidden(string $question, ?callable $validator = null): mixed
- {
- return $this->output->askHidden($question, $validator);
- }
-
- protected function confirm(string $question, bool $default = true): bool
- {
- return $this->output->confirm($question, $default);
- }
-
- protected function choice(string $question, array $choices, mixed $default = null, bool $multiSelect = false): mixed
- {
- return $this->output->choice($question, $choices, $default, $multiSelect);
- }
-
- protected function progressStart(int $max = 0): void
- {
- $this->output->progressStart($max);
- }
-
- protected function progressAdvance(int $step = 1): void
- {
- $this->output->progressAdvance($step);
- }
+ $this->input = $input;
- protected function progressFinish(): void
- {
- $this->output->progressFinish();
+ return $this;
}
- protected function createProgressBar(int $max = 0): ProgressBar
+ public function getOutput(): Output
{
- return $this->output->createProgressBar($max);
+ return $this->output;
}
- private function parseVerbosity(int|string $level): int
+ public function setOutput(Output $output): static
{
- if (is_int($level)) {
- return $level;
- }
+ $this->output = $output;
- return self::VERBOSITY_MAP[$level] ?? OutputInterface::VERBOSITY_NORMAL;
+ return $this;
}
}
diff --git a/src/IO/Helper/InputTrait.php b/src/IO/Helper/InputTrait.php
new file mode 100644
index 0000000..3bc9d08
--- /dev/null
+++ b/src/IO/Helper/InputTrait.php
@@ -0,0 +1,55 @@
+input->getArgument($key);
+ }
+
+ protected function option(string $key): bool|array|string|null
+ {
+ return $this->input->getOption($key);
+ }
+
+ protected function options(): array
+ {
+ return $this->input->getOptions();
+ }
+
+ /**
+ * Determine if the given argument is present.
+ */
+ protected function hasArgument($name): bool
+ {
+ return $this->input->hasArgument($name) && ! is_null($this->argument($name));
+ }
+
+ /**
+ * Get all the arguments passed to the command.
+ */
+ protected function arguments(): array
+ {
+ return $this->input->getArguments();
+ }
+
+ /**
+ * Determine if the given option is present.
+ */
+ protected function hasOption($name): bool
+ {
+ return $this->input->hasOption($name) && ! is_null($this->option($name));
+ }
+}
diff --git a/src/IO/Helper/OutputTrait.php b/src/IO/Helper/OutputTrait.php
new file mode 100644
index 0000000..2991bd4
--- /dev/null
+++ b/src/IO/Helper/OutputTrait.php
@@ -0,0 +1,141 @@
+output->horizontalTable($headers, $rows);
+ }
+
+ protected function progressAdvance(int $step = 1): void
+ {
+ $this->output->progressAdvance($step);
+ }
+
+ protected function error(string|array $message): void
+ {
+ $this->output->error($message);
+ }
+
+ protected function progressFinish(): void
+ {
+ $this->output->progressFinish();
+ }
+
+ protected function title(string $message): void
+ {
+ $this->output->title($message);
+ }
+
+ protected function confirm(string $question, bool $default = true): bool
+ {
+ return $this->output->confirm($question, $default);
+ }
+
+ /**
+ * Writes a message to the output and adds a newline at the end.
+ */
+ protected function line(string $message, ?string $style = null): void
+ {
+ $styled = $style ? "<$style>$message$style>" : $message;
+
+ $this->output->writeln($styled);
+ }
+
+ protected function note(string|array $message): void
+ {
+ $this->output->note($message);
+ }
+
+ protected function question(string|array $message): void
+ {
+ $this->line($message, 'question');
+ }
+
+ protected function definitionList(string|array|TableSeparator ...$list): void
+ {
+ $this->output->definitionList(...$list);
+ }
+
+ protected function table(array $headers, array $rows): void
+ {
+ $this->output->table($headers, $rows);
+ }
+
+ protected function progressStart(int $max = 0): void
+ {
+ $this->output->progressStart($max);
+ }
+
+ protected function warning(string|array $message): void
+ {
+ $this->output->warning($message);
+ }
+
+ protected function createProgressBar(int $max = 0): ProgressBar
+ {
+ return $this->output->createProgressBar($max);
+ }
+
+ protected function comment(string|array $message): void
+ {
+ $this->output->comment($message);
+ }
+
+ protected function info(string|array $message): void
+ {
+ $this->output->info($message);
+ }
+
+ protected function text(string|array $message): void
+ {
+ $this->output->text($message);
+ }
+
+ protected function success(string|array $message): void
+ {
+ $this->output->success($message);
+ }
+
+ protected function askHidden(string $question, ?callable $validator = null): mixed
+ {
+ return $this->output->askHidden($question, $validator);
+ }
+
+ protected function choice(string $question, array $choices, mixed $default = null, bool $multiSelect = false): mixed
+ {
+ return $this->output->choice($question, $choices, $default, $multiSelect);
+ }
+
+ protected function listing(array $elements): void
+ {
+ $this->output->listing($elements);
+ }
+
+ protected function caution(string|array $message): void
+ {
+ $this->output->caution($message);
+ }
+
+ protected function section(string $message): void
+ {
+ $this->output->section($message);
+ }
+
+ protected function ask(string $question, ?string $default = null, ?callable $validator = null): mixed
+ {
+ return $this->output->ask($question, $default, $validator);
+ }
+}
diff --git a/src/IO/Output.php b/src/IO/Output.php
new file mode 100644
index 0000000..4e7087e
--- /dev/null
+++ b/src/IO/Output.php
@@ -0,0 +1,98 @@
+getFormatter())) {
+ $output = new NullOutput();
+ }
+
+ parent::__construct($input, $output);
+
+ $this->bufferedOutput = new TrimmedBufferOutput(
+ DIRECTORY_SEPARATOR === '\\' ? 4 : 2,
+ $output->getVerbosity(),
+ false,
+ clone $output->getFormatter()
+ );
+ }
+
+ public function listing(array $elements): void
+ {
+ $this->autoPrependText();
+
+ $elements = array_map(static fn ($element) => sprintf(' ➜ %s', $element), $elements);
+
+ $this->writeln($elements);
+ $this->newLine();
+ }
+
+ public function comment(string|array $message): void
+ {
+ $this->write(sprintf('➜ %s>', $message));
+ $this->newLine();
+ }
+
+ public function success(string|array $message): void
+ {
+ $this->write(sprintf('✔ %s>', $message));
+ $this->newLine();
+ }
+
+ public function error(string|array $message): void
+ {
+ $this->write(sprintf('✘ %s>', $message));
+ $this->newLine();
+ }
+
+ public function warning(string|array $message): void
+ {
+ $this->write(sprintf('⚠ %s>', $message));
+ $this->newLine();
+ }
+
+ public function note(string|array $message): void
+ {
+ $this->write(sprintf('➜ %s>', $message));
+ $this->newLine();
+ }
+
+ public function info(string|array $message): void
+ {
+ $this->write(sprintf('ℹ %s>', $message));
+ $this->newLine();
+ }
+
+ public function caution(string|array $message): void
+ {
+ $this->write(sprintf('! %s>', $message));
+ $this->newLine();
+ }
+
+ private function autoPrependText(): void
+ {
+ $fetched = $this->bufferedOutput->fetch();
+ // Prepend new line if last char isn't EOL:
+ if ($fetched && ! str_ends_with($fetched, "\n")) {
+ $this->newLine();
+ }
+ }
+}
diff --git a/src/LegacySymfonyStyle.php b/src/LegacySymfonyStyle.php
deleted file mode 100644
index 9070783..0000000
--- a/src/LegacySymfonyStyle.php
+++ /dev/null
@@ -1,21 +0,0 @@
-getFormatter()) ?
- new LegacySymfonyStyle($input) :
- new SymfonyStyle($input, $output);
- }
-}
diff --git a/tests/CommandTest.php b/tests/CommandTest.php
index cf5a9b9..9d653b5 100644
--- a/tests/CommandTest.php
+++ b/tests/CommandTest.php
@@ -4,11 +4,10 @@
namespace Symblaze\Console\Tests;
-use Symfony\Component\Console\Helper\ProgressBar;
-use Symfony\Component\Console\Helper\TableSeparator;
+use PHPUnit\Framework\Attributes\Test;
+use Symblaze\Console\IO\Output;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-use Symfony\Component\Console\Style\SymfonyStyle;
final class CommandTest extends TestCase
{
@@ -197,409 +196,15 @@ public function get_all_options(): void
$this->assertSame($expected, $command->options());
}
- /** @test */
- public function write_message_with_line(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('writeln')->with('Hello world');
-
- $command->line('Hello world');
- }
-
- /** @test */
- public function write_styled_message_with_line(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('writeln')->with('Hello world');
-
- $command->line('Hello world', 'info');
- }
-
- /** @test */
- public function write_a_verbose_message_with_line(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('writeln')->with('Hello world', OutputInterface::VERBOSITY_DEBUG);
-
- $command->line('Hello world', null, 'vvv');
- }
-
- /** @test */
- public function write_an_info_message(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('info')->with('Hello world');
-
- $command->info('Hello world');
- }
-
- /** @test */
- public function write_a_comment_message(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('comment')->with('Hello world');
-
- $command->comment('Hello world');
- }
-
- /** @test */
- public function write_a_question(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('writeln')->with('Hello world');
-
- $command->question('Hello world');
- }
-
- /** @test */
- public function write_an_error_message(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('error')->with('Hello world');
-
- $command->error('Hello world');
- }
-
- /** @test */
- public function write_a_warn_message(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('warning')->with('Hello world');
-
- $command->warning('Hello world');
- }
-
- /** @test */
- public function write_a_success_message(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('success')->with('Hello world');
-
- $command->success('Hello world');
- }
-
- /** @test */
- public function write_a_title(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('title')->with('Hello world');
-
- $command->title('Hello world');
- }
-
- /** @test */
- public function display_a_section(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('section')->with('Hello world');
-
- $command->section('Hello world');
- }
-
- /** @test */
- public function display_a_single_text_message(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('text')->with('Hello world');
-
- $command->text('Hello world');
- }
-
- /** @test */
- public function display_an_list_of_test_messages(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('text')->with(['Hello world', 'Hello world']);
-
- $command->text(['Hello world', 'Hello world']);
- }
-
- /** @test */
- public function display_un_ordered_list(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('listing')->with(['Hello world', 'Hello world']);
-
- $command->listing(['Hello world', 'Hello world']);
- }
-
- /** @test */
- public function display_a_table(): void
- {
- $headers = ['Header 1', 'Header 2'];
- $rows = [
- ['Cell 1-1', 'Cell 1-2'],
- ['Cell 2-1', 'Cell 2-2'],
- ['Cell 3-1', 'Cell 3-2'],
- ];
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('table')->with($headers, $rows);
-
- $command->table($headers, $rows);
- }
-
- /** @test */
- public function display_horizontal_table(): void
- {
- $headers = ['Header 1', 'Header 2'];
- $rows = [
- ['Cell 1-1', 'Cell 1-2'],
- ['Cell 2-1', 'Cell 2-2'],
- ['Cell 3-1', 'Cell 3-2'],
- ];
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('horizontalTable')->with($headers, $rows);
-
- $command->horizontalTable($headers, $rows);
- }
-
- /** @test */
- public function display_a_definition_list(): void
- {
- $list = [
- 'This is a title',
- ['foo1' => 'bar1'],
- ['foo2' => 'bar2'],
- ['foo3' => 'bar3'],
- new TableSeparator(),
- 'This is another title',
- ['foo4' => 'bar4'],
- ];
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('definitionList')->with($list);
-
- $command->definitionList($list);
- }
-
- /** @test */
- public function display_a_note(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('note')->with('Hello world');
-
- $command->note('Hello world');
- }
-
- /** @test */
- public function display_a_list_of_notes(): void
- {
- $notes = ['Hello world', 'Hello world'];
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('note')->with($notes);
-
- $command->note($notes);
- }
-
- /** @test */
- public function display_a_caution(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('caution')->with('Hello world');
-
- $command->caution('Hello world');
- }
-
- /** @test */
- public function display_a_list_of_cautions(): void
- {
- $cautions = ['Hello world', 'Hello world'];
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('caution')->with($cautions);
-
- $command->caution($cautions);
- }
-
- /** @test */
- public function ask_the_user_to_provide_a_value(): void
- {
- $question = 'What is your name?';
- $default = 'John Doe';
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('ask')->with($question, $default)->willReturn($default);
-
- $this->assertSame('John Doe', $command->ask($question, $default));
- }
-
- /** @test */
- public function ask_the_user_for_sensitive_data(): void
- {
- $question = 'What is your password?';
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $outputMock = $this->createMock(SymfonyStyle::class);
- $command->setOutput($outputMock);
-
- $outputMock->expects($this->once())->method('askHidden')->with($question)->willReturn('secret');
-
- $this->assertSame('secret', $command->askHidden($question));
- }
-
- /** @test */
- public function ask_a_yes_or_no_question(): void
- {
- $question = 'Do you want to continue?';
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $output = $this->createMock(SymfonyStyle::class);
- $command->setOutput($output);
-
- $output->expects($this->once())->method('confirm')->with($question)->willReturn(true);
-
- $this->assertTrue($command->confirm($question));
- }
-
- /** @test */
- public function ask_a_question_whose_answer_is_constrained_to_a_given_list(): void
- {
- $question = 'Select the queue to analyze';
- $choices = ['queue1', 'queue2', 'queue3'];
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $output = $this->createMock(SymfonyStyle::class);
- $command->setOutput($output);
-
- $output->expects($this->once())->method('choice')->with($question, $choices)->willReturn('queue1');
-
- $this->assertSame('queue1', $command->choice($question, $choices));
- }
-
- /** @test */
- public function progress_bar_start(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $output = $this->createMock(SymfonyStyle::class);
- $command->setOutput($output);
-
- $output->expects($this->once())->method('progressStart')->with(10);
-
- $command->progressStart(10);
- }
-
- /** @test */
- public function progress_advance(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $output = $this->createMock(SymfonyStyle::class);
- $command->setOutput($output);
-
- $output->expects($this->once())->method('progressAdvance')->with(10);
-
- $command->progressAdvance(10);
- }
-
- /** @test */
- public function progress_finish(): void
- {
- $command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $output = $this->createMock(SymfonyStyle::class);
- $command->setOutput($output);
-
- $output->expects($this->once())->method('progressFinish');
-
- $command->progressFinish();
- }
-
- /** @test */
- public function create_progress_bar(): void
+ #[Test]
+ public function run_sets_output_helper(): void
{
$command = new Doubles\MyCommand();
- $command->setInput($this->createMock(InputInterface::class));
- $output = $this->createMock(SymfonyStyle::class);
- $command->setOutput($output);
+ $input = $this->createMock(InputInterface::class);
+ $output = $this->createMock(OutputInterface::class);
- $output->expects($this->once())->method('createProgressBar')->with(10)->willReturn(new ProgressBar($output));
+ $command->run($input, $output);
- $command->createProgressBar(10);
+ $this->assertInstanceOf(Output::class, $command->getOutput());
}
}
diff --git a/tests/Doubles/MyCommand.php b/tests/Doubles/MyCommand.php
index 4269407..33f6af1 100644
--- a/tests/Doubles/MyCommand.php
+++ b/tests/Doubles/MyCommand.php
@@ -6,10 +6,8 @@
use Symblaze\Console\Command;
use Symfony\Component\Console\Attribute\AsCommand;
-use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-use Symfony\Component\Console\Style\SymfonyStyle;
/**
* @method hasArgument(string $name): bool
@@ -18,30 +16,6 @@
* @method hasOption(string $name): bool
* @method option(string $key): bool|array|string|null
* @method options(): array
- * @method line(string $message, ?string $style = null, string|int $verbosity = 'normal'): void
- * @method info(string|array $message): void
- * @method comment(string|array $message): void
- * @method question(string|array $message): void
- * @method error(string|array $message): void
- * @method warning(string|array $message): void
- * @method success(string|array $message): void
- * @method title(string $message): void
- * @method section(string $message): void
- * @method text(string|array $message): void
- * @method listing(array $elements): void
- * @method table(array $headers, array $rows): void
- * @method horizontalTable(array $headers, array $rows): void
- * @method definitionList(string|array|TableSeparator ...$list): void
- * @method note(string|array $message): void
- * @method caution(string|array $message): void
- * @method ask(string $question, string $default = null, callable $validator = null): mixed
- * @method askHidden(string $question, callable $validator = null): mixed
- * @method confirm(string $question, bool $default = true): bool
- * @method choice(string $question, array $choices, mixed $default = null, bool $multiSelect = false): mixed
- * @method progressStart(int $max = 0): void
- * @method progressAdvance(int $step = 1): void
- * @method progressFinish(): void
- * @method createProgressBar(int $max = 0): ProgressBar
*/
#[AsCommand(name: 'acme:command {required_argument} {optional_argument?} {argument_with_value=default} {--O|option} {--OWV|option_with_value=} {--OWDV|option_with_default=default}')]
class MyCommand extends Command
@@ -55,14 +29,4 @@ public function __call(string $name, array $arguments)
{
return parent::$name(...$arguments);
}
-
- public function setOutput(SymfonyStyle $output): void
- {
- $this->output = $output;
- }
-
- public function setInput(InputInterface $input): void
- {
- $this->input = $input;
- }
}