QuestionHelperTest.php 34 KB

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