From be9cb92a41c89dcb4d1e006ee6d369a6699ca86e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Mon, 8 Jun 2020 21:53:13 +0200 Subject: [PATCH 1/2] Reset question validator attempts only for actual stdin --- Helper/QuestionHelper.php | 8 +++--- Tests/Helper/QuestionHelperTest.php | 39 +++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/Helper/QuestionHelper.php b/Helper/QuestionHelper.php index 134f6231e..f9d74ebe5 100644 --- a/Helper/QuestionHelper.php +++ b/Helper/QuestionHelper.php @@ -509,14 +509,16 @@ private function getShell() private function isTty(): bool { - $inputStream = !$this->inputStream && \defined('STDIN') ? STDIN : $this->inputStream; + if (!\defined('STDIN')) { + return true; + } if (\function_exists('stream_isatty')) { - return stream_isatty($inputStream); + return stream_isatty(fopen('php://input', 'r')); } if (\function_exists('posix_isatty')) { - return posix_isatty($inputStream); + return posix_isatty(fopen('php://input', 'r')); } return true; diff --git a/Tests/Helper/QuestionHelperTest.php b/Tests/Helper/QuestionHelperTest.php index ddb0c90e1..b9eb2f66d 100644 --- a/Tests/Helper/QuestionHelperTest.php +++ b/Tests/Helper/QuestionHelperTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Console\Tests\Helper; +use Symfony\Component\Console\Application; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Helper\FormatterHelper; @@ -21,6 +22,7 @@ use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Terminal; +use Symfony\Component\Console\Tester\ApplicationTester; /** * @group tty @@ -727,21 +729,36 @@ public function testAskThrowsExceptionOnMissingInputWithValidator() $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), $question); } - public function testAskThrowsExceptionFromValidatorEarlyWhenTtyIsMissing() + public function testQuestionValidatorRepeatsThePrompt() { - $this->expectException('Exception'); - $this->expectExceptionMessage('Bar, not Foo'); + $tries = 0; + $application = new Application(); + $application->setAutoExit(false); + $application->register('question') + ->setCode(function ($input, $output) use (&$tries) { + $question = new Question('This is a promptable question'); + $question->setValidator(function ($value) use (&$tries) { + ++$tries; + if (!$value) { + throw new \Exception(); + } - $output = $this->getMockBuilder('\Symfony\Component\Console\Output\OutputInterface')->getMock(); - $output->expects($this->once())->method('writeln'); + return $value; + }); + + (new QuestionHelper())->ask($input, $output, $question); - (new QuestionHelper())->ask( - $this->createStreamableInputInterfaceMock($this->getInputStream('Foo'), true), - $output, - (new Question('Q?'))->setHidden(true)->setValidator(function ($input) { - throw new \Exception("Bar, not $input"); + return 0; }) - ); + ; + + $tester = new ApplicationTester($application); + $tester->setInputs(['', 'not-empty']); + + $statusCode = $tester->run(['command' => 'question'], ['interactive' => true]); + + $this->assertSame(2, $tries); + $this->assertSame($statusCode, 0); } public function testEmptyChoices() From a3660e1c74be6d5a02b884f57e80a4e440a705ef Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 15 Jun 2020 14:27:36 +0200 Subject: [PATCH 2/2] [Console] Reset question validator attempts only for actual stdin (bis) --- Helper/QuestionHelper.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Helper/QuestionHelper.php b/Helper/QuestionHelper.php index f9d74ebe5..1b60786c9 100644 --- a/Helper/QuestionHelper.php +++ b/Helper/QuestionHelper.php @@ -104,7 +104,7 @@ private function doAsk(OutputInterface $output, Question $question) { $this->writePrompt($output, $question); - $inputStream = $this->inputStream ?: STDIN; + $inputStream = $this->inputStream ?: fopen('php://stdin', 'r'); $autocomplete = $question->getAutocompleterCallback(); if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) { @@ -474,7 +474,7 @@ private function validateAttempts(callable $interviewer, OutputInterface $output } catch (\Exception $error) { } - $attempts = $attempts ?? -(int) $this->isTty(); + $attempts = $attempts ?? -(int) $this->askForever(); } throw $error; @@ -507,18 +507,20 @@ private function getShell() return self::$shell; } - private function isTty(): bool + private function askForever(): bool { - if (!\defined('STDIN')) { + $inputStream = $this->inputStream ?: fopen('php://stdin', 'r'); + + if ('php://stdin' !== (stream_get_meta_data($inputStream)['url'] ?? null)) { return true; } if (\function_exists('stream_isatty')) { - return stream_isatty(fopen('php://input', 'r')); + return stream_isatty($inputStream); } if (\function_exists('posix_isatty')) { - return posix_isatty(fopen('php://input', 'r')); + return posix_isatty($inputStream); } return true;