From e890f6b7d68617ca8989acb23570ccae4f7eb939 Mon Sep 17 00:00:00 2001 From: Brent Roose Date: Tue, 14 May 2024 09:21:53 +0200 Subject: [PATCH] Improve console tester --- src/Testing/ConsoleTester.php | 33 +++++++++++++++----- tests/Testing/ConsoleTesterTest.php | 47 +++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 tests/Testing/ConsoleTesterTest.php diff --git a/src/Testing/ConsoleTester.php b/src/Testing/ConsoleTester.php index 0859545..a6a0813 100644 --- a/src/Testing/ConsoleTester.php +++ b/src/Testing/ConsoleTester.php @@ -5,13 +5,16 @@ namespace Tempest\Console\Testing; use Closure; +use Exception; use Fiber; use PHPUnit\Framework\Assert; +use ReflectionMethod; use Tempest\AppConfig; use Tempest\Console\Components\InteractiveComponentRenderer; use Tempest\Console\Console; use Tempest\Console\ConsoleApplication; use Tempest\Console\ConsoleArgumentBag; +use Tempest\Console\ConsoleCommand; use Tempest\Console\Exceptions\ConsoleExceptionHandler; use Tempest\Console\GenericConsole; use Tempest\Console\Input\InputBuffer; @@ -21,6 +24,7 @@ use Tempest\Console\Output\OutputBuffer; use Tempest\Container\Container; use Tempest\Highlight\Highlighter; +use Tempest\Support\Reflection\Attributes; final class ConsoleTester { @@ -28,15 +32,12 @@ final class ConsoleTester private ?MemoryInputBuffer $input = null; private ?InteractiveComponentRenderer $componentRenderer = null; - public function __construct(private Container $container) - { + public function __construct( + private readonly Container $container, + ) { } - /** - * @param string|Closure $command - * @return $this - */ - public function call(string|Closure $command): self + public function call(string|Closure|array $command): self { $clone = clone $this; @@ -66,6 +67,22 @@ public function call(string|Closure $command): self $command($console); }); } else { + if (is_string($command) && class_exists($command)) { + $command = [$command, '__invoke']; + } + + if (is_array($command) || class_exists($command)) { + $attribute = Attributes::find(ConsoleCommand::class) + ->in(new ReflectionMethod(...$command)) + ->first(); + + if (! $attribute) { + throw new Exception("Could not resolve console command from {$command[0]}::{$command[1]}"); + } + + $command = $attribute->getName(); + } + $fiber = new Fiber(function () use ($command, $clone) { $clone->container->singleton(ConsoleArgumentBag::class, new ConsoleArgumentBag(['tempest', ...explode(' ', $command)])); @@ -98,7 +115,7 @@ public function input(int|string|Key $input): self public function submit(int|string $input = ''): self { - $input = (string) $input; + $input = (string)$input; $this->input($input . Key::ENTER->value); diff --git a/tests/Testing/ConsoleTesterTest.php b/tests/Testing/ConsoleTesterTest.php new file mode 100644 index 0000000..1117758 --- /dev/null +++ b/tests/Testing/ConsoleTesterTest.php @@ -0,0 +1,47 @@ +console + ->call(ComplexCommand::class) + ->assertContains('complex '); + } + + public function test_call_with_closure(): void + { + $this->console + ->call(function (Console $console) { + $console->writeln('hi'); + }) + ->assertContains('hi'); + } + + public function test_call_with_callable(): void + { + $this->console + ->call([InteractiveCommand::class, 'validation']) + ->assertContains('a'); + } + + public function test_call_with_command(): void + { + $this->console + ->call('interactive:validation') + ->assertContains('a'); + } +}