TYPO3  7.6
ApplicationTest.php
Go to the documentation of this file.
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;
13 
31 use Symfony\Component\EventDispatcher\EventDispatcher;
32 
33 class ApplicationTest extends \PHPUnit_Framework_TestCase
34 {
35  protected static $fixturesPath;
36 
37  public static function setUpBeforeClass()
38  {
39  self::$fixturesPath = realpath(__DIR__.'/Fixtures/');
40  require_once self::$fixturesPath.'/FooCommand.php';
41  require_once self::$fixturesPath.'/Foo1Command.php';
42  require_once self::$fixturesPath.'/Foo2Command.php';
43  require_once self::$fixturesPath.'/Foo3Command.php';
44  require_once self::$fixturesPath.'/Foo4Command.php';
45  require_once self::$fixturesPath.'/Foo5Command.php';
46  require_once self::$fixturesPath.'/FoobarCommand.php';
47  require_once self::$fixturesPath.'/BarBucCommand.php';
48  require_once self::$fixturesPath.'/FooSubnamespaced1Command.php';
49  require_once self::$fixturesPath.'/FooSubnamespaced2Command.php';
50  }
51 
52  protected function normalizeLineBreaks($text)
53  {
54  return str_replace(PHP_EOL, "\n", $text);
55  }
56 
62  protected function ensureStaticCommandHelp(Application $application)
63  {
64  foreach ($application->all() as $command) {
65  $command->setHelp(str_replace('%command.full_name%', 'app/console %command.name%', $command->getHelp()));
66  }
67  }
68 
69  public function testConstructor()
70  {
71  $application = new Application('foo', 'bar');
72  $this->assertEquals('foo', $application->getName(), '__construct() takes the application name as its first argument');
73  $this->assertEquals('bar', $application->getVersion(), '__construct() takes the application version as its second argument');
74  $this->assertEquals(array('help', 'list'), array_keys($application->all()), '__construct() registered the help and list commands by default');
75  }
76 
77  public function testSetGetName()
78  {
79  $application = new Application();
80  $application->setName('foo');
81  $this->assertEquals('foo', $application->getName(), '->setName() sets the name of the application');
82  }
83 
84  public function testSetGetVersion()
85  {
86  $application = new Application();
87  $application->setVersion('bar');
88  $this->assertEquals('bar', $application->getVersion(), '->setVersion() sets the version of the application');
89  }
90 
91  public function testGetLongVersion()
92  {
93  $application = new Application('foo', 'bar');
94  $this->assertEquals('<info>foo</info> version <comment>bar</comment>', $application->getLongVersion(), '->getLongVersion() returns the long version of the application');
95  }
96 
97  public function testHelp()
98  {
99  $application = new Application();
100  $this->assertStringEqualsFile(self::$fixturesPath.'/application_gethelp.txt', $this->normalizeLineBreaks($application->getHelp()), '->getHelp() returns a help message');
101  }
102 
103  public function testAll()
104  {
105  $application = new Application();
106  $commands = $application->all();
107  $this->assertInstanceOf('Symfony\\Component\\Console\\Command\\HelpCommand', $commands['help'], '->all() returns the registered commands');
108 
109  $application->add(new \FooCommand());
110  $commands = $application->all('foo');
111  $this->assertCount(1, $commands, '->all() takes a namespace as its first argument');
112  }
113 
114  public function testRegister()
115  {
116  $application = new Application();
117  $command = $application->register('foo');
118  $this->assertEquals('foo', $command->getName(), '->register() registers a new command');
119  }
120 
121  public function testAdd()
122  {
123  $application = new Application();
124  $application->add($foo = new \FooCommand());
125  $commands = $application->all();
126  $this->assertEquals($foo, $commands['foo:bar'], '->add() registers a command');
127 
128  $application = new Application();
129  $application->addCommands(array($foo = new \FooCommand(), $foo1 = new \Foo1Command()));
130  $commands = $application->all();
131  $this->assertEquals(array($foo, $foo1), array($commands['foo:bar'], $commands['foo:bar1']), '->addCommands() registers an array of commands');
132  }
133 
139  {
140  $application = new Application();
141  $application->add(new \Foo5Command());
142  }
143 
144  public function testHasGet()
145  {
146  $application = new Application();
147  $this->assertTrue($application->has('list'), '->has() returns true if a named command is registered');
148  $this->assertFalse($application->has('afoobar'), '->has() returns false if a named command is not registered');
149 
150  $application->add($foo = new \FooCommand());
151  $this->assertTrue($application->has('afoobar'), '->has() returns true if an alias is registered');
152  $this->assertEquals($foo, $application->get('foo:bar'), '->get() returns a command by name');
153  $this->assertEquals($foo, $application->get('afoobar'), '->get() returns a command by alias');
154 
155  $application = new Application();
156  $application->add($foo = new \FooCommand());
157  // simulate --help
158  $r = new \ReflectionObject($application);
159  $p = $r->getProperty('wantHelps');
160  $p->setAccessible(true);
161  $p->setValue($application, true);
162  $command = $application->get('foo:bar');
163  $this->assertInstanceOf('Symfony\Component\Console\Command\HelpCommand', $command, '->get() returns the help command if --help is provided as the input');
164  }
165 
166  public function testSilentHelp()
167  {
168  $application = new Application();
169  $application->setAutoExit(false);
170  $application->setCatchExceptions(false);
171 
172  $tester = new ApplicationTester($application);
173  $tester->run(array('-h' => true, '-q' => true), array('decorated' => false));
174 
175  $this->assertEmpty($tester->getDisplay(true));
176  }
177 
182  public function testGetInvalidCommand()
183  {
184  $application = new Application();
185  $application->get('foofoo');
186  }
187 
188  public function testGetNamespaces()
189  {
190  $application = new Application();
191  $application->add(new \FooCommand());
192  $application->add(new \Foo1Command());
193  $this->assertEquals(array('foo'), $application->getNamespaces(), '->getNamespaces() returns an array of unique used namespaces');
194  }
195 
196  public function testFindNamespace()
197  {
198  $application = new Application();
199  $application->add(new \FooCommand());
200  $this->assertEquals('foo', $application->findNamespace('foo'), '->findNamespace() returns the given namespace if it exists');
201  $this->assertEquals('foo', $application->findNamespace('f'), '->findNamespace() finds a namespace given an abbreviation');
202  $application->add(new \Foo2Command());
203  $this->assertEquals('foo', $application->findNamespace('foo'), '->findNamespace() returns the given namespace if it exists');
204  }
205 
207  {
208  $application = new Application();
209  $application->add(new \FooSubnamespaced1Command());
210  $application->add(new \FooSubnamespaced2Command());
211  $this->assertEquals('foo', $application->findNamespace('foo'), '->findNamespace() returns commands even if the commands are only contained in subnamespaces');
212  }
213 
218  public function testFindAmbiguousNamespace()
219  {
220  $application = new Application();
221  $application->add(new \BarBucCommand());
222  $application->add(new \FooCommand());
223  $application->add(new \Foo2Command());
224  $application->findNamespace('f');
225  }
226 
231  public function testFindInvalidNamespace()
232  {
233  $application = new Application();
234  $application->findNamespace('bar');
235  }
236 
242  {
243  $application = new Application();
244  $application->add(new \FooCommand());
245  $application->add(new \Foo1Command());
246  $application->add(new \Foo2Command());
247 
248  $application->find($commandName = 'foo1');
249  }
250 
251  public function testFind()
252  {
253  $application = new Application();
254  $application->add(new \FooCommand());
255 
256  $this->assertInstanceOf('FooCommand', $application->find('foo:bar'), '->find() returns a command if its name exists');
257  $this->assertInstanceOf('Symfony\Component\Console\Command\HelpCommand', $application->find('h'), '->find() returns a command if its name exists');
258  $this->assertInstanceOf('FooCommand', $application->find('f:bar'), '->find() returns a command if the abbreviation for the namespace exists');
259  $this->assertInstanceOf('FooCommand', $application->find('f:b'), '->find() returns a command if the abbreviation for the namespace and the command name exist');
260  $this->assertInstanceOf('FooCommand', $application->find('a'), '->find() returns a command if the abbreviation exists for an alias');
261  }
262 
266  public function testFindWithAmbiguousAbbreviations($abbreviation, $expectedExceptionMessage)
267  {
268  $this->setExpectedException('InvalidArgumentException', $expectedExceptionMessage);
269 
270  $application = new Application();
271  $application->add(new \FooCommand());
272  $application->add(new \Foo1Command());
273  $application->add(new \Foo2Command());
274 
275  $application->find($abbreviation);
276  }
277 
279  {
280  return array(
281  array('f', 'Command "f" is not defined.'),
282  array('a', 'Command "a" is ambiguous (afoobar, afoobar1 and 1 more).'),
283  array('foo:b', 'Command "foo:b" is ambiguous (foo:bar, foo:bar1 and 1 more).'),
284  );
285  }
286 
288  {
289  $application = new Application();
290  $application->add(new \Foo3Command());
291  $application->add(new \Foo4Command());
292 
293  $this->assertInstanceOf('Foo3Command', $application->find('foo3:bar'), '->find() returns the good command even if a namespace has same name');
294  $this->assertInstanceOf('Foo4Command', $application->find('foo3:bar:toh'), '->find() returns a command even if its namespace equals another command name');
295  }
296 
298  {
299  $application = new Application();
300  $application->add(new \FooCommand());
301  $application->add(new \FoobarCommand());
302 
303  $this->assertInstanceOf('FoobarCommand', $application->find('f:f'));
304  }
305 
307  {
308  $application = new Application();
309  $application->add(new \Foo4Command());
310 
311  $this->assertInstanceOf('Foo4Command', $application->find('f::t'));
312  }
313 
320  {
321  $application = new Application();
322  $application->add(new \Foo3Command());
323  $application->find($name);
324  }
325 
327  {
328  return array(
329  array('foo3:baR'),
330  array('foO3:bar'),
331  );
332  }
333 
335  {
336  $application = new Application();
337  $application->add(new \FooCommand());
338  $application->add(new \Foo1Command());
339  $application->add(new \Foo2Command());
340 
341  // Command + plural
342  try {
343  $application->find('foo:baR');
344  $this->fail('->find() throws an \InvalidArgumentException if command does not exist, with alternatives');
345  } catch (\Exception $e) {
346  $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if command does not exist, with alternatives');
347  $this->assertRegExp('/Did you mean one of these/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternatives');
348  $this->assertRegExp('/foo1:bar/', $e->getMessage());
349  $this->assertRegExp('/foo:bar/', $e->getMessage());
350  }
351 
352  // Namespace + plural
353  try {
354  $application->find('foo2:bar');
355  $this->fail('->find() throws an \InvalidArgumentException if command does not exist, with alternatives');
356  } catch (\Exception $e) {
357  $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if command does not exist, with alternatives');
358  $this->assertRegExp('/Did you mean one of these/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternatives');
359  $this->assertRegExp('/foo1/', $e->getMessage());
360  }
361 
362  $application->add(new \Foo3Command());
363  $application->add(new \Foo4Command());
364 
365  // Subnamespace + plural
366  try {
367  $a = $application->find('foo3:');
368  $this->fail('->find() should throw an \InvalidArgumentException if a command is ambiguous because of a subnamespace, with alternatives');
369  } catch (\Exception $e) {
370  $this->assertInstanceOf('\InvalidArgumentException', $e);
371  $this->assertRegExp('/foo3:bar/', $e->getMessage());
372  $this->assertRegExp('/foo3:bar:toh/', $e->getMessage());
373  }
374  }
375 
376  public function testFindAlternativeCommands()
377  {
378  $application = new Application();
379 
380  $application->add(new \FooCommand());
381  $application->add(new \Foo1Command());
382  $application->add(new \Foo2Command());
383 
384  try {
385  $application->find($commandName = 'Unknown command');
386  $this->fail('->find() throws an \InvalidArgumentException if command does not exist');
387  } catch (\Exception $e) {
388  $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if command does not exist');
389  $this->assertEquals(sprintf('Command "%s" is not defined.', $commandName), $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, without alternatives');
390  }
391 
392  // Test if "bar1" command throw an "\InvalidArgumentException" and does not contain
393  // "foo:bar" as alternative because "bar1" is too far from "foo:bar"
394  try {
395  $application->find($commandName = 'bar1');
396  $this->fail('->find() throws an \InvalidArgumentException if command does not exist');
397  } catch (\Exception $e) {
398  $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if command does not exist');
399  $this->assertRegExp(sprintf('/Command "%s" is not defined./', $commandName), $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternatives');
400  $this->assertRegExp('/afoobar1/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternative : "afoobar1"');
401  $this->assertRegExp('/foo:bar1/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternative : "foo:bar1"');
402  $this->assertNotRegExp('/foo:bar(?>!1)/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, without "foo:bar" alternative');
403  }
404  }
405 
407  {
408  $fooCommand = new \FooCommand();
409  $fooCommand->setAliases(array('foo2'));
410 
411  $application = new Application();
412  $application->add($fooCommand);
413 
414  $result = $application->find('foo');
415 
416  $this->assertSame($fooCommand, $result);
417  }
418 
420  {
421  $application = new Application();
422 
423  $application->add(new \FooCommand());
424  $application->add(new \Foo1Command());
425  $application->add(new \Foo2Command());
426  $application->add(new \foo3Command());
427 
428  try {
429  $application->find('Unknown-namespace:Unknown-command');
430  $this->fail('->find() throws an \InvalidArgumentException if namespace does not exist');
431  } catch (\Exception $e) {
432  $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if namespace does not exist');
433  $this->assertEquals('There are no commands defined in the "Unknown-namespace" namespace.', $e->getMessage(), '->find() throws an \InvalidArgumentException if namespace does not exist, without alternatives');
434  }
435 
436  try {
437  $application->find('foo2:command');
438  $this->fail('->find() throws an \InvalidArgumentException if namespace does not exist');
439  } catch (\Exception $e) {
440  $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if namespace does not exist');
441  $this->assertRegExp('/There are no commands defined in the "foo2" namespace./', $e->getMessage(), '->find() throws an \InvalidArgumentException if namespace does not exist, with alternative');
442  $this->assertRegExp('/foo/', $e->getMessage(), '->find() throws an \InvalidArgumentException if namespace does not exist, with alternative : "foo"');
443  $this->assertRegExp('/foo1/', $e->getMessage(), '->find() throws an \InvalidArgumentException if namespace does not exist, with alternative : "foo1"');
444  $this->assertRegExp('/foo3/', $e->getMessage(), '->find() throws an \InvalidArgumentException if namespace does not exist, with alternative : "foo3"');
445  }
446  }
447 
449  {
450  $application = $this->getMock('Symfony\Component\Console\Application', array('getNamespaces'));
451  $application->expects($this->once())
452  ->method('getNamespaces')
453  ->will($this->returnValue(array('foo:sublong', 'bar:sub')));
454 
455  $this->assertEquals('foo:sublong', $application->findNamespace('f:sub'));
456  }
457 
463  {
464  $application = new Application();
465  $application->add(new \FooCommand());
466  $application->add(new \Foo4Command());
467  $application->find('foo::bar');
468  }
469 
470  public function testSetCatchExceptions()
471  {
472  $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth'));
473  $application->setAutoExit(false);
474  $application->expects($this->any())
475  ->method('getTerminalWidth')
476  ->will($this->returnValue(120));
477  $tester = new ApplicationTester($application);
478 
479  $application->setCatchExceptions(true);
480  $tester->run(array('command' => 'foo'), array('decorated' => false));
481  $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception1.txt', $tester->getDisplay(true), '->setCatchExceptions() sets the catch exception flag');
482 
483  $application->setCatchExceptions(false);
484  try {
485  $tester->run(array('command' => 'foo'), array('decorated' => false));
486  $this->fail('->setCatchExceptions() sets the catch exception flag');
487  } catch (\Exception $e) {
488  $this->assertInstanceOf('\Exception', $e, '->setCatchExceptions() sets the catch exception flag');
489  $this->assertEquals('Command "foo" is not defined.', $e->getMessage(), '->setCatchExceptions() sets the catch exception flag');
490  }
491  }
492 
496  public function testLegacyAsText()
497  {
498  $application = new Application();
499  $application->add(new \FooCommand());
500  $this->ensureStaticCommandHelp($application);
501  $this->assertStringEqualsFile(self::$fixturesPath.'/application_astext1.txt', $this->normalizeLineBreaks($application->asText()), '->asText() returns a text representation of the application');
502  $this->assertStringEqualsFile(self::$fixturesPath.'/application_astext2.txt', $this->normalizeLineBreaks($application->asText('foo')), '->asText() returns a text representation of the application');
503  }
504 
508  public function testLegacyAsXml()
509  {
510  $application = new Application();
511  $application->add(new \FooCommand());
512  $this->ensureStaticCommandHelp($application);
513  $this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/application_asxml1.txt', $application->asXml(), '->asXml() returns an XML representation of the application');
514  $this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/application_asxml2.txt', $application->asXml('foo'), '->asXml() returns an XML representation of the application');
515  }
516 
517  public function testRenderException()
518  {
519  $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth'));
520  $application->setAutoExit(false);
521  $application->expects($this->any())
522  ->method('getTerminalWidth')
523  ->will($this->returnValue(120));
524  $tester = new ApplicationTester($application);
525 
526  $tester->run(array('command' => 'foo'), array('decorated' => false));
527  $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception1.txt', $tester->getDisplay(true), '->renderException() renders a pretty exception');
528 
529  $tester->run(array('command' => 'foo'), array('decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE));
530  $this->assertContains('Exception trace', $tester->getDisplay(), '->renderException() renders a pretty exception with a stack trace when verbosity is verbose');
531 
532  $tester->run(array('command' => 'list', '--foo' => true), array('decorated' => false));
533  $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception2.txt', $tester->getDisplay(true), '->renderException() renders the command synopsis when an exception occurs in the context of a command');
534 
535  $application->add(new \Foo3Command());
536  $tester = new ApplicationTester($application);
537  $tester->run(array('command' => 'foo3:bar'), array('decorated' => false));
538  $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception3.txt', $tester->getDisplay(true), '->renderException() renders a pretty exceptions with previous exceptions');
539 
540  $tester->run(array('command' => 'foo3:bar'), array('decorated' => true));
541  $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception3decorated.txt', $tester->getDisplay(true), '->renderException() renders a pretty exceptions with previous exceptions');
542 
543  $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth'));
544  $application->setAutoExit(false);
545  $application->expects($this->any())
546  ->method('getTerminalWidth')
547  ->will($this->returnValue(32));
548  $tester = new ApplicationTester($application);
549 
550  $tester->run(array('command' => 'foo'), array('decorated' => false));
551  $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception4.txt', $tester->getDisplay(true), '->renderException() wraps messages when they are bigger than the terminal');
552  }
553 
555  {
556  if (!function_exists('mb_strwidth')) {
557  $this->markTestSkipped('The "mb_strwidth" function is not available');
558  }
559 
560  $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth'));
561  $application->setAutoExit(false);
562  $application->expects($this->any())
563  ->method('getTerminalWidth')
564  ->will($this->returnValue(120));
565  $application->register('foo')->setCode(function () {
566  throw new \Exception('エラーメッセージ');
567  });
568  $tester = new ApplicationTester($application);
569 
570  $tester->run(array('command' => 'foo'), array('decorated' => false));
571  $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth1.txt', $tester->getDisplay(true), '->renderException() renders a pretty exceptions with previous exceptions');
572 
573  $tester->run(array('command' => 'foo'), array('decorated' => true));
574  $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth1decorated.txt', $tester->getDisplay(true), '->renderException() renders a pretty exceptions with previous exceptions');
575 
576  $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth'));
577  $application->setAutoExit(false);
578  $application->expects($this->any())
579  ->method('getTerminalWidth')
580  ->will($this->returnValue(32));
581  $application->register('foo')->setCode(function () {
582  throw new \Exception('コマンドの実行中にエラーが発生しました。');
583  });
584  $tester = new ApplicationTester($application);
585  $tester->run(array('command' => 'foo'), array('decorated' => false));
586  $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth2.txt', $tester->getDisplay(true), '->renderException() wraps messages when they are bigger than the terminal');
587  }
588 
589  public function testRun()
590  {
591  $application = new Application();
592  $application->setAutoExit(false);
593  $application->setCatchExceptions(false);
594  $application->add($command = new \Foo1Command());
595  $_SERVER['argv'] = array('cli.php', 'foo:bar1');
596 
597  ob_start();
598  $application->run();
599  ob_end_clean();
600 
601  $this->assertInstanceOf('Symfony\Component\Console\Input\ArgvInput', $command->input, '->run() creates an ArgvInput by default if none is given');
602  $this->assertInstanceOf('Symfony\Component\Console\Output\ConsoleOutput', $command->output, '->run() creates a ConsoleOutput by default if none is given');
603 
604  $application = new Application();
605  $application->setAutoExit(false);
606  $application->setCatchExceptions(false);
607 
608  $this->ensureStaticCommandHelp($application);
609  $tester = new ApplicationTester($application);
610 
611  $tester->run(array(), array('decorated' => false));
612  $this->assertStringEqualsFile(self::$fixturesPath.'/application_run1.txt', $tester->getDisplay(true), '->run() runs the list command if no argument is passed');
613 
614  $tester->run(array('--help' => true), array('decorated' => false));
615  $this->assertStringEqualsFile(self::$fixturesPath.'/application_run2.txt', $tester->getDisplay(true), '->run() runs the help command if --help is passed');
616 
617  $tester->run(array('-h' => true), array('decorated' => false));
618  $this->assertStringEqualsFile(self::$fixturesPath.'/application_run2.txt', $tester->getDisplay(true), '->run() runs the help command if -h is passed');
619 
620  $tester->run(array('command' => 'list', '--help' => true), array('decorated' => false));
621  $this->assertStringEqualsFile(self::$fixturesPath.'/application_run3.txt', $tester->getDisplay(true), '->run() displays the help if --help is passed');
622 
623  $tester->run(array('command' => 'list', '-h' => true), array('decorated' => false));
624  $this->assertStringEqualsFile(self::$fixturesPath.'/application_run3.txt', $tester->getDisplay(true), '->run() displays the help if -h is passed');
625 
626  $tester->run(array('--ansi' => true));
627  $this->assertTrue($tester->getOutput()->isDecorated(), '->run() forces color output if --ansi is passed');
628 
629  $tester->run(array('--no-ansi' => true));
630  $this->assertFalse($tester->getOutput()->isDecorated(), '->run() forces color output to be disabled if --no-ansi is passed');
631 
632  $tester->run(array('--version' => true), array('decorated' => false));
633  $this->assertStringEqualsFile(self::$fixturesPath.'/application_run4.txt', $tester->getDisplay(true), '->run() displays the program version if --version is passed');
634 
635  $tester->run(array('-V' => true), array('decorated' => false));
636  $this->assertStringEqualsFile(self::$fixturesPath.'/application_run4.txt', $tester->getDisplay(true), '->run() displays the program version if -v is passed');
637 
638  $tester->run(array('command' => 'list', '--quiet' => true));
639  $this->assertSame('', $tester->getDisplay(), '->run() removes all output if --quiet is passed');
640 
641  $tester->run(array('command' => 'list', '-q' => true));
642  $this->assertSame('', $tester->getDisplay(), '->run() removes all output if -q is passed');
643 
644  $tester->run(array('command' => 'list', '--verbose' => true));
645  $this->assertSame(Output::VERBOSITY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if --verbose is passed');
646 
647  $tester->run(array('command' => 'list', '--verbose' => 1));
648  $this->assertSame(Output::VERBOSITY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if --verbose=1 is passed');
649 
650  $tester->run(array('command' => 'list', '--verbose' => 2));
651  $this->assertSame(Output::VERBOSITY_VERY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to very verbose if --verbose=2 is passed');
652 
653  $tester->run(array('command' => 'list', '--verbose' => 3));
654  $this->assertSame(Output::VERBOSITY_DEBUG, $tester->getOutput()->getVerbosity(), '->run() sets the output to debug if --verbose=3 is passed');
655 
656  $tester->run(array('command' => 'list', '--verbose' => 4));
657  $this->assertSame(Output::VERBOSITY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if unknown --verbose level is passed');
658 
659  $tester->run(array('command' => 'list', '-v' => true));
660  $this->assertSame(Output::VERBOSITY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if -v is passed');
661 
662  $tester->run(array('command' => 'list', '-vv' => true));
663  $this->assertSame(Output::VERBOSITY_VERY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if -v is passed');
664 
665  $tester->run(array('command' => 'list', '-vvv' => true));
666  $this->assertSame(Output::VERBOSITY_DEBUG, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if -v is passed');
667 
668  $application = new Application();
669  $application->setAutoExit(false);
670  $application->setCatchExceptions(false);
671  $application->add(new \FooCommand());
672  $tester = new ApplicationTester($application);
673 
674  $tester->run(array('command' => 'foo:bar', '--no-interaction' => true), array('decorated' => false));
675  $this->assertSame('called'.PHP_EOL, $tester->getDisplay(), '->run() does not call interact() if --no-interaction is passed');
676 
677  $tester->run(array('command' => 'foo:bar', '-n' => true), array('decorated' => false));
678  $this->assertSame('called'.PHP_EOL, $tester->getDisplay(), '->run() does not call interact() if -n is passed');
679  }
680 
689  {
690  $application = new Application();
691  $application->setAutoExit(false);
692  $application->setCatchExceptions(false);
693  $application->add(new \FooCommand());
694 
695  $output = new StreamOutput(fopen('php://memory', 'w', false));
696 
697  $input = new ArgvInput(array('cli.php', '-v', 'foo:bar'));
698  $application->run($input, $output);
699 
700  $input = new ArgvInput(array('cli.php', '--verbose', 'foo:bar'));
701  $application->run($input, $output);
702  }
703 
705  {
706  $exception = new \Exception('', 4);
707 
708  $application = $this->getMock('Symfony\Component\Console\Application', array('doRun'));
709  $application->setAutoExit(false);
710  $application->expects($this->once())
711  ->method('doRun')
712  ->will($this->throwException($exception));
713 
714  $exitCode = $application->run(new ArrayInput(array()), new NullOutput());
715 
716  $this->assertSame(4, $exitCode, '->run() returns integer exit code extracted from raised exception');
717  }
718 
720  {
721  $exception = new \Exception('', 0);
722 
723  $application = $this->getMock('Symfony\Component\Console\Application', array('doRun'));
724  $application->setAutoExit(false);
725  $application->expects($this->once())
726  ->method('doRun')
727  ->will($this->throwException($exception));
728 
729  $exitCode = $application->run(new ArrayInput(array()), new NullOutput());
730 
731  $this->assertSame(1, $exitCode, '->run() returns exit code 1 when exception code is 0');
732  }
733 
739  {
740  $application = new Application();
741  $application->setAutoExit(false);
742  $application->setCatchExceptions(false);
743  $application
744  ->register('foo')
745  ->setDefinition(array($def))
746  ->setCode(function (InputInterface $input, OutputInterface $output) {})
747  ;
748 
749  $input = new ArrayInput(array('command' => 'foo'));
750  $output = new NullOutput();
751  $application->run($input, $output);
752  }
753 
755  {
756  return array(
757  array(new InputArgument('command', InputArgument::REQUIRED)),
758  array(new InputOption('quiet', '', InputOption::VALUE_NONE)),
759  array(new InputOption('query', 'q', InputOption::VALUE_NONE)),
760  );
761  }
762 
764  {
765  $application = new Application();
766  $application->setAutoExit(false);
767  $application->setCatchExceptions(false);
768 
769  $helperSet = $application->getHelperSet();
770 
771  $this->assertTrue($helperSet->has('formatter'));
772  $this->assertTrue($helperSet->has('dialog'));
773  $this->assertTrue($helperSet->has('progress'));
774  }
775 
777  {
778  $application = new Application();
779  $application->setAutoExit(false);
780  $application->setCatchExceptions(false);
781 
782  $application->setHelperSet(new HelperSet(array(new FormatterHelper())));
783 
784  $helperSet = $application->getHelperSet();
785 
786  $this->assertTrue($helperSet->has('formatter'));
787 
788  // no other default helper set should be returned
789  $this->assertFalse($helperSet->has('dialog'));
790  $this->assertFalse($helperSet->has('progress'));
791  }
792 
794  {
795  $application = new CustomApplication();
796  $application->setAutoExit(false);
797  $application->setCatchExceptions(false);
798 
799  $application->setHelperSet(new HelperSet(array(new FormatterHelper())));
800 
801  $helperSet = $application->getHelperSet();
802 
803  $this->assertTrue($helperSet->has('formatter'));
804 
805  // no other default helper set should be returned
806  $this->assertFalse($helperSet->has('dialog'));
807  $this->assertFalse($helperSet->has('progress'));
808  }
809 
811  {
812  $application = new Application();
813  $application->setAutoExit(false);
814  $application->setCatchExceptions(false);
815 
816  $inputDefinition = $application->getDefinition();
817 
818  $this->assertTrue($inputDefinition->hasArgument('command'));
819 
820  $this->assertTrue($inputDefinition->hasOption('help'));
821  $this->assertTrue($inputDefinition->hasOption('quiet'));
822  $this->assertTrue($inputDefinition->hasOption('verbose'));
823  $this->assertTrue($inputDefinition->hasOption('version'));
824  $this->assertTrue($inputDefinition->hasOption('ansi'));
825  $this->assertTrue($inputDefinition->hasOption('no-ansi'));
826  $this->assertTrue($inputDefinition->hasOption('no-interaction'));
827  }
828 
830  {
831  $application = new CustomApplication();
832  $application->setAutoExit(false);
833  $application->setCatchExceptions(false);
834 
835  $inputDefinition = $application->getDefinition();
836 
837  // check whether the default arguments and options are not returned any more
838  $this->assertFalse($inputDefinition->hasArgument('command'));
839 
840  $this->assertFalse($inputDefinition->hasOption('help'));
841  $this->assertFalse($inputDefinition->hasOption('quiet'));
842  $this->assertFalse($inputDefinition->hasOption('verbose'));
843  $this->assertFalse($inputDefinition->hasOption('version'));
844  $this->assertFalse($inputDefinition->hasOption('ansi'));
845  $this->assertFalse($inputDefinition->hasOption('no-ansi'));
846  $this->assertFalse($inputDefinition->hasOption('no-interaction'));
847 
848  $this->assertTrue($inputDefinition->hasOption('custom'));
849  }
850 
852  {
853  $application = new Application();
854  $application->setAutoExit(false);
855  $application->setCatchExceptions(false);
856 
857  $application->setDefinition(new InputDefinition(array(new InputOption('--custom', '-c', InputOption::VALUE_NONE, 'Set the custom input definition.'))));
858 
859  $inputDefinition = $application->getDefinition();
860 
861  // check whether the default arguments and options are not returned any more
862  $this->assertFalse($inputDefinition->hasArgument('command'));
863 
864  $this->assertFalse($inputDefinition->hasOption('help'));
865  $this->assertFalse($inputDefinition->hasOption('quiet'));
866  $this->assertFalse($inputDefinition->hasOption('verbose'));
867  $this->assertFalse($inputDefinition->hasOption('version'));
868  $this->assertFalse($inputDefinition->hasOption('ansi'));
869  $this->assertFalse($inputDefinition->hasOption('no-ansi'));
870  $this->assertFalse($inputDefinition->hasOption('no-interaction'));
871 
872  $this->assertTrue($inputDefinition->hasOption('custom'));
873  }
874 
875  public function testRunWithDispatcher()
876  {
877  $application = new Application();
878  $application->setAutoExit(false);
879  $application->setDispatcher($this->getDispatcher());
880 
881  $application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) {
882  $output->write('foo.');
883  });
884 
885  $tester = new ApplicationTester($application);
886  $tester->run(array('command' => 'foo'));
887  $this->assertEquals('before.foo.after.', $tester->getDisplay());
888  }
889 
895  {
896  $application = new Application();
897  $application->setDispatcher($this->getDispatcher());
898  $application->setAutoExit(false);
899  $application->setCatchExceptions(false);
900 
901  $application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) {
902  throw new \RuntimeException('foo');
903  });
904 
905  $tester = new ApplicationTester($application);
906  $tester->run(array('command' => 'foo'));
907  }
908 
910  {
911  $application = new Application();
912  $application->setDispatcher($this->getDispatcher());
913  $application->setAutoExit(false);
914 
915  $application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) {
916  $output->write('foo.');
917 
918  throw new \RuntimeException('foo');
919  });
920 
921  $tester = new ApplicationTester($application);
922  $tester->run(array('command' => 'foo'));
923  $this->assertContains('before.foo.after.caught.', $tester->getDisplay());
924  }
925 
927  {
928  $application = new Application();
929  $application->setDispatcher($this->getDispatcher(true));
930  $application->setAutoExit(false);
931 
932  $application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) {
933  $output->write('foo.');
934  });
935 
936  $tester = new ApplicationTester($application);
937  $exitCode = $tester->run(array('command' => 'foo'));
938  $this->assertContains('before.after.', $tester->getDisplay());
939  $this->assertEquals(ConsoleCommandEvent::RETURN_CODE_DISABLED, $exitCode);
940  }
941 
942  public function testTerminalDimensions()
943  {
944  $application = new Application();
945  $originalDimensions = $application->getTerminalDimensions();
946  $this->assertCount(2, $originalDimensions);
947 
948  $width = 80;
949  if ($originalDimensions[0] == $width) {
950  $width = 100;
951  }
952 
953  $application->setTerminalDimensions($width, 80);
954  $this->assertSame(array($width, 80), $application->getTerminalDimensions());
955  }
956 
957  protected function getDispatcher($skipCommand = false)
958  {
959  $dispatcher = new EventDispatcher();
960  $dispatcher->addListener('console.command', function (ConsoleCommandEvent $event) use ($skipCommand) {
961  $event->getOutput()->write('before.');
962 
963  if ($skipCommand) {
964  $event->disableCommand();
965  }
966  });
967  $dispatcher->addListener('console.terminate', function (ConsoleTerminateEvent $event) use ($skipCommand) {
968  $event->getOutput()->write('after.');
969 
970  if (!$skipCommand) {
971  $event->setExitCode(113);
972  }
973  });
974  $dispatcher->addListener('console.exception', function (ConsoleExceptionEvent $event) {
975  $event->getOutput()->writeln('caught.');
976 
977  $event->setException(new \LogicException('caught.', $event->getExitCode(), $event->getException()));
978  });
979 
980  return $dispatcher;
981  }
982 
984  {
985  $command = new \FooCommand();
986 
987  $application = new Application();
988  $application->setAutoExit(false);
989  $application->add($command);
990  $application->setDefaultCommand($command->getName());
991 
992  $tester = new ApplicationTester($application);
993  $tester->run(array());
994  $this->assertEquals('interact called'.PHP_EOL.'called'.PHP_EOL, $tester->getDisplay(), 'Application runs the default set command if different from \'list\' command');
995 
996  $application = new CustomDefaultCommandApplication();
997  $application->setAutoExit(false);
998 
999  $tester = new ApplicationTester($application);
1000  $tester->run(array());
1001 
1002  $this->assertEquals('interact called'.PHP_EOL.'called'.PHP_EOL, $tester->getDisplay(), 'Application runs the default set command if different from \'list\' command');
1003  }
1004 
1006  {
1007  if (!function_exists('posix_isatty')) {
1008  $this->markTestSkipped('posix_isatty function is required');
1009  }
1010 
1011  $application = new CustomDefaultCommandApplication();
1012  $application->setAutoExit(false);
1013 
1014  $tester = new ApplicationTester($application);
1015  $tester->run(array('command' => 'help'));
1016 
1017  $this->assertFalse($tester->getInput()->hasParameterOption(array('--no-interaction', '-n')));
1018 
1019  $inputStream = $application->getHelperSet()->get('question')->getInputStream();
1020  $this->assertEquals($tester->getInput()->isInteractive(), @posix_isatty($inputStream));
1021  }
1022 }
1023 
1025 {
1031  protected function getDefaultInputDefinition()
1032  {
1033  return new InputDefinition(array(new InputOption('--custom', '-c', InputOption::VALUE_NONE, 'Set the custom input definition.')));
1034  }
1035 
1041  protected function getDefaultHelperSet()
1042  {
1043  return new HelperSet(array(new FormatterHelper()));
1044  }
1045 }
1046 
1048 {
1052  public function __construct()
1053  {
1054  parent::__construct();
1055 
1056  $command = new \FooCommand();
1057  $this->add($command);
1058  $this->setDefaultCommand($command->getName());
1059  }
1060 }