Skip to content

Commit fd902f7

Browse files
authored
test: Add tests to check against the forwarded arguments and options to the child process (#324)
1 parent 5483485 commit fd902f7

File tree

3 files changed

+267
-0
lines changed

3 files changed

+267
-0
lines changed

phpstan-tests.neon.dist

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ parameters:
2222
message: '#ParallelizationIntegrationTest::\$importUnknownMoviesCountCommand#'
2323
- path: tests/Integration/ParallelizationIntegrationTest.php
2424
message: '#ParallelizationIntegrationTest::\$noSubProcessCommand#'
25+
- path: tests/Integration/DebugChildProcessInputsTest.php
26+
message: '#DebugChildProcessInputsTest::\$command#'
2527

2628
- path: tests/ChunkedItemsIteratorTest.php
2729
message: '#Parameter \#2 \$fetchItems of static method .+ChunkedItemsIterator::fromItemOrCallable\(\) expects callable\(\)#'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Webmozarts Console Parallelization package.
5+
*
6+
* (c) Webmozarts GmbH <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Webmozarts\Console\Parallelization\Fixtures\Command;
15+
16+
use Override;
17+
use Symfony\Component\Console\Input\InputInterface;
18+
use Symfony\Component\Console\Input\InputOption;
19+
use Symfony\Component\Console\Output\OutputInterface;
20+
use Webmozarts\Console\Parallelization\Logger\Logger;
21+
use Webmozarts\Console\Parallelization\ParallelCommand;
22+
use Webmozarts\Console\Parallelization\ParallelExecutorFactory;
23+
use function file_put_contents;
24+
use function func_get_args;
25+
use function implode;
26+
use const LOCK_EX;
27+
28+
final class DebugChildProcessCommand extends ParallelCommand
29+
{
30+
public const string OUTPUT_FILE = __DIR__.'/../../../dist/debug-child-input.txt';
31+
32+
private const string SIMPLE_OPTION = 'simple-option';
33+
private const string ARRAY_OPTION = 'array-option';
34+
35+
private string $item = 'item';
36+
private ?Logger $logger = null;
37+
38+
public function __construct()
39+
{
40+
parent::__construct('debug:process');
41+
}
42+
43+
#[Override]
44+
protected function configure(): void
45+
{
46+
parent::configure();
47+
48+
$this->addOption(
49+
self::SIMPLE_OPTION,
50+
null,
51+
InputOption::VALUE_OPTIONAL,
52+
);
53+
$this->addOption(
54+
self::ARRAY_OPTION,
55+
null,
56+
InputOption::VALUE_OPTIONAL + InputOption::VALUE_IS_ARRAY,
57+
);
58+
}
59+
60+
public function setItem(string $item): void
61+
{
62+
$this->item = $item;
63+
}
64+
65+
protected function fetchItems(InputInterface $input, OutputInterface $output): array
66+
{
67+
return [$this->item];
68+
}
69+
70+
#[Override]
71+
protected function configureParallelExecutableFactory(
72+
ParallelExecutorFactory $parallelExecutorFactory,
73+
InputInterface $input,
74+
OutputInterface $output,
75+
): ParallelExecutorFactory {
76+
return parent::configureParallelExecutableFactory(...func_get_args())
77+
->withScriptPath(__DIR__.'/../../../bin/console');
78+
}
79+
80+
public function setLogger(?Logger $logger): void
81+
{
82+
$this->logger = $logger;
83+
}
84+
85+
#[Override]
86+
protected function createLogger(
87+
InputInterface $input,
88+
OutputInterface $output,
89+
): Logger {
90+
return $this->logger ?? parent::createLogger($input, $output);
91+
}
92+
93+
protected function runSingleCommand(string $item, InputInterface $input, OutputInterface $output): void
94+
{
95+
file_put_contents(
96+
self::OUTPUT_FILE,
97+
self::createContent(
98+
$item,
99+
$input->getOption(self::SIMPLE_OPTION),
100+
$input->getOption(self::ARRAY_OPTION),
101+
),
102+
flags: LOCK_EX,
103+
);
104+
}
105+
106+
protected function getItemName(?int $count): string
107+
{
108+
return 1 === $count ? 'item' : 'items';
109+
}
110+
111+
public static function createContent(
112+
string $item,
113+
?string $simpleOption,
114+
array $arrayOption,
115+
): string {
116+
$normalizedArrayOption = implode(
117+
"\n",
118+
array_map(
119+
static fn (string $option): string => " - {$option}",
120+
$arrayOption,
121+
),
122+
);
123+
124+
return <<<EOF
125+
Item: {$item}
126+
Simple Option: {$simpleOption}
127+
Array Option:
128+
{$normalizedArrayOption}
129+
130+
EOF;
131+
}
132+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Webmozarts Console Parallelization package.
5+
*
6+
* (c) Webmozarts GmbH <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Webmozarts\Console\Parallelization\Integration;
15+
16+
use PHPUnit\Framework\Attributes\CoversNothing;
17+
use PHPUnit\Framework\Attributes\DataProvider;
18+
use PHPUnit\Framework\TestCase;
19+
use Symfony\Bundle\FrameworkBundle\Console\Application;
20+
use Symfony\Component\Console\Tester\CommandTester;
21+
use Symfony\Component\Filesystem\Filesystem;
22+
use Webmozarts\Console\Parallelization\Fixtures\Command\DebugChildProcessCommand;
23+
use Webmozarts\Console\Parallelization\Integration\App\BareKernel;
24+
use Webmozarts\Console\Parallelization\Logger\DummyLogger;
25+
use function file_get_contents;
26+
27+
/**
28+
* @internal
29+
*/
30+
#[CoversNothing]
31+
class DebugChildProcessInputsTest extends TestCase
32+
{
33+
private DebugChildProcessCommand $command;
34+
private CommandTester $commandTester;
35+
36+
protected function setUp(): void
37+
{
38+
$this->command = (new Application(new BareKernel()))->add(new DebugChildProcessCommand());
39+
$this->commandTester = new CommandTester($this->command);
40+
}
41+
42+
protected function tearDown(): void
43+
{
44+
(new Filesystem())->remove(DebugChildProcessCommand::OUTPUT_FILE);
45+
}
46+
47+
#[DataProvider('inputProvider')]
48+
public function test_it_can_run_the_command_without_sub_processes(
49+
string $item,
50+
?string $simpleOption,
51+
array $arrayOption,
52+
string $expected,
53+
): void {
54+
$logger = new DummyLogger();
55+
56+
$this->command->setItem($item);
57+
$this->command->setLogger($logger);
58+
59+
$this->commandTester->execute(
60+
[
61+
'command' => 'debug:process',
62+
'--simple-option' => $simpleOption,
63+
'--array-option' => $arrayOption,
64+
],
65+
['interactive' => true],
66+
);
67+
68+
$output = $this->commandTester->getDisplay();
69+
$actual = file_get_contents(DebugChildProcessCommand::OUTPUT_FILE);
70+
71+
$this->commandTester->assertCommandIsSuccessful($output);
72+
self::assertSame($expected, $actual, $output);
73+
}
74+
75+
public static function inputProvider(): iterable
76+
{
77+
// This test fails...
78+
// yield 'default' => [
79+
// 'item',
80+
// null,
81+
// [],
82+
// DebugChildProcessCommand::createContent(
83+
// 'item',
84+
// '',
85+
// [],
86+
// ),
87+
// ];
88+
89+
yield 'with values' => [
90+
'item',
91+
'option',
92+
['option1', 'option2'],
93+
DebugChildProcessCommand::createContent(
94+
'item',
95+
'option',
96+
['option1--array-option=option2'],
97+
),
98+
];
99+
100+
yield 'escaped string token' => [
101+
'"foo"',
102+
'"bar"',
103+
['"option1"', '"option2"'],
104+
DebugChildProcessCommand::createContent(
105+
'"foo"',
106+
'"\"bar\""',
107+
['"\"option1\""--array-option="\"option2\""'],
108+
),
109+
];
110+
111+
yield 'escaped string token with both types of quotes' => [
112+
'"o_id in(\'20\')"',
113+
'"p_id in(\'22\')"',
114+
['"option in(\'1\')"', '"option in(\'2\')"'],
115+
DebugChildProcessCommand::createContent(
116+
'"o_id in(\'20\')"',
117+
'"\"p_id in(\'22\')\""',
118+
['"\"option in(\'1\')\""--array-option="\"option in(\'2\')\""'],
119+
),
120+
];
121+
122+
yield 'with values with spaces' => [
123+
'a b c d',
124+
'd c b a',
125+
['option 1', 'option 2'],
126+
DebugChildProcessCommand::createContent(
127+
'a b c d',
128+
'"d c b a"',
129+
['"option 1"--array-option="option 2"'],
130+
),
131+
];
132+
}
133+
}

0 commit comments

Comments
 (0)