From 0e1178343ad46fc23bab164e91123e33d1c065f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= <5175937+theofidry@users.noreply.github.com> Date: Sun, 30 Oct 2022 16:23:39 +0100 Subject: [PATCH] Handle the case where no items has been returned (#178) Closes #176 --- src/Configuration.php | 5 +- tests/ConfigurationTest.php | 10 +++ tests/Fixtures/Command/NoItemCommand.php | 40 ++++++++++++ tests/Fixtures/ItemNamingCapabilities.php | 29 +++++++++ tests/Integration/NoItemCommandTest.php | 74 +++++++++++++++++++++++ 5 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 tests/Fixtures/Command/NoItemCommand.php create mode 100644 tests/Fixtures/ItemNamingCapabilities.php create mode 100644 tests/Integration/NoItemCommandTest.php diff --git a/src/Configuration.php b/src/Configuration.php index 11216d1..5ef0766 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -15,6 +15,7 @@ use Webmozart\Assert\Assert; use function ceil; +use function max; use function min; use function sprintf; @@ -185,10 +186,10 @@ private static function createForWithChildProcesses( ); } - $numberOfSegments = (int) ceil($numberOfItems / $segmentSize); + $numberOfSegments = max(1, (int) ceil($numberOfItems / $segmentSize)); Assert::positiveInteger($numberOfSegments); - $numberOfSegmentsRequired = (int) ceil($numberOfItems / $segmentSize); + $numberOfSegmentsRequired = max(1, (int) ceil($numberOfItems / $segmentSize)); Assert::positiveInteger($numberOfSegmentsRequired); $requiredNumberOfProcesses = min($numberOfProcesses, $numberOfSegmentsRequired); diff --git a/tests/ConfigurationTest.php b/tests/ConfigurationTest.php index 3008282..a35f3ee 100644 --- a/tests/ConfigurationTest.php +++ b/tests/ConfigurationTest.php @@ -293,6 +293,16 @@ private static function childValuesProvider(): iterable 2, 2, ); + + yield 'no item' => $createSet( + 0, + 1, + 5, + 5, + 1, + 1, + 0, + ); } /** diff --git a/tests/Fixtures/Command/NoItemCommand.php b/tests/Fixtures/Command/NoItemCommand.php new file mode 100644 index 0000000..4782637 --- /dev/null +++ b/tests/Fixtures/Command/NoItemCommand.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Webmozarts\Console\Parallelization\Fixtures\Command; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Webmozarts\Console\Parallelization\Fixtures\ItemNamingCapabilities; +use Webmozarts\Console\Parallelization\ParallelCommand; +use Webmozarts\Console\Parallelization\UnexpectedCall; + +final class NoItemCommand extends ParallelCommand +{ + use ItemNamingCapabilities; + + public function __construct() + { + parent::__construct('test:no-item'); + } + + protected function fetchItems(InputInterface $input, OutputInterface $output): iterable + { + return []; + } + + protected function runSingleCommand(string $item, InputInterface $input, OutputInterface $output): void + { + throw UnexpectedCall::forMethod(__METHOD__); + } +} diff --git a/tests/Fixtures/ItemNamingCapabilities.php b/tests/Fixtures/ItemNamingCapabilities.php new file mode 100644 index 0000000..b0bdf8b --- /dev/null +++ b/tests/Fixtures/ItemNamingCapabilities.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Webmozarts\Console\Parallelization\Fixtures; + +trait ItemNamingCapabilities +{ + /** + * @param positive-int|0|null $count + */ + protected function getItemName(?int $count): string + { + if (null === $count) { + return 'item(s)'; + } + + return $count > 1 ? 'items' : 'item'; + } +} diff --git a/tests/Integration/NoItemCommandTest.php b/tests/Integration/NoItemCommandTest.php new file mode 100644 index 0000000..8d62e24 --- /dev/null +++ b/tests/Integration/NoItemCommandTest.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Webmozarts\Console\Parallelization\Integration; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Tester\CommandTester; +use Webmozarts\Console\Parallelization\Fixtures\Command\NoItemCommand; + +/** + * @coversNothing + * + * @internal + */ +class NoItemCommandTest extends TestCase +{ + private Command $command; + private CommandTester $commandTester; + + protected function setUp(): void + { + $this->command = (new Application())->add(new NoItemCommand()); + $this->commandTester = new CommandTester($this->command); + } + + protected function tearDown(): void + { + unset($this->command, $this->commandTester); + } + + public function test_it_can_execute_a_command_that_gives_no_item(): void + { + $this->commandTester->execute( + ['command' => 'test:no-item'], + ['interactive' => true], + ); + + $expected = <<<'EOF' + Processing 0 item in segments of 50, batches of 50, 1 round, 0 batch, with 1 child process. + + 0 [>---------------------------] 10 secs 10.0 MiB + + // Memory usage: 10.0 MB (peak: 10.0 MB), time: 10 secs + + Processed 0 item. + + EOF; + + $actual = OutputNormalizer::removeIntermediateFixedProgressBars( + $this->getOutput($this->commandTester), + ); + + self::assertSame($expected, $actual, $actual); + } + + private function getOutput(CommandTester $commandTester): string + { + $output = $commandTester->getDisplay(true); + + return OutputNormalizer::normalize($output); + } +}