From 67191f7f1d85ea8fa7598787e1e26b722acdb5e9 Mon Sep 17 00:00:00 2001 From: Sven Nolting Date: Mon, 2 Dec 2024 14:51:36 +0100 Subject: [PATCH 1/5] [Console] Fix division by 0 error --- Helper/ProgressBar.php | 2 +- Tests/Helper/ProgressBarTest.php | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Helper/ProgressBar.php b/Helper/ProgressBar.php index b406292b4..23157e3c7 100644 --- a/Helper/ProgressBar.php +++ b/Helper/ProgressBar.php @@ -229,7 +229,7 @@ public function getEstimated(): float public function getRemaining(): float { - if (!$this->step) { + if (0 === $this->step || $this->step === $this->startingStep) { return 0; } diff --git a/Tests/Helper/ProgressBarTest.php b/Tests/Helper/ProgressBarTest.php index a5a0eca24..c32307720 100644 --- a/Tests/Helper/ProgressBarTest.php +++ b/Tests/Helper/ProgressBarTest.php @@ -110,6 +110,14 @@ public function testRegularTimeEstimation() ); } + public function testRegularTimeRemainingWithDifferentStartAtAndCustomDisplay() + { + ProgressBar::setFormatDefinition('custom', ' %current%/%max% [%bar%] %percent:3s%% %remaining% %estimated%'); + $bar = new ProgressBar($output = $this->getOutputStream(), 1_200, 0); + $bar->setFormat('custom'); + $bar->start(1_200, 600); + } + public function testResumedTimeEstimation() { $bar = new ProgressBar($output = $this->getOutputStream(), 1_200, 0); From 799445db3f15768ecc382ac5699e6da0520a0a04 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 7 Dec 2024 13:07:30 +0100 Subject: [PATCH 2/5] fix risky test that doesn't perform any assertions --- Tests/Helper/ProgressBarTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/Helper/ProgressBarTest.php b/Tests/Helper/ProgressBarTest.php index c32307720..a1db94583 100644 --- a/Tests/Helper/ProgressBarTest.php +++ b/Tests/Helper/ProgressBarTest.php @@ -112,8 +112,10 @@ public function testRegularTimeEstimation() public function testRegularTimeRemainingWithDifferentStartAtAndCustomDisplay() { + $this->expectNotToPerformAssertions(); + ProgressBar::setFormatDefinition('custom', ' %current%/%max% [%bar%] %percent:3s%% %remaining% %estimated%'); - $bar = new ProgressBar($output = $this->getOutputStream(), 1_200, 0); + $bar = new ProgressBar($this->getOutputStream(), 1_200, 0); $bar->setFormat('custom'); $bar->start(1_200, 600); } From fefcc18c0f5d0efe3ab3152f15857298868dc2c3 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Wed, 11 Dec 2024 04:49:26 +0100 Subject: [PATCH 3/5] [Console] Fix tests --- Tests/ApplicationTest.php | 1 + Tests/ConsoleEventsTest.php | 1 + Tests/SignalRegistry/SignalRegistryTest.php | 1 + 3 files changed, 3 insertions(+) diff --git a/Tests/ApplicationTest.php b/Tests/ApplicationTest.php index 469353505..4f6e6cb96 100644 --- a/Tests/ApplicationTest.php +++ b/Tests/ApplicationTest.php @@ -79,6 +79,7 @@ protected function tearDown(): void pcntl_signal(\SIGTERM, \SIG_DFL); pcntl_signal(\SIGUSR1, \SIG_DFL); pcntl_signal(\SIGUSR2, \SIG_DFL); + pcntl_signal(\SIGALRM, \SIG_DFL); } } diff --git a/Tests/ConsoleEventsTest.php b/Tests/ConsoleEventsTest.php index 9c04d2706..408f8c0d3 100644 --- a/Tests/ConsoleEventsTest.php +++ b/Tests/ConsoleEventsTest.php @@ -39,6 +39,7 @@ protected function tearDown(): void pcntl_signal(\SIGTERM, \SIG_DFL); pcntl_signal(\SIGUSR1, \SIG_DFL); pcntl_signal(\SIGUSR2, \SIG_DFL); + pcntl_signal(\SIGALRM, \SIG_DFL); } } diff --git a/Tests/SignalRegistry/SignalRegistryTest.php b/Tests/SignalRegistry/SignalRegistryTest.php index f997f7c1d..92d500f9e 100644 --- a/Tests/SignalRegistry/SignalRegistryTest.php +++ b/Tests/SignalRegistry/SignalRegistryTest.php @@ -27,6 +27,7 @@ protected function tearDown(): void pcntl_signal(\SIGTERM, \SIG_DFL); pcntl_signal(\SIGUSR1, \SIG_DFL); pcntl_signal(\SIGUSR2, \SIG_DFL); + pcntl_signal(\SIGALRM, \SIG_DFL); } public function testOneCallbackForASignalSignalIsHandled() From 2e4af9c952617cc3f9559ff706aee420a8464c36 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Thu, 27 Feb 2025 11:59:51 +0100 Subject: [PATCH 4/5] fix(console): fix progress bar messing output in section when there is an EOL --- Helper/ProgressBar.php | 9 ++++ Tests/Helper/ProgressBarTest.php | 75 ++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/Helper/ProgressBar.php b/Helper/ProgressBar.php index 23157e3c7..3dc06d7b4 100644 --- a/Helper/ProgressBar.php +++ b/Helper/ProgressBar.php @@ -486,12 +486,21 @@ private function overwrite(string $message): void if ($this->output instanceof ConsoleSectionOutput) { $messageLines = explode("\n", $this->previousMessage); $lineCount = \count($messageLines); + + $lastLineWithoutDecoration = Helper::removeDecoration($this->output->getFormatter(), end($messageLines) ?? ''); + + // When the last previous line is empty (without formatting) it is already cleared by the section output, so we don't need to clear it again + if ('' === $lastLineWithoutDecoration) { + --$lineCount; + } + foreach ($messageLines as $messageLine) { $messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine)); if ($messageLineLength > $this->terminal->getWidth()) { $lineCount += floor($messageLineLength / $this->terminal->getWidth()); } } + $this->output->clear($lineCount); } else { $lineCount = substr_count($this->previousMessage, "\n"); diff --git a/Tests/Helper/ProgressBarTest.php b/Tests/Helper/ProgressBarTest.php index a1db94583..615237f1f 100644 --- a/Tests/Helper/ProgressBarTest.php +++ b/Tests/Helper/ProgressBarTest.php @@ -416,6 +416,81 @@ public function testOverwriteWithSectionOutput() ); } + public function testOverwriteWithSectionOutputAndEol() + { + $sections = []; + $stream = $this->getOutputStream(true); + $output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter()); + + $bar = new ProgressBar($output, 50, 0); + $bar->setFormat('[%bar%] %percent:3s%%' . PHP_EOL . '%message%' . PHP_EOL); + $bar->setMessage(''); + $bar->start(); + $bar->display(); + $bar->setMessage('Doing something...'); + $bar->advance(); + $bar->setMessage('Doing something foo...'); + $bar->advance(); + + rewind($output->getStream()); + $this->assertEquals(escapeshellcmd( + '[>---------------------------] 0%'.\PHP_EOL.\PHP_EOL. + "\x1b[2A\x1b[0J".'[>---------------------------] 2%'.\PHP_EOL. 'Doing something...' . \PHP_EOL . + "\x1b[2A\x1b[0J".'[=>--------------------------] 4%'.\PHP_EOL. 'Doing something foo...' . \PHP_EOL), + escapeshellcmd(stream_get_contents($output->getStream())) + ); + } + + public function testOverwriteWithSectionOutputAndEolWithEmptyMessage() + { + $sections = []; + $stream = $this->getOutputStream(true); + $output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter()); + + $bar = new ProgressBar($output, 50, 0); + $bar->setFormat('[%bar%] %percent:3s%%' . PHP_EOL . '%message%'); + $bar->setMessage('Start'); + $bar->start(); + $bar->display(); + $bar->setMessage(''); + $bar->advance(); + $bar->setMessage('Doing something...'); + $bar->advance(); + + rewind($output->getStream()); + $this->assertEquals(escapeshellcmd( + '[>---------------------------] 0%'.\PHP_EOL.'Start'.\PHP_EOL. + "\x1b[2A\x1b[0J".'[>---------------------------] 2%'.\PHP_EOL . + "\x1b[1A\x1b[0J".'[=>--------------------------] 4%'.\PHP_EOL. 'Doing something...' . \PHP_EOL), + escapeshellcmd(stream_get_contents($output->getStream())) + ); + } + + public function testOverwriteWithSectionOutputAndEolWithEmptyMessageComment() + { + $sections = []; + $stream = $this->getOutputStream(true); + $output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter()); + + $bar = new ProgressBar($output, 50, 0); + $bar->setFormat('[%bar%] %percent:3s%%' . PHP_EOL . '%message%'); + $bar->setMessage('Start'); + $bar->start(); + $bar->display(); + $bar->setMessage(''); + $bar->advance(); + $bar->setMessage('Doing something...'); + $bar->advance(); + + rewind($output->getStream()); + $this->assertEquals(escapeshellcmd( + '[>---------------------------] 0%'.\PHP_EOL."\x1b[33mStart\x1b[39m".\PHP_EOL. + "\x1b[2A\x1b[0J".'[>---------------------------] 2%'.\PHP_EOL . + "\x1b[1A\x1b[0J".'[=>--------------------------] 4%'.\PHP_EOL. "\x1b[33mDoing something...\x1b[39m" . \PHP_EOL), + escapeshellcmd(stream_get_contents($output->getStream())) + ); + } + public function testOverwriteWithAnsiSectionOutput() { // output has 43 visible characters plus 2 invisible ANSI characters From a3011c7b7adb58d89f6c0d822abb641d7a5f9719 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Mon, 7 Apr 2025 16:42:41 +0100 Subject: [PATCH 5/5] Correctly convert SIGSYS to its name --- SignalRegistry/SignalMap.php | 2 +- Tests/SignalRegistry/SignalMapTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/SignalRegistry/SignalMap.php b/SignalRegistry/SignalMap.php index de419bda7..2f9aa67c1 100644 --- a/SignalRegistry/SignalMap.php +++ b/SignalRegistry/SignalMap.php @@ -27,7 +27,7 @@ public static function getSignalName(int $signal): ?string if (!isset(self::$map)) { $r = new \ReflectionExtension('pcntl'); $c = $r->getConstants(); - $map = array_filter($c, fn ($k) => str_starts_with($k, 'SIG') && !str_starts_with($k, 'SIG_'), \ARRAY_FILTER_USE_KEY); + $map = array_filter($c, fn ($k) => str_starts_with($k, 'SIG') && !str_starts_with($k, 'SIG_') && 'SIGBABY' !== $k, \ARRAY_FILTER_USE_KEY); self::$map = array_flip($map); } diff --git a/Tests/SignalRegistry/SignalMapTest.php b/Tests/SignalRegistry/SignalMapTest.php index 887c5d7af..f4e320477 100644 --- a/Tests/SignalRegistry/SignalMapTest.php +++ b/Tests/SignalRegistry/SignalMapTest.php @@ -22,6 +22,7 @@ class SignalMapTest extends TestCase * @testWith [2, "SIGINT"] * [9, "SIGKILL"] * [15, "SIGTERM"] + * [31, "SIGSYS"] */ public function testSignalExists(int $signal, string $expected) {