Skip to content

Commit 8d17c4f

Browse files
committed
refactor(ConfigCommand): use dependency injection for ExecutableFinder
- Replace the instantiation of ExecutableFinder in the ConfigCommand class with dependency injection to increase code modularity and testability. - Update the handle method signature to include the ExecutableFinder parameter.
1 parent 0dd8daf commit 8d17c4f

File tree

2 files changed

+26
-38
lines changed

2 files changed

+26
-38
lines changed

app/Commands/ConfigCommand.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public function __construct()
6868
/**
6969
* @throws \JsonException
7070
*/
71-
public function handle(): int
71+
public function handle(ExecutableFinder $executableFinder): int
7272
{
7373
$file = value(function () {
7474
if ($file = $this->option('file')) {
@@ -123,13 +123,12 @@ public function handle(): int
123123

124124
break;
125125
case 'edit':
126-
$editor = value(function () {
126+
$editor = value(function () use ($executableFinder) {
127127
if ($editor = $this->option('editor')) {
128128
return $editor;
129129
}
130130

131131
$editors = windows_os() ? self::WINDOWS_EDITORS : self::UNIX_EDITORS;
132-
$executableFinder = new ExecutableFinder();
133132
foreach ($editors as $editor) {
134133
if ($executableFinder->find($editor)) {
135134
return $editor;

tests/Feature/ConfigCommandTest.php

Lines changed: 24 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
use App\ConfigManager;
1515
use App\Exceptions\RuntimeException;
1616
use App\Exceptions\UnsupportedConfigActionException;
17-
use Symfony\Component\Process\Exception\RuntimeException as SymfonyRuntimeException;
18-
use Symfony\Component\Process\Process;
17+
use Symfony\Component\Process\Exception\ProcessFailedException;
18+
use Symfony\Component\Process\ExecutableFinder;
1919

2020
it('can set config', function (): void {
2121
$this->getFunctionMock(class_namespace(ConfigCommand::class), 'file_exists')
@@ -104,58 +104,47 @@
104104
])->assertSuccessful();
105105
})->group(__DIR__, __FILE__);
106106

107-
it('will throw RuntimeException for edit config on Windows', function (): void {
108-
$this->artisan(ConfigCommand::class, [
109-
'action' => 'edit',
110-
]);
111-
})
112-
->group(__DIR__, __FILE__)
113-
->skip(! windows_os())
114-
->throws(RuntimeException::class, 'The edit config command is not supported on Windows.');
115-
116-
it('will throw RuntimeException for edit config', function (): void {
117-
$this->getFunctionMock(class_namespace(ConfigCommand::class), 'exec')
118-
->expects($this->exactly(6))
119-
->willReturn('');
120-
107+
it('will throw `Command not found` ProcessFailedException for edit config', function (): void {
121108
$this->artisan(ConfigCommand::class, [
122109
'action' => 'edit',
110+
'--editor' => 'foo',
123111
]);
124112
})
125113
->group(__DIR__, __FILE__)
126-
->skip(windows_os())
127-
->throws(RuntimeException::class, 'No editor found or specified.');
114+
->throws(ProcessFailedException::class);
128115

129-
it('will throw \SymfonyRuntimeException for edit config', function (): void {
130-
$this->getFunctionMock(class_namespace(Process::class), 'proc_open')
131-
->expects($this->once())
132-
->willReturn(false);
116+
it('will throw another `Command not found` ProcessFailedException for edit config', function (): void {
117+
app()->singleton(ExecutableFinder::class, static function () {
118+
return new class() extends ExecutableFinder {
119+
public function find(string $name, ?string $default = null, array $extraDirs = []): string
120+
{
121+
return 'foo';
122+
}
123+
};
124+
});
133125

134126
$this->artisan(ConfigCommand::class, [
135127
'action' => 'edit',
136-
'--editor' => 'foo',
137128
]);
138129
})
139130
->group(__DIR__, __FILE__)
140-
->skip()
141-
->throws(SymfonyRuntimeException::class, 'TTY mode requires /dev/tty to be read/writable.');
131+
->throws(ProcessFailedException::class);
142132

143-
it('will throw SymfonyRuntimeException for edit config', function (): void {
144-
$this->getFunctionMock(class_namespace(ConfigCommand::class), 'exec')
145-
->expects($this->once())
146-
->willReturn('/usr/local/bin/vim');
147-
148-
$this->getFunctionMock(class_namespace(Process::class), 'proc_open')
149-
->expects($this->any())
150-
->willReturn(false);
133+
it('will throw RuntimeException for edit config', function (): void {
134+
app()->singleton(ExecutableFinder::class, static function () {
135+
return new class() extends ExecutableFinder {
136+
public function find(string $name, ?string $default = null, array $extraDirs = []): void
137+
{
138+
}
139+
};
140+
});
151141

152142
$this->artisan(ConfigCommand::class, [
153143
'action' => 'edit',
154144
]);
155145
})
156146
->group(__DIR__, __FILE__)
157-
->skip(windows_os())
158-
->throws(SymfonyRuntimeException::class, 'TTY mode requires /dev/tty to be read/writable.');
147+
->throws(RuntimeException::class, 'Unable to find a default editor or specify the editor.');
159148

160149
it('will throw UnsupportedConfigActionException', function (): void {
161150
$this->artisan(ConfigCommand::class, [

0 commit comments

Comments
 (0)