4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Console\Tests\Helper;
14 use Symfony\Component\Console\Formatter\OutputFormatter;
15 use Symfony\Component\Console\Helper\QuestionHelper;
16 use Symfony\Component\Console\Helper\HelperSet;
17 use Symfony\Component\Console\Helper\FormatterHelper;
18 use Symfony\Component\Console\Output\StreamOutput;
19 use Symfony\Component\Console\Question\ChoiceQuestion;
20 use Symfony\Component\Console\Question\ConfirmationQuestion;
21 use Symfony\Component\Console\Question\Question;
26 class QuestionHelperTest extends AbstractQuestionHelperTest
28 public function testAskChoice()
30 $questionHelper = new QuestionHelper();
32 $helperSet = new HelperSet(array(new FormatterHelper()));
33 $questionHelper->setHelperSet($helperSet);
35 $heroes = array('Superman', 'Batman', 'Spiderman');
37 $inputStream = $this->getInputStream("\n1\n 1 \nFabien\n1\nFabien\n1\n0,2\n 0 , 2 \n\n\n");
39 $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '2');
40 $question->setMaxAttempts(1);
41 // first answer is an empty answer, we're supposed to receive the default value
42 $this->assertEquals('Spiderman', $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
44 $question = new ChoiceQuestion('What is your favorite superhero?', $heroes);
45 $question->setMaxAttempts(1);
46 $this->assertEquals('Batman', $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
47 $this->assertEquals('Batman', $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
49 $question = new ChoiceQuestion('What is your favorite superhero?', $heroes);
50 $question->setErrorMessage('Input "%s" is not a superhero!');
51 $question->setMaxAttempts(2);
52 $this->assertEquals('Batman', $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $output = $this->createOutputInterface(), $question));
54 rewind($output->getStream());
55 $stream = stream_get_contents($output->getStream());
56 $this->assertContains('Input "Fabien" is not a superhero!', $stream);
59 $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '1');
60 $question->setMaxAttempts(1);
61 $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $output = $this->createOutputInterface(), $question);
63 } catch (\InvalidArgumentException $e) {
64 $this->assertEquals('Value "Fabien" is invalid', $e->getMessage());
67 $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, null);
68 $question->setMaxAttempts(1);
69 $question->setMultiselect(true);
71 $this->assertEquals(array('Batman'), $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
72 $this->assertEquals(array('Superman', 'Spiderman'), $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
73 $this->assertEquals(array('Superman', 'Spiderman'), $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
75 $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '0,1');
76 $question->setMaxAttempts(1);
77 $question->setMultiselect(true);
79 $this->assertEquals(array('Superman', 'Batman'), $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
81 $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, ' 0 , 1 ');
82 $question->setMaxAttempts(1);
83 $question->setMultiselect(true);
85 $this->assertEquals(array('Superman', 'Batman'), $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
87 $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, 0);
88 // We are supposed to get the default value since we are not in interactive mode
89 $this->assertEquals('Superman', $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream, true), $this->createOutputInterface(), $question));
92 public function testAsk()
94 $dialog = new QuestionHelper();
96 $inputStream = $this->getInputStream("\n8AM\n");
98 $question = new Question('What time is it?', '2PM');
99 $this->assertEquals('2PM', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
101 $question = new Question('What time is it?', '2PM');
102 $this->assertEquals('8AM', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $output = $this->createOutputInterface(), $question));
104 rewind($output->getStream());
105 $this->assertEquals('What time is it?', stream_get_contents($output->getStream()));
108 public function testAskWithAutocomplete()
110 if (!$this->hasSttyAvailable()) {
111 $this->markTestSkipped('`stty` is required to test autocomplete functionality');
115 // Ac<BACKSPACE><BACKSPACE>s<TAB>Test<NEWLINE>
117 // <UP ARROW><UP ARROW><NEWLINE>
118 // <UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><TAB>Test<NEWLINE>
119 // <DOWN ARROW><NEWLINE>
120 // S<BACKSPACE><BACKSPACE><DOWN ARROW><DOWN ARROW><NEWLINE>
121 // F00<BACKSPACE><BACKSPACE>oo<TAB><NEWLINE>
122 $inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\n");
124 $dialog = new QuestionHelper();
125 $helperSet = new HelperSet(array(new FormatterHelper()));
126 $dialog->setHelperSet($helperSet);
128 $question = new Question('Please select a bundle', 'FrameworkBundle');
129 $question->setAutocompleterValues(array('AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle'));
131 $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
132 $this->assertEquals('AsseticBundleTest', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
133 $this->assertEquals('FrameworkBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
134 $this->assertEquals('SecurityBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
135 $this->assertEquals('FooBundleTest', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
136 $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
137 $this->assertEquals('AsseticBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
138 $this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
141 public function testAskWithAutocompleteWithNonSequentialKeys()
143 if (!$this->hasSttyAvailable()) {
144 $this->markTestSkipped('`stty` is required to test autocomplete functionality');
147 // <UP ARROW><UP ARROW><NEWLINE><DOWN ARROW><DOWN ARROW><NEWLINE>
148 $inputStream = $this->getInputStream("\033[A\033[A\n\033[B\033[B\n");
150 $dialog = new QuestionHelper();
151 $dialog->setHelperSet(new HelperSet(array(new FormatterHelper())));
153 $question = new ChoiceQuestion('Please select a bundle', array(1 => 'AcmeDemoBundle', 4 => 'AsseticBundle'));
154 $question->setMaxAttempts(1);
156 $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
157 $this->assertEquals('AsseticBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
160 public function testAskWithAutocompleteWithExactMatch()
162 if (!$this->hasSttyAvailable()) {
163 $this->markTestSkipped('`stty` is required to test autocomplete functionality');
166 $inputStream = $this->getInputStream("b\n");
168 $possibleChoices = array(
174 $dialog = new QuestionHelper();
175 $dialog->setHelperSet(new HelperSet(array(new FormatterHelper())));
177 $question = new ChoiceQuestion('Please select a city', $possibleChoices);
178 $question->setMaxAttempts(1);
180 $this->assertSame('b', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
183 public function testAutocompleteWithTrailingBackslash()
185 if (!$this->hasSttyAvailable()) {
186 $this->markTestSkipped('`stty` is required to test autocomplete functionality');
189 $inputStream = $this->getInputStream('E');
191 $dialog = new QuestionHelper();
192 $helperSet = new HelperSet(array(new FormatterHelper()));
193 $dialog->setHelperSet($helperSet);
195 $question = new Question('');
196 $expectedCompletion = 'ExampleNamespace\\';
197 $question->setAutocompleterValues(array($expectedCompletion));
199 $output = $this->createOutputInterface();
200 $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $output, $question);
202 $outputStream = $output->getStream();
203 rewind($outputStream);
204 $actualOutput = stream_get_contents($outputStream);
206 // Shell control (esc) sequences are not so important: we only care that
207 // <hl> tag is interpreted correctly and replaced
208 $irrelevantEscSequences = array(
209 "\0337" => '', // Save cursor position
210 "\0338" => '', // Restore cursor position
211 "\033[K" => '', // Clear line from cursor till the end
214 $importantActualOutput = strtr($actualOutput, $irrelevantEscSequences);
216 // Remove colors (e.g. "\033[30m", "\033[31;41m")
217 $importantActualOutput = preg_replace('/\033\[\d+(;\d+)?m/', '', $importantActualOutput);
219 $this->assertEquals($expectedCompletion, $importantActualOutput);
222 public function testAskHiddenResponse()
224 if ('\\' === DIRECTORY_SEPARATOR) {
225 $this->markTestSkipped('This test is not supported on Windows');
228 $dialog = new QuestionHelper();
230 $question = new Question('What time is it?');
231 $question->setHidden(true);
233 $this->assertEquals('8AM', $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream("8AM\n")), $this->createOutputInterface(), $question));
237 * @dataProvider getAskConfirmationData
239 public function testAskConfirmation($question, $expected, $default = true)
241 $dialog = new QuestionHelper();
243 $inputStream = $this->getInputStream($question."\n");
244 $question = new ConfirmationQuestion('Do you like French fries?', $default);
245 $this->assertEquals($expected, $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question), 'confirmation question should '.($expected ? 'pass' : 'cancel'));
248 public function getAskConfirmationData()
252 array('', false, false),
260 public function testAskConfirmationWithCustomTrueAnswer()
262 $dialog = new QuestionHelper();
264 $inputStream = $this->getInputStream("j\ny\n");
265 $question = new ConfirmationQuestion('Do you like French fries?', false, '/^(j|y)/i');
266 $this->assertTrue($dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
267 $question = new ConfirmationQuestion('Do you like French fries?', false, '/^(j|y)/i');
268 $this->assertTrue($dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
271 public function testAskAndValidate()
273 $dialog = new QuestionHelper();
274 $helperSet = new HelperSet(array(new FormatterHelper()));
275 $dialog->setHelperSet($helperSet);
277 $error = 'This is not a color!';
278 $validator = function ($color) use ($error) {
279 if (!in_array($color, array('white', 'black'))) {
280 throw new \InvalidArgumentException($error);
286 $question = new Question('What color was the white horse of Henry IV?', 'white');
287 $question->setValidator($validator);
288 $question->setMaxAttempts(2);
290 $inputStream = $this->getInputStream("\nblack\n");
291 $this->assertEquals('white', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
292 $this->assertEquals('black', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
295 $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream("green\nyellow\norange\n")), $this->createOutputInterface(), $question);
297 } catch (\InvalidArgumentException $e) {
298 $this->assertEquals($error, $e->getMessage());
303 * @dataProvider simpleAnswerProvider
305 public function testSelectChoiceFromSimpleChoices($providedAnswer, $expectedValue)
307 $possibleChoices = array(
313 $dialog = new QuestionHelper();
314 $helperSet = new HelperSet(array(new FormatterHelper()));
315 $dialog->setHelperSet($helperSet);
317 $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
318 $question->setMaxAttempts(1);
319 $answer = $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream($providedAnswer."\n")), $this->createOutputInterface(), $question);
321 $this->assertSame($expectedValue, $answer);
324 public function simpleAnswerProvider()
327 array(0, 'My environment 1'),
328 array(1, 'My environment 2'),
329 array(2, 'My environment 3'),
330 array('My environment 1', 'My environment 1'),
331 array('My environment 2', 'My environment 2'),
332 array('My environment 3', 'My environment 3'),
337 * @dataProvider specialCharacterInMultipleChoice
339 public function testSpecialCharacterChoiceFromMultipleChoiceList($providedAnswer, $expectedValue)
341 $possibleChoices = array(
346 $dialog = new QuestionHelper();
347 $inputStream = $this->getInputStream($providedAnswer."\n");
348 $helperSet = new HelperSet(array(new FormatterHelper()));
349 $dialog->setHelperSet($helperSet);
351 $question = new ChoiceQuestion('Please select the directory', $possibleChoices);
352 $question->setMaxAttempts(1);
353 $question->setMultiselect(true);
354 $answer = $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question);
356 $this->assertSame($expectedValue, $answer);
359 public function specialCharacterInMultipleChoice()
362 array('.', array('.')),
363 array('., src', array('.', 'src')),
368 * @dataProvider mixedKeysChoiceListAnswerProvider
370 public function testChoiceFromChoicelistWithMixedKeys($providedAnswer, $expectedValue)
372 $possibleChoices = array(
373 '0' => 'No environment',
374 '1' => 'My environment 1',
375 'env_2' => 'My environment 2',
376 3 => 'My environment 3',
379 $dialog = new QuestionHelper();
380 $helperSet = new HelperSet(array(new FormatterHelper()));
381 $dialog->setHelperSet($helperSet);
383 $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
384 $question->setMaxAttempts(1);
385 $answer = $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream($providedAnswer."\n")), $this->createOutputInterface(), $question);
387 $this->assertSame($expectedValue, $answer);
390 public function mixedKeysChoiceListAnswerProvider()
394 array('No environment', '0'),
396 array('env_2', 'env_2'),
398 array('My environment 1', '1'),
403 * @dataProvider answerProvider
405 public function testSelectChoiceFromChoiceList($providedAnswer, $expectedValue)
407 $possibleChoices = array(
408 'env_1' => 'My environment 1',
409 'env_2' => 'My environment',
410 'env_3' => 'My environment',
413 $dialog = new QuestionHelper();
414 $helperSet = new HelperSet(array(new FormatterHelper()));
415 $dialog->setHelperSet($helperSet);
417 $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
418 $question->setMaxAttempts(1);
419 $answer = $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream($providedAnswer."\n")), $this->createOutputInterface(), $question);
421 $this->assertSame($expectedValue, $answer);
425 * @expectedException \InvalidArgumentException
426 * @expectedExceptionMessage The provided answer is ambiguous. Value should be one of env_2 or env_3.
428 public function testAmbiguousChoiceFromChoicelist()
430 $possibleChoices = array(
431 'env_1' => 'My first environment',
432 'env_2' => 'My environment',
433 'env_3' => 'My environment',
436 $dialog = new QuestionHelper();
437 $helperSet = new HelperSet(array(new FormatterHelper()));
438 $dialog->setHelperSet($helperSet);
440 $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
441 $question->setMaxAttempts(1);
443 $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream("My environment\n")), $this->createOutputInterface(), $question);
446 public function answerProvider()
449 array('env_1', 'env_1'),
450 array('env_2', 'env_2'),
451 array('env_3', 'env_3'),
452 array('My environment 1', 'env_1'),
456 public function testNoInteraction()
458 $dialog = new QuestionHelper();
459 $question = new Question('Do you have a job?', 'not yet');
460 $this->assertEquals('not yet', $dialog->ask($this->createStreamableInputInterfaceMock(null, false), $this->createOutputInterface(), $question));
464 * @requires function mb_strwidth
466 public function testChoiceOutputFormattingQuestionForUtf8Keys()
468 $question = 'Lorem ipsum?';
469 $possibleChoices = array(
474 $outputShown = array(
476 ' [<info>foo </info>] foo',
477 ' [<info>żółw </info>] bar',
478 ' [<info>łabądź</info>] baz',
480 $output = $this->getMockBuilder('\Symfony\Component\Console\Output\OutputInterface')->getMock();
481 $output->method('getFormatter')->willReturn(new OutputFormatter());
483 $dialog = new QuestionHelper();
484 $helperSet = new HelperSet(array(new FormatterHelper()));
485 $dialog->setHelperSet($helperSet);
487 $output->expects($this->once())->method('writeln')->with($this->equalTo($outputShown));
489 $question = new ChoiceQuestion($question, $possibleChoices, 'foo');
490 $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream("\n")), $output, $question);
496 public function testLegacyAskChoice()
498 $questionHelper = new QuestionHelper();
500 $helperSet = new HelperSet(array(new FormatterHelper()));
501 $questionHelper->setHelperSet($helperSet);
503 $heroes = array('Superman', 'Batman', 'Spiderman');
505 $questionHelper->setInputStream($this->getInputStream("\n1\n 1 \nFabien\n1\nFabien\n1\n0,2\n 0 , 2 \n\n\n"));
507 $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '2');
508 $question->setMaxAttempts(1);
509 // first answer is an empty answer, we're supposed to receive the default value
510 $this->assertEquals('Spiderman', $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
512 $question = new ChoiceQuestion('What is your favorite superhero?', $heroes);
513 $question->setMaxAttempts(1);
514 $this->assertEquals('Batman', $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
515 $this->assertEquals('Batman', $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
517 $question = new ChoiceQuestion('What is your favorite superhero?', $heroes);
518 $question->setErrorMessage('Input "%s" is not a superhero!');
519 $question->setMaxAttempts(2);
520 $this->assertEquals('Batman', $questionHelper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question));
522 rewind($output->getStream());
523 $stream = stream_get_contents($output->getStream());
524 $this->assertContains('Input "Fabien" is not a superhero!', $stream);
527 $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '1');
528 $question->setMaxAttempts(1);
529 $questionHelper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question);
531 } catch (\InvalidArgumentException $e) {
532 $this->assertEquals('Value "Fabien" is invalid', $e->getMessage());
535 $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, null);
536 $question->setMaxAttempts(1);
537 $question->setMultiselect(true);
539 $this->assertEquals(array('Batman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
540 $this->assertEquals(array('Superman', 'Spiderman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
541 $this->assertEquals(array('Superman', 'Spiderman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
543 $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '0,1');
544 $question->setMaxAttempts(1);
545 $question->setMultiselect(true);
547 $this->assertEquals(array('Superman', 'Batman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
549 $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, ' 0 , 1 ');
550 $question->setMaxAttempts(1);
551 $question->setMultiselect(true);
553 $this->assertEquals(array('Superman', 'Batman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
559 public function testLegacyAsk()
561 $dialog = new QuestionHelper();
563 $dialog->setInputStream($this->getInputStream("\n8AM\n"));
565 $question = new Question('What time is it?', '2PM');
566 $this->assertEquals('2PM', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
568 $question = new Question('What time is it?', '2PM');
569 $this->assertEquals('8AM', $dialog->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question));
571 rewind($output->getStream());
572 $this->assertEquals('What time is it?', stream_get_contents($output->getStream()));
578 public function testLegacyAskWithAutocomplete()
580 if (!$this->hasSttyAvailable()) {
581 $this->markTestSkipped('`stty` is required to test autocomplete functionality');
585 // Ac<BACKSPACE><BACKSPACE>s<TAB>Test<NEWLINE>
587 // <UP ARROW><UP ARROW><NEWLINE>
588 // <UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><TAB>Test<NEWLINE>
589 // <DOWN ARROW><NEWLINE>
590 // S<BACKSPACE><BACKSPACE><DOWN ARROW><DOWN ARROW><NEWLINE>
591 // F00<BACKSPACE><BACKSPACE>oo<TAB><NEWLINE>
592 $inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\n");
594 $dialog = new QuestionHelper();
595 $dialog->setInputStream($inputStream);
596 $helperSet = new HelperSet(array(new FormatterHelper()));
597 $dialog->setHelperSet($helperSet);
599 $question = new Question('Please select a bundle', 'FrameworkBundle');
600 $question->setAutocompleterValues(array('AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle'));
602 $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
603 $this->assertEquals('AsseticBundleTest', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
604 $this->assertEquals('FrameworkBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
605 $this->assertEquals('SecurityBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
606 $this->assertEquals('FooBundleTest', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
607 $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
608 $this->assertEquals('AsseticBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
609 $this->assertEquals('FooBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
615 public function testLegacyAskWithAutocompleteWithNonSequentialKeys()
617 if (!$this->hasSttyAvailable()) {
618 $this->markTestSkipped('`stty` is required to test autocomplete functionality');
621 // <UP ARROW><UP ARROW><NEWLINE><DOWN ARROW><DOWN ARROW><NEWLINE>
622 $inputStream = $this->getInputStream("\033[A\033[A\n\033[B\033[B\n");
624 $dialog = new QuestionHelper();
625 $dialog->setInputStream($inputStream);
626 $dialog->setHelperSet(new HelperSet(array(new FormatterHelper())));
628 $question = new ChoiceQuestion('Please select a bundle', array(1 => 'AcmeDemoBundle', 4 => 'AsseticBundle'));
629 $question->setMaxAttempts(1);
631 $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
632 $this->assertEquals('AsseticBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
638 public function testLegacyAskHiddenResponse()
640 if ('\\' === DIRECTORY_SEPARATOR) {
641 $this->markTestSkipped('This test is not supported on Windows');
644 $dialog = new QuestionHelper();
645 $dialog->setInputStream($this->getInputStream("8AM\n"));
647 $question = new Question('What time is it?');
648 $question->setHidden(true);
650 $this->assertEquals('8AM', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
655 * @dataProvider getAskConfirmationData
657 public function testLegacyAskConfirmation($question, $expected, $default = true)
659 $dialog = new QuestionHelper();
661 $dialog->setInputStream($this->getInputStream($question."\n"));
662 $question = new ConfirmationQuestion('Do you like French fries?', $default);
663 $this->assertEquals($expected, $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question), 'confirmation question should '.($expected ? 'pass' : 'cancel'));
669 public function testLegacyAskConfirmationWithCustomTrueAnswer()
671 $dialog = new QuestionHelper();
673 $dialog->setInputStream($this->getInputStream("j\ny\n"));
674 $question = new ConfirmationQuestion('Do you like French fries?', false, '/^(j|y)/i');
675 $this->assertTrue($dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
676 $question = new ConfirmationQuestion('Do you like French fries?', false, '/^(j|y)/i');
677 $this->assertTrue($dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
683 public function testLegacyAskAndValidate()
685 $dialog = new QuestionHelper();
686 $helperSet = new HelperSet(array(new FormatterHelper()));
687 $dialog->setHelperSet($helperSet);
689 $error = 'This is not a color!';
690 $validator = function ($color) use ($error) {
691 if (!in_array($color, array('white', 'black'))) {
692 throw new \InvalidArgumentException($error);
698 $question = new Question('What color was the white horse of Henry IV?', 'white');
699 $question->setValidator($validator);
700 $question->setMaxAttempts(2);
702 $dialog->setInputStream($this->getInputStream("\nblack\n"));
703 $this->assertEquals('white', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
704 $this->assertEquals('black', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
706 $dialog->setInputStream($this->getInputStream("green\nyellow\norange\n"));
708 $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
710 } catch (\InvalidArgumentException $e) {
711 $this->assertEquals($error, $e->getMessage());
717 * @dataProvider simpleAnswerProvider
719 public function testLegacySelectChoiceFromSimpleChoices($providedAnswer, $expectedValue)
721 $possibleChoices = array(
727 $dialog = new QuestionHelper();
728 $dialog->setInputStream($this->getInputStream($providedAnswer."\n"));
729 $helperSet = new HelperSet(array(new FormatterHelper()));
730 $dialog->setHelperSet($helperSet);
732 $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
733 $question->setMaxAttempts(1);
734 $answer = $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
736 $this->assertSame($expectedValue, $answer);
741 * @dataProvider mixedKeysChoiceListAnswerProvider
743 public function testLegacyChoiceFromChoicelistWithMixedKeys($providedAnswer, $expectedValue)
745 $possibleChoices = array(
746 '0' => 'No environment',
747 '1' => 'My environment 1',
748 'env_2' => 'My environment 2',
749 3 => 'My environment 3',
752 $dialog = new QuestionHelper();
753 $dialog->setInputStream($this->getInputStream($providedAnswer."\n"));
754 $helperSet = new HelperSet(array(new FormatterHelper()));
755 $dialog->setHelperSet($helperSet);
757 $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
758 $question->setMaxAttempts(1);
759 $answer = $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
761 $this->assertSame($expectedValue, $answer);
766 * @dataProvider answerProvider
768 public function testLegacySelectChoiceFromChoiceList($providedAnswer, $expectedValue)
770 $possibleChoices = array(
771 'env_1' => 'My environment 1',
772 'env_2' => 'My environment',
773 'env_3' => 'My environment',
776 $dialog = new QuestionHelper();
777 $dialog->setInputStream($this->getInputStream($providedAnswer."\n"));
778 $helperSet = new HelperSet(array(new FormatterHelper()));
779 $dialog->setHelperSet($helperSet);
781 $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
782 $question->setMaxAttempts(1);
783 $answer = $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
785 $this->assertSame($expectedValue, $answer);
790 * @expectedException \InvalidArgumentException
791 * @expectedExceptionMessage The provided answer is ambiguous. Value should be one of env_2 or env_3.
793 public function testLegacyAmbiguousChoiceFromChoicelist()
795 $possibleChoices = array(
796 'env_1' => 'My first environment',
797 'env_2' => 'My environment',
798 'env_3' => 'My environment',
801 $dialog = new QuestionHelper();
802 $dialog->setInputStream($this->getInputStream("My environment\n"));
803 $helperSet = new HelperSet(array(new FormatterHelper()));
804 $dialog->setHelperSet($helperSet);
806 $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
807 $question->setMaxAttempts(1);
809 $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
813 * @requires function mb_strwidth
816 public function testLegacyChoiceOutputFormattingQuestionForUtf8Keys()
818 $question = 'Lorem ipsum?';
819 $possibleChoices = array(
824 $outputShown = array(
826 ' [<info>foo </info>] foo',
827 ' [<info>żółw </info>] bar',
828 ' [<info>łabądź</info>] baz',
830 $output = $this->getMockBuilder('\Symfony\Component\Console\Output\OutputInterface')->getMock();
831 $output->method('getFormatter')->willReturn(new OutputFormatter());
833 $dialog = new QuestionHelper();
834 $dialog->setInputStream($this->getInputStream("\n"));
835 $helperSet = new HelperSet(array(new FormatterHelper()));
836 $dialog->setHelperSet($helperSet);
838 $output->expects($this->once())->method('writeln')->with($this->equalTo($outputShown));
840 $question = new ChoiceQuestion($question, $possibleChoices, 'foo');
841 $dialog->ask($this->createInputInterfaceMock(), $output, $question);
845 * @expectedException \Symfony\Component\Console\Exception\RuntimeException
846 * @expectedExceptionMessage Aborted
848 public function testAskThrowsExceptionOnMissingInput()
850 $dialog = new QuestionHelper();
851 $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), new Question('What\'s your name?'));
855 * @expectedException \Symfony\Component\Console\Exception\RuntimeException
856 * @expectedExceptionMessage Aborted
858 public function testAskThrowsExceptionOnMissingInputWithValidator()
860 $dialog = new QuestionHelper();
862 $question = new Question('What\'s your name?');
863 $question->setValidator(function () {
865 throw new \Exception('A value is required.');
869 $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), $question);
873 * @expectedException \LogicException
874 * @expectedExceptionMessage Choice question must have at least 1 choice available.
876 public function testEmptyChoices()
878 new ChoiceQuestion('Question', array(), 'irrelevant');
881 public function testTraversableAutocomplete()
883 if (!$this->hasSttyAvailable()) {
884 $this->markTestSkipped('`stty` is required to test autocomplete functionality');
888 // Ac<BACKSPACE><BACKSPACE>s<TAB>Test<NEWLINE>
890 // <UP ARROW><UP ARROW><NEWLINE>
891 // <UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><TAB>Test<NEWLINE>
892 // <DOWN ARROW><NEWLINE>
893 // S<BACKSPACE><BACKSPACE><DOWN ARROW><DOWN ARROW><NEWLINE>
894 // F00<BACKSPACE><BACKSPACE>oo<TAB><NEWLINE>
895 $inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\n");
897 $dialog = new QuestionHelper();
898 $helperSet = new HelperSet(array(new FormatterHelper()));
899 $dialog->setHelperSet($helperSet);
901 $question = new Question('Please select a bundle', 'FrameworkBundle');
902 $question->setAutocompleterValues(new AutocompleteValues(array('irrelevant' => 'AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle')));
904 $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
905 $this->assertEquals('AsseticBundleTest', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
906 $this->assertEquals('FrameworkBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
907 $this->assertEquals('SecurityBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
908 $this->assertEquals('FooBundleTest', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
909 $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
910 $this->assertEquals('AsseticBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
911 $this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
914 protected function getInputStream($input)
916 $stream = fopen('php://memory', 'r+', false);
917 fwrite($stream, $input);
923 protected function createOutputInterface()
925 return new StreamOutput(fopen('php://memory', 'r+', false));
928 protected function createInputInterfaceMock($interactive = true)
930 $mock = $this->getMockBuilder('Symfony\Component\Console\Input\InputInterface')->getMock();
931 $mock->expects($this->any())
932 ->method('isInteractive')
933 ->will($this->returnValue($interactive));
938 private function hasSttyAvailable()
940 exec('stty 2>&1', $output, $exitcode);
942 return 0 === $exitcode;
946 class AutocompleteValues implements \IteratorAggregate
950 public function __construct(array $values)
952 $this->values = $values;
955 public function getIterator()
957 return new \ArrayIterator($this->values);