diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php index f169b6eb8702e..bccbc2ff4b8cf 100644 --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php @@ -241,6 +241,13 @@ public function run(InputInterface $input, OutputInterface $output) $this->interact($input, $output); } + // The command name argument is often omitted when a command is executed directly with its run() method. + // It would fail the validation if we didn't make sure the command argument is present, + // since it's required by the application. + if ($input->hasArgument('command') && null === $input->getArgument('command')) { + $input->setArgument('command', $this->getName()); + } + $input->validate(); if ($this->code) { diff --git a/src/Symfony/Component/Console/Input/Input.php b/src/Symfony/Component/Console/Input/Input.php index 05a029f09caaf..8103d193164c2 100644 --- a/src/Symfony/Component/Console/Input/Input.php +++ b/src/Symfony/Component/Console/Input/Input.php @@ -72,8 +72,15 @@ abstract protected function parse(); */ public function validate() { - if (count($this->arguments) < $this->definition->getArgumentRequiredCount()) { - throw new \RuntimeException('Not enough arguments.'); + $definition = $this->definition; + $givenArguments = $this->arguments; + + $missingArguments = array_filter(array_keys($definition->getArguments()), function ($argument) use ($definition, $givenArguments) { + return !array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired(); + }); + + if (count($missingArguments) > 0) { + throw new \RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments))); } } diff --git a/src/Symfony/Component/Console/Tests/Command/CommandTest.php b/src/Symfony/Component/Console/Tests/Command/CommandTest.php index a0c8d78deb275..a252fe7127794 100644 --- a/src/Symfony/Component/Console/Tests/Command/CommandTest.php +++ b/src/Symfony/Component/Console/Tests/Command/CommandTest.php @@ -267,6 +267,15 @@ public function testRunReturnsIntegerExitCode() $this->assertSame(2, $exitCode, '->run() returns integer exit code (casts numeric to int)'); } + public function testRunWithApplication() + { + $command = new \TestCommand(); + $command->setApplication(new Application()); + $exitCode = $command->run(new StringInput(''), new NullOutput()); + + $this->assertSame(0, $exitCode, '->run() returns an integer exit code'); + } + public function testRunReturnsAlwaysInteger() { $command = new \TestCommand(); diff --git a/src/Symfony/Component/Console/Tests/Input/InputTest.php b/src/Symfony/Component/Console/Tests/Input/InputTest.php index 0b3e38fb6f4ce..eb1c6617f5644 100644 --- a/src/Symfony/Component/Console/Tests/Input/InputTest.php +++ b/src/Symfony/Component/Console/Tests/Input/InputTest.php @@ -94,7 +94,7 @@ public function testGetInvalidArgument() /** * @expectedException \RuntimeException - * @expectedExceptionMessage Not enough arguments. + * @expectedExceptionMessage Not enough arguments (missing: "name"). */ public function testValidateWithMissingArguments() { @@ -103,6 +103,17 @@ public function testValidateWithMissingArguments() $input->validate(); } + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage Not enough arguments (missing: "name"). + */ + public function testValidateWithMissingRequiredArguments() + { + $input = new ArrayInput(array('bar' => 'baz')); + $input->bind(new InputDefinition(array(new InputArgument('name', InputArgument::REQUIRED), new InputArgument('bar', InputArgument::OPTIONAL)))); + $input->validate(); + } + public function testValidate() { $input = new ArrayInput(array('name' => 'foo'));