Yaffs site version 1.1
[yaffs-website] / vendor / symfony / console / Tests / Helper / QuestionHelperTest.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\Console\Tests\Helper;
13
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\Console\Formatter\OutputFormatter;
16 use Symfony\Component\Console\Helper\QuestionHelper;
17 use Symfony\Component\Console\Helper\HelperSet;
18 use Symfony\Component\Console\Helper\FormatterHelper;
19 use Symfony\Component\Console\Output\StreamOutput;
20 use Symfony\Component\Console\Question\ChoiceQuestion;
21 use Symfony\Component\Console\Question\ConfirmationQuestion;
22 use Symfony\Component\Console\Question\Question;
23
24 /**
25  * @group tty
26  */
27 class QuestionHelperTest extends TestCase
28 {
29     public function testAskChoice()
30     {
31         $questionHelper = new QuestionHelper();
32
33         $helperSet = new HelperSet(array(new FormatterHelper()));
34         $questionHelper->setHelperSet($helperSet);
35
36         $heroes = array('Superman', 'Batman', 'Spiderman');
37
38         $questionHelper->setInputStream($this->getInputStream("\n1\n  1  \nFabien\n1\nFabien\n1\n0,2\n 0 , 2  \n\n\n"));
39
40         $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '2');
41         $question->setMaxAttempts(1);
42         // first answer is an empty answer, we're supposed to receive the default value
43         $this->assertEquals('Spiderman', $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
44
45         $question = new ChoiceQuestion('What is your favorite superhero?', $heroes);
46         $question->setMaxAttempts(1);
47         $this->assertEquals('Batman', $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
48         $this->assertEquals('Batman', $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
49
50         $question = new ChoiceQuestion('What is your favorite superhero?', $heroes);
51         $question->setErrorMessage('Input "%s" is not a superhero!');
52         $question->setMaxAttempts(2);
53         $this->assertEquals('Batman', $questionHelper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question));
54
55         rewind($output->getStream());
56         $stream = stream_get_contents($output->getStream());
57         $this->assertContains('Input "Fabien" is not a superhero!', $stream);
58
59         try {
60             $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '1');
61             $question->setMaxAttempts(1);
62             $questionHelper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question);
63             $this->fail();
64         } catch (\InvalidArgumentException $e) {
65             $this->assertEquals('Value "Fabien" is invalid', $e->getMessage());
66         }
67
68         $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, null);
69         $question->setMaxAttempts(1);
70         $question->setMultiselect(true);
71
72         $this->assertEquals(array('Batman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
73         $this->assertEquals(array('Superman', 'Spiderman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
74         $this->assertEquals(array('Superman', 'Spiderman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
75
76         $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '0,1');
77         $question->setMaxAttempts(1);
78         $question->setMultiselect(true);
79
80         $this->assertEquals(array('Superman', 'Batman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
81
82         $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, ' 0 , 1 ');
83         $question->setMaxAttempts(1);
84         $question->setMultiselect(true);
85
86         $this->assertEquals(array('Superman', 'Batman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
87     }
88
89     public function testAsk()
90     {
91         $dialog = new QuestionHelper();
92
93         $dialog->setInputStream($this->getInputStream("\n8AM\n"));
94
95         $question = new Question('What time is it?', '2PM');
96         $this->assertEquals('2PM', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
97
98         $question = new Question('What time is it?', '2PM');
99         $this->assertEquals('8AM', $dialog->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question));
100
101         rewind($output->getStream());
102         $this->assertEquals('What time is it?', stream_get_contents($output->getStream()));
103     }
104
105     public function testAskWithAutocomplete()
106     {
107         if (!$this->hasSttyAvailable()) {
108             $this->markTestSkipped('`stty` is required to test autocomplete functionality');
109         }
110
111         // Acm<NEWLINE>
112         // Ac<BACKSPACE><BACKSPACE>s<TAB>Test<NEWLINE>
113         // <NEWLINE>
114         // <UP ARROW><UP ARROW><NEWLINE>
115         // <UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><TAB>Test<NEWLINE>
116         // <DOWN ARROW><NEWLINE>
117         // S<BACKSPACE><BACKSPACE><DOWN ARROW><DOWN ARROW><NEWLINE>
118         // F00<BACKSPACE><BACKSPACE>oo<TAB><NEWLINE>
119         $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");
120
121         $dialog = new QuestionHelper();
122         $dialog->setInputStream($inputStream);
123         $helperSet = new HelperSet(array(new FormatterHelper()));
124         $dialog->setHelperSet($helperSet);
125
126         $question = new Question('Please select a bundle', 'FrameworkBundle');
127         $question->setAutocompleterValues(array('AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle'));
128
129         $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
130         $this->assertEquals('AsseticBundleTest', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
131         $this->assertEquals('FrameworkBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
132         $this->assertEquals('SecurityBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
133         $this->assertEquals('FooBundleTest', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
134         $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
135         $this->assertEquals('AsseticBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
136         $this->assertEquals('FooBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
137     }
138
139     public function testAskWithAutocompleteWithNonSequentialKeys()
140     {
141         if (!$this->hasSttyAvailable()) {
142             $this->markTestSkipped('`stty` is required to test autocomplete functionality');
143         }
144
145         // <UP ARROW><UP ARROW><NEWLINE><DOWN ARROW><DOWN ARROW><NEWLINE>
146         $inputStream = $this->getInputStream("\033[A\033[A\n\033[B\033[B\n");
147
148         $dialog = new QuestionHelper();
149         $dialog->setInputStream($inputStream);
150         $dialog->setHelperSet(new HelperSet(array(new FormatterHelper())));
151
152         $question = new ChoiceQuestion('Please select a bundle', array(1 => 'AcmeDemoBundle', 4 => 'AsseticBundle'));
153         $question->setMaxAttempts(1);
154
155         $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
156         $this->assertEquals('AsseticBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
157     }
158
159     public function testAskHiddenResponse()
160     {
161         if ('\\' === DIRECTORY_SEPARATOR) {
162             $this->markTestSkipped('This test is not supported on Windows');
163         }
164
165         $dialog = new QuestionHelper();
166         $dialog->setInputStream($this->getInputStream("8AM\n"));
167
168         $question = new Question('What time is it?');
169         $question->setHidden(true);
170
171         $this->assertEquals('8AM', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
172     }
173
174     /**
175      * @dataProvider getAskConfirmationData
176      */
177     public function testAskConfirmation($question, $expected, $default = true)
178     {
179         $dialog = new QuestionHelper();
180
181         $dialog->setInputStream($this->getInputStream($question."\n"));
182         $question = new ConfirmationQuestion('Do you like French fries?', $default);
183         $this->assertEquals($expected, $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question), 'confirmation question should '.($expected ? 'pass' : 'cancel'));
184     }
185
186     public function getAskConfirmationData()
187     {
188         return array(
189             array('', true),
190             array('', false, false),
191             array('y', true),
192             array('yes', true),
193             array('n', false),
194             array('no', false),
195         );
196     }
197
198     public function testAskConfirmationWithCustomTrueAnswer()
199     {
200         $dialog = new QuestionHelper();
201
202         $dialog->setInputStream($this->getInputStream("j\ny\n"));
203         $question = new ConfirmationQuestion('Do you like French fries?', false, '/^(j|y)/i');
204         $this->assertTrue($dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
205         $question = new ConfirmationQuestion('Do you like French fries?', false, '/^(j|y)/i');
206         $this->assertTrue($dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
207     }
208
209     public function testAskAndValidate()
210     {
211         $dialog = new QuestionHelper();
212         $helperSet = new HelperSet(array(new FormatterHelper()));
213         $dialog->setHelperSet($helperSet);
214
215         $error = 'This is not a color!';
216         $validator = function ($color) use ($error) {
217             if (!in_array($color, array('white', 'black'))) {
218                 throw new \InvalidArgumentException($error);
219             }
220
221             return $color;
222         };
223
224         $question = new Question('What color was the white horse of Henry IV?', 'white');
225         $question->setValidator($validator);
226         $question->setMaxAttempts(2);
227
228         $dialog->setInputStream($this->getInputStream("\nblack\n"));
229         $this->assertEquals('white', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
230         $this->assertEquals('black', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
231
232         $dialog->setInputStream($this->getInputStream("green\nyellow\norange\n"));
233         try {
234             $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
235             $this->fail();
236         } catch (\InvalidArgumentException $e) {
237             $this->assertEquals($error, $e->getMessage());
238         }
239     }
240
241     /**
242      * @dataProvider simpleAnswerProvider
243      */
244     public function testSelectChoiceFromSimpleChoices($providedAnswer, $expectedValue)
245     {
246         $possibleChoices = array(
247             'My environment 1',
248             'My environment 2',
249             'My environment 3',
250         );
251
252         $dialog = new QuestionHelper();
253         $dialog->setInputStream($this->getInputStream($providedAnswer."\n"));
254         $helperSet = new HelperSet(array(new FormatterHelper()));
255         $dialog->setHelperSet($helperSet);
256
257         $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
258         $question->setMaxAttempts(1);
259         $answer = $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
260
261         $this->assertSame($expectedValue, $answer);
262     }
263
264     public function simpleAnswerProvider()
265     {
266         return array(
267             array(0, 'My environment 1'),
268             array(1, 'My environment 2'),
269             array(2, 'My environment 3'),
270             array('My environment 1', 'My environment 1'),
271             array('My environment 2', 'My environment 2'),
272             array('My environment 3', 'My environment 3'),
273         );
274     }
275
276     /**
277      * @dataProvider specialCharacterInMultipleChoice
278      */
279     public function testSpecialCharacterChoiceFromMultipleChoiceList($providedAnswer, $expectedValue)
280     {
281         $possibleChoices = array(
282             '.',
283             'src',
284         );
285
286         $dialog = new QuestionHelper();
287         $dialog->setInputStream($this->getInputStream($providedAnswer."\n"));
288         $helperSet = new HelperSet(array(new FormatterHelper()));
289         $dialog->setHelperSet($helperSet);
290
291         $question = new ChoiceQuestion('Please select the directory', $possibleChoices);
292         $question->setMaxAttempts(1);
293         $question->setMultiselect(true);
294         $answer = $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
295
296         $this->assertSame($expectedValue, $answer);
297     }
298
299     public function specialCharacterInMultipleChoice()
300     {
301         return array(
302             array('.', array('.')),
303             array('., src', array('.', 'src')),
304         );
305     }
306
307     /**
308      * @dataProvider mixedKeysChoiceListAnswerProvider
309      */
310     public function testChoiceFromChoicelistWithMixedKeys($providedAnswer, $expectedValue)
311     {
312         $possibleChoices = array(
313             '0' => 'No environment',
314             '1' => 'My environment 1',
315             'env_2' => 'My environment 2',
316             3 => 'My environment 3',
317         );
318
319         $dialog = new QuestionHelper();
320         $dialog->setInputStream($this->getInputStream($providedAnswer."\n"));
321         $helperSet = new HelperSet(array(new FormatterHelper()));
322         $dialog->setHelperSet($helperSet);
323
324         $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
325         $question->setMaxAttempts(1);
326         $answer = $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
327
328         $this->assertSame($expectedValue, $answer);
329     }
330
331     public function mixedKeysChoiceListAnswerProvider()
332     {
333         return array(
334             array('0', '0'),
335             array('No environment', '0'),
336             array('1', '1'),
337             array('env_2', 'env_2'),
338             array(3, '3'),
339             array('My environment 1', '1'),
340         );
341     }
342
343     /**
344      * @dataProvider answerProvider
345      */
346     public function testSelectChoiceFromChoiceList($providedAnswer, $expectedValue)
347     {
348         $possibleChoices = array(
349             'env_1' => 'My environment 1',
350             'env_2' => 'My environment',
351             'env_3' => 'My environment',
352         );
353
354         $dialog = new QuestionHelper();
355         $dialog->setInputStream($this->getInputStream($providedAnswer."\n"));
356         $helperSet = new HelperSet(array(new FormatterHelper()));
357         $dialog->setHelperSet($helperSet);
358
359         $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
360         $question->setMaxAttempts(1);
361         $answer = $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
362
363         $this->assertSame($expectedValue, $answer);
364     }
365
366     /**
367      * @expectedException        \InvalidArgumentException
368      * @expectedExceptionMessage The provided answer is ambiguous. Value should be one of env_2 or env_3.
369      */
370     public function testAmbiguousChoiceFromChoicelist()
371     {
372         $possibleChoices = array(
373             'env_1' => 'My first environment',
374             'env_2' => 'My environment',
375             'env_3' => 'My environment',
376         );
377
378         $dialog = new QuestionHelper();
379         $dialog->setInputStream($this->getInputStream("My environment\n"));
380         $helperSet = new HelperSet(array(new FormatterHelper()));
381         $dialog->setHelperSet($helperSet);
382
383         $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
384         $question->setMaxAttempts(1);
385
386         $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
387     }
388
389     public function answerProvider()
390     {
391         return array(
392             array('env_1', 'env_1'),
393             array('env_2', 'env_2'),
394             array('env_3', 'env_3'),
395             array('My environment 1', 'env_1'),
396         );
397     }
398
399     public function testNoInteraction()
400     {
401         $dialog = new QuestionHelper();
402         $question = new Question('Do you have a job?', 'not yet');
403         $this->assertEquals('not yet', $dialog->ask($this->createInputInterfaceMock(false), $this->createOutputInterface(), $question));
404     }
405
406     /**
407      * @requires function mb_strwidth
408      */
409     public function testChoiceOutputFormattingQuestionForUtf8Keys()
410     {
411         $question = 'Lorem ipsum?';
412         $possibleChoices = array(
413             'foo' => 'foo',
414             'żółw' => 'bar',
415             'łabądź' => 'baz',
416         );
417         $outputShown = array(
418             $question,
419             '  [<info>foo   </info>] foo',
420             '  [<info>żółw  </info>] bar',
421             '  [<info>łabądź</info>] baz',
422         );
423         $output = $this->getMockBuilder('\Symfony\Component\Console\Output\OutputInterface')->getMock();
424         $output->method('getFormatter')->willReturn(new OutputFormatter());
425
426         $dialog = new QuestionHelper();
427         $dialog->setInputStream($this->getInputStream("\n"));
428         $helperSet = new HelperSet(array(new FormatterHelper()));
429         $dialog->setHelperSet($helperSet);
430
431         $output->expects($this->once())->method('writeln')->with($this->equalTo($outputShown));
432
433         $question = new ChoiceQuestion($question, $possibleChoices, 'foo');
434         $dialog->ask($this->createInputInterfaceMock(), $output, $question);
435     }
436
437     /**
438      * @expectedException        \Symfony\Component\Console\Exception\RuntimeException
439      * @expectedExceptionMessage Aborted
440      */
441     public function testAskThrowsExceptionOnMissingInput()
442     {
443         $dialog = new QuestionHelper();
444         $dialog->setInputStream($this->getInputStream(''));
445
446         $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), new Question('What\'s your name?'));
447     }
448
449     /**
450      * @expectedException        \Symfony\Component\Console\Exception\RuntimeException
451      * @expectedExceptionMessage Aborted
452      */
453     public function testAskThrowsExceptionOnMissingInputWithValidator()
454     {
455         $dialog = new QuestionHelper();
456         $dialog->setInputStream($this->getInputStream(''));
457
458         $question = new Question('What\'s your name?');
459         $question->setValidator(function () {
460             if (!$value) {
461                 throw new \Exception('A value is required.');
462             }
463         });
464
465         $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
466     }
467
468     /**
469      * @expectedException \LogicException
470      * @expectedExceptionMessage Choice question must have at least 1 choice available.
471      */
472     public function testEmptyChoices()
473     {
474         new ChoiceQuestion('Question', array(), 'irrelevant');
475     }
476
477     protected function getInputStream($input)
478     {
479         $stream = fopen('php://memory', 'r+', false);
480         fwrite($stream, $input);
481         rewind($stream);
482
483         return $stream;
484     }
485
486     protected function createOutputInterface()
487     {
488         return new StreamOutput(fopen('php://memory', 'r+', false));
489     }
490
491     protected function createInputInterfaceMock($interactive = true)
492     {
493         $mock = $this->getMockBuilder('Symfony\Component\Console\Input\InputInterface')->getMock();
494         $mock->expects($this->any())
495             ->method('isInteractive')
496             ->will($this->returnValue($interactive));
497
498         return $mock;
499     }
500
501     private function hasSttyAvailable()
502     {
503         exec('stty 2>&1', $output, $exitcode);
504
505         return $exitcode === 0;
506     }
507 }