bug #37160 Reset question validator attempts only for actual stdin (ostrolucky)

This PR was merged into the 4.4 branch.

Discussion
----------

Reset question validator attempts only for actual stdin

| Q             | A
| ------------- | ---
| Branch?       | 4/4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tickets       | Fix #37046
| License       | MIT
| Doc PR        |

Let's see what CI says. Works for me locally with phpunit and when running such command manually

Commits
-------

8fe7be4212 Reset question validator attempts only for actual stdin
This commit is contained in:
Fabien Potencier 2020-06-15 07:23:00 +02:00
commit 52612b1541
2 changed files with 33 additions and 14 deletions

View File

@ -509,14 +509,16 @@ class QuestionHelper extends Helper
private function isTty(): bool private function isTty(): bool
{ {
$inputStream = !$this->inputStream && \defined('STDIN') ? STDIN : $this->inputStream; if (!\defined('STDIN')) {
return true;
}
if (\function_exists('stream_isatty')) { if (\function_exists('stream_isatty')) {
return stream_isatty($inputStream); return stream_isatty(fopen('php://input', 'r'));
} }
if (\function_exists('posix_isatty')) { if (\function_exists('posix_isatty')) {
return posix_isatty($inputStream); return posix_isatty(fopen('php://input', 'r'));
} }
return true; return true;

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\Console\Tests\Helper; namespace Symfony\Component\Console\Tests\Helper;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\FormatterHelper; use Symfony\Component\Console\Helper\FormatterHelper;
@ -21,6 +22,7 @@ use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Terminal; use Symfony\Component\Console\Terminal;
use Symfony\Component\Console\Tester\ApplicationTester;
/** /**
* @group tty * @group tty
@ -727,21 +729,36 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
$dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), $question); $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), $question);
} }
public function testAskThrowsExceptionFromValidatorEarlyWhenTtyIsMissing() public function testQuestionValidatorRepeatsThePrompt()
{ {
$this->expectException('Exception'); $tries = 0;
$this->expectExceptionMessage('Bar, not Foo'); $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(); return $value;
$output->expects($this->once())->method('writeln'); });
(new QuestionHelper())->ask( (new QuestionHelper())->ask($input, $output, $question);
$this->createStreamableInputInterfaceMock($this->getInputStream('Foo'), true),
$output, return 0;
(new Question('Q?'))->setHidden(true)->setValidator(function ($input) {
throw new \Exception("Bar, not $input");
}) })
); ;
$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() public function testEmptyChoices()