Skip to content

Commit 9d9d76a

Browse files
committed
wip: Refactor WikiCommand
1 parent 9c3fd5c commit 9d9d76a

2 files changed

Lines changed: 157 additions & 82 deletions

File tree

src/Console/Command/WikiCommand.php

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@
1818

1919
namespace FastForward\DevTools\Console\Command;
2020

21+
use Composer\Command\BaseCommand;
2122
use FastForward\DevTools\Composer\Json\ComposerJson;
23+
use FastForward\DevTools\Process\ProcessBuilderInterface;
24+
use FastForward\DevTools\Process\ProcessQueueInterface;
2225
use Symfony\Component\Console\Attribute\AsCommand;
2326
use Symfony\Component\Console\Input\InputInterface;
2427
use Symfony\Component\Console\Input\InputOption;
2528
use Symfony\Component\Console\Output\OutputInterface;
26-
use Symfony\Component\Filesystem\Filesystem;
27-
use Symfony\Component\Process\Process;
2829

2930
/**
3031
* Handles the generation of API documentation for the project.
@@ -36,19 +37,19 @@
3637
help: 'This command generates API documentation in Markdown format using phpDocumentor. '
3738
. 'It accepts an optional `--target` option to specify the output directory for the generated documentation.'
3839
)]
39-
final class WikiCommand extends AbstractCommand
40+
final class WikiCommand extends BaseCommand
4041
{
4142
/**
4243
* Creates a new WikiCommand instance.
4344
*
4445
* @param ComposerJson $composerJson the composer.json accessor
45-
* @param Filesystem $filesystem the filesystem component
4646
*/
4747
public function __construct(
48+
private readonly ProcessBuilderInterface $processBuilder,
49+
private readonly ProcessQueueInterface $processQueue,
4850
private readonly ComposerJson $composerJson,
49-
Filesystem $filesystem
5051
) {
51-
return parent::__construct($filesystem);
52+
return parent::__construct();
5253
}
5354

5455
/**
@@ -68,6 +69,12 @@ protected function configure(): void
6869
mode: InputOption::VALUE_OPTIONAL,
6970
description: 'Path to the output directory for the generated Markdown documentation.',
7071
default: '.github/wiki'
72+
)
73+
->addOption(
74+
name: 'cache-dir',
75+
mode: InputOption::VALUE_OPTIONAL,
76+
description: 'Path to the cache directory for phpDocumentor.',
77+
default: 'tmp/cache/phpdoc'
7178
);
7279
}
7380

@@ -86,34 +93,27 @@ protected function execute(InputInterface $input, OutputInterface $output): int
8693
{
8794
$output->writeln('<info>Generating API documentation...</info>');
8895

89-
$arguments = [
90-
$this->getAbsolutePath('vendor/bin/phpdoc'),
91-
'--cache-folder',
92-
$this->getCurrentWorkingDirectory() . '/tmp/cache/phpdoc',
93-
'--visibility=public,protected',
94-
'--title=' . $this->composerJson->getPackageDescription(),
95-
];
96+
$processBuilder = $this->processBuilder
97+
->withArgument('--visibility', 'public,protected')
98+
->withArgument('--template', 'vendor/saggre/phpdocumentor-markdown/themes/markdown')
99+
->withArgument('--title', $this->composerJson->getPackageDescription())
100+
->withArgument('--target', $input->getOption('target'))
101+
->withArgument('--cache-folder', $input->getOption('cache-dir'));
96102

97103
$psr4Namespaces = $this->composerJson->getAutoload();
98104

99105
foreach ($psr4Namespaces as $path) {
100-
$arguments[] = '--directory';
101-
$arguments[] = $path;
106+
$processBuilder = $processBuilder->withArgument('--directory', $path);
102107
}
103108

104109
if ($defaultPackageName = array_key_first($psr4Namespaces)) {
105-
$arguments[] = '--defaultpackagename';
106-
$arguments[] = $defaultPackageName;
110+
$processBuilder = $processBuilder->withArgument('--defaultpackagename', $defaultPackageName);
107111
}
108112

109-
$command = new Process([
110-
...$arguments,
111-
'--target',
112-
$this->getAbsolutePath($input->getOption('target')),
113-
'--template',
114-
'vendor/saggre/phpdocumentor-markdown/themes/markdown',
115-
]);
113+
$this->processQueue->add(
114+
$processBuilder->build('vendor/bin/phpdoc')
115+
);
116116

117-
return parent::runProcess($command, $output);
117+
return $this->processQueue->run();
118118
}
119119
}

tests/Console/Command/WikiCommandTest.php

Lines changed: 132 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -18,98 +18,173 @@
1818

1919
namespace FastForward\DevTools\Tests\Console\Command;
2020

21-
use FastForward\DevTools\Composer\Json\ComposerJson;
2221
use FastForward\DevTools\Console\Command\WikiCommand;
22+
use FastForward\DevTools\Composer\Json\ComposerJson;
23+
use FastForward\DevTools\Process\ProcessBuilderInterface;
24+
use FastForward\DevTools\Process\ProcessQueueInterface;
2325
use PHPUnit\Framework\Attributes\CoversClass;
2426
use PHPUnit\Framework\Attributes\Test;
27+
use PHPUnit\Framework\TestCase;
28+
use Prophecy\Argument;
2529
use Prophecy\PhpUnit\ProphecyTrait;
2630
use Prophecy\Prophecy\ObjectProphecy;
31+
use ReflectionMethod;
32+
use Symfony\Component\Console\Input\InputInterface;
33+
use Symfony\Component\Console\Output\OutputInterface;
2734
use Symfony\Component\Process\Process;
2835

2936
#[CoversClass(WikiCommand::class)]
30-
final class WikiCommandTest extends AbstractCommandTestCase
37+
final class WikiCommandTest extends TestCase
3138
{
3239
use ProphecyTrait;
3340

34-
/**
35-
* @var ObjectProphecy<ComposerJson>
36-
*/
41+
private ObjectProphecy $processBuilder;
42+
43+
private ObjectProphecy $processQueue;
44+
3745
private ObjectProphecy $composerJson;
3846

39-
/**
40-
* @return WikiCommand
41-
*/
42-
protected function getCommandClass(): WikiCommand
47+
private ObjectProphecy $input;
48+
49+
private ObjectProphecy $output;
50+
51+
private ObjectProphecy $process;
52+
53+
private WikiCommand $command;
54+
55+
protected function setUp(): void
4356
{
44-
return new WikiCommand($this->composerJson->reveal(), $this->filesystem->reveal());
57+
$this->processBuilder = $this->prophesize(ProcessBuilderInterface::class);
58+
$this->processQueue = $this->prophesize(ProcessQueueInterface::class);
59+
$this->composerJson = $this->prophesize(ComposerJson::class);
60+
$this->input = $this->prophesize(InputInterface::class);
61+
$this->output = $this->prophesize(OutputInterface::class);
62+
$this->process = $this->prophesize(Process::class);
63+
64+
$this->composerJson->getPackageDescription()
65+
->willReturn('Fast Forward Dev Tools plugin');
66+
$this->composerJson->getAutoload()
67+
->willReturn(['FastForward\\DevTools\\' => 'src/']);
68+
69+
$this->processBuilder->withArgument(Argument::any())
70+
->willReturn($this->processBuilder->reveal());
71+
$this->processBuilder->withArgument(Argument::any(), Argument::any())
72+
->willReturn($this->processBuilder->reveal());
73+
74+
$this->processBuilder->build(Argument::any())
75+
->willReturn($this->process->reveal());
76+
77+
$this->command = new WikiCommand(
78+
$this->processBuilder->reveal(),
79+
$this->processQueue->reveal(),
80+
$this->composerJson->reveal(),
81+
);
4582
}
4683

47-
/**
48-
* @return string
49-
*/
50-
protected function getCommandName(): string
84+
#[Test]
85+
public function commandWillSetExpectedNameDescriptionAndHelp(): void
5186
{
52-
return 'wiki';
87+
self::assertSame('wiki', $this->command->getName());
88+
self::assertSame(
89+
'Generates API documentation in Markdown format.',
90+
$this->command->getDescription()
91+
);
92+
self::assertSame(
93+
'This command generates API documentation in Markdown format using phpDocumentor. '
94+
. 'It accepts an optional `--target` option to specify the output directory for the generated documentation.',
95+
$this->command->getHelp()
96+
);
5397
}
5498

55-
/**
56-
* @return string
57-
*/
58-
protected function getCommandDescription(): string
99+
#[Test]
100+
public function commandWillHaveExpectedOptions(): void
59101
{
60-
return 'Generates API documentation in Markdown format.';
102+
$definition = $this->command->getDefinition();
103+
104+
self::assertTrue($definition->hasOption('target'));
105+
self::assertTrue($definition->hasOption('cache-dir'));
61106
}
62107

63-
/**
64-
* @return string
65-
*/
66-
protected function getCommandHelp(): string
108+
#[Test]
109+
public function executeWillReturnSuccessWhenProcessQueueSucceeds(): void
67110
{
68-
return 'This command generates API documentation in Markdown format using phpDocumentor. '
69-
. 'It accepts an optional `--target` option to specify the output directory for the generated documentation.';
111+
$this->input->getOption('target')
112+
->willReturn('.github/wiki');
113+
$this->input->getOption('cache-dir')
114+
->willReturn('tmp/cache/phpdoc');
115+
116+
$this->processQueue->add($this->process->reveal())
117+
->shouldBeCalled();
118+
119+
$this->processQueue->run()
120+
->willReturn(ProcessQueueInterface::SUCCESS)
121+
->shouldBeCalled();
122+
123+
$this->output->writeln('<info>Generating API documentation...</info>')
124+
->shouldBeCalled();
125+
126+
$result = $this->executeCommand();
127+
128+
self::assertSame(WikiCommand::SUCCESS, $result);
70129
}
71130

72-
/**
73-
* @return void
74-
*/
75-
protected function setUp(): void
131+
#[Test]
132+
public function executeWillReturnFailureWhenProcessQueueFails(): void
76133
{
77-
$this->composerJson = $this->prophesize(ComposerJson::class);
78-
$this->composerJson->getPackageDescription()
79-
->willReturn('Fast Forward Dev Tools plugin');
80-
$this->composerJson->getAutoload()
81-
->willReturn([
82-
'FastForward\\DevTools\\' => 'src/',
83-
]);
134+
$this->input->getOption('target')
135+
->willReturn('.github/wiki');
136+
$this->input->getOption('cache-dir')
137+
->willReturn('tmp/cache/phpdoc');
138+
139+
$this->processQueue->add($this->process->reveal())
140+
->shouldBeCalled();
141+
142+
$this->processQueue->run()
143+
->willReturn(ProcessQueueInterface::FAILURE)
144+
->shouldBeCalled();
145+
146+
$this->output->writeln('<info>Generating API documentation...</info>')
147+
->shouldBeCalled();
148+
149+
$result = $this->executeCommand();
84150

85-
parent::setUp();
151+
self::assertSame(WikiCommand::FAILURE, $result);
86152
}
87153

88-
/**
89-
* @return void
90-
*/
91154
#[Test]
92-
public function executeWillRunProcessWithPhpdocMarkdownArguments(): void
155+
public function executeWillBuildProcessWithCorrectArguments(): void
93156
{
94-
$this->willRunProcessWithCallback(function (Process $process): bool {
95-
$commandLine = $process->getCommandLine();
157+
$this->input->getOption('target')
158+
->willReturn('.github/wiki');
159+
$this->input->getOption('cache-dir')
160+
->willReturn('tmp/cache/phpdoc');
96161

97-
return str_contains($commandLine, 'vendor/bin/phpdoc')
98-
&& str_contains($commandLine, '--target')
99-
&& str_contains($commandLine, '.github/wiki');
100-
});
162+
$this->processBuilder->withArgument('--visibility', 'public,protected')
163+
->willReturn($this->processBuilder->reveal());
164+
$this->processBuilder->withArgument('--template', Argument::any())
165+
->willReturn($this->processBuilder->reveal());
166+
$this->processBuilder->withArgument(Argument::any(), Argument::any())
167+
->willReturn($this->processBuilder->reveal());
101168

102-
self::assertSame(WikiCommand::SUCCESS, $this->invokeExecute());
169+
$this->processQueue->add($this->process->reveal())
170+
->shouldBeCalled();
171+
172+
$this->processQueue->run()
173+
->willReturn(ProcessQueueInterface::SUCCESS)
174+
->shouldBeCalled();
175+
176+
$this->output->writeln(Argument::type('string'))
177+
->shouldBeCalled();
178+
179+
$result = $this->executeCommand();
180+
181+
self::assertSame(WikiCommand::SUCCESS, $result);
103182
}
104183

105-
/**
106-
* @return void
107-
*/
108-
#[Test]
109-
public function executeWillReturnFailureIfProcessFails(): void
184+
private function executeCommand(): int
110185
{
111-
$this->willRunProcessWithCallback(static fn(): bool => true, false);
186+
$reflectionMethod = new ReflectionMethod($this->command, 'execute');
112187

113-
self::assertSame(WikiCommand::FAILURE, $this->invokeExecute());
188+
return $reflectionMethod->invoke($this->command, $this->input->reveal(), $this->output->reveal());
114189
}
115-
}
190+
}

0 commit comments

Comments
 (0)