Repository: symfony/symfony
File: src/Symfony/Component/Console/Tests/Command/InvokableCommandTest.php (PHP)

Code before:
use Symfony\Component\Console\Attribute\Argument;
use Symfony\Component\Console\Attribute\Option;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Completion\Suggestion;
use Symfony\Component\Console\Exception\InvalidOptionException;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Output\OutputInterface;

class InvokableCommandTest extends TestCase
{
    public function testCommandInputArgumentDefinition()
    {
        $command = new Command('foo');
        $command->setCode(function (
            #[Argument(name: 'very-first-name')] string $name,
            #[Argument] ?string $firstName,
            #[Argument] string $lastName = '',
            #[Argument(description: 'Short argument description')] string $bio = '',
            // Declare callback in static context, even when method is NOT static.
            // PHP doesn't allow to use `$this` here, and callback is later modified
            // on-the-fly to be called on instance instead: https://github.com/symfony/symfony/blob/7.3/src/Symfony/Component/Console/Attribute/Argument.php#L87
            // and this test case validates if this mechanism works.
            #[Argument(suggestedValues: [self::class, 'getSuggestedRoles'])] array $roles = ['ROLE_USER'],
        ): int {
            \assert($this !== null); // so PHP CS Fixer knows this callback actually coupled with `$this` and `static_lambda` rule shall not be applied

            return 0;
        });

        $nameInputArgument = $command->getDefinition()->getArgument('very-first-name');
        self::assertSame('very-first-name', $nameInputArgument->getName());
        self::assertTrue($nameInputArgument->isRequired());

        $lastNameInputArgument = $command->getDefinition()->getArgument('first-name');
        self::assertSame('first-name', $lastNameInputArgument->getName());
        self::assertFalse($lastNameInputArgument->isRequired());
        self::assertNull($lastNameInputArgument->getDefault());

        $lastNameInputArgument = $command->getDefinition()->getArgument('last-name');
        self::assertSame('last-name', $lastNameInputArgument->getName());
        self::assertFalse($lastNameInputArgument->isRequired());
        self::assertSame('', $lastNameInputArgument->getDefault());

        $bioInputArgument = $command->getDefinition()->getArgument('bio');
        self::assertSame('bio', $bioInputArgument->getName());
        self::assertFalse($bioInputArgument->isRequired());

Review comment (suggestion):
we don't add links to github in the codebase
```suggestion
            // on-the-fly to be called on instance instead
```

Code after:
use Symfony\Component\Console\Attribute\Argument;
use Symfony\Component\Console\Attribute\Option;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Completion\Suggestion;
use Symfony\Component\Console\Exception\InvalidOptionException;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Output\OutputInterface;

class InvokableCommandTest extends TestCase
{
    public function testCommandInputArgumentDefinition()
    {
        $command = new Command('foo');
        $command->setCode(function (
            #[Argument(name: 'very-first-name')] string $name,
            #[Argument] ?string $firstName,
            #[Argument] string $lastName = '',
            #[Argument(description: 'Short argument description')] string $bio = '',
            // In this test case, we declare the callback in static context, even when the method is NOT static.
            // PHP doesn't allow using `$this` here, and the callback is later modified on-the-fly
            // to be called on the instance instead, and this test case validates if this mechanism works.
            //
            // @see \Symfony\Component\Console\Attribute\Argument
            #[Argument(suggestedValues: [self::class, 'getSuggestedRoles'])] array $roles = ['ROLE_USER'],
        ): int {
            \assert(null !== $this); // so PHP CS Fixer knows this callback is actually coupled with `$this` and `static_lambda` rule shall not be applied

            return 0;
        });

        $nameInputArgument = $command->getDefinition()->getArgument('very-first-name');
        self::assertSame('very-first-name', $nameInputArgument->getName());
        self::assertTrue($nameInputArgument->isRequired());

        $lastNameInputArgument = $command->getDefinition()->getArgument('first-name');
        self::assertSame('first-name', $lastNameInputArgument->getName());
        self::assertFalse($lastNameInputArgument->isRequired());
        self::assertNull($lastNameInputArgument->getDefault());

        $lastNameInputArgument = $command->getDefinition()->getArgument('last-name');
        self::assertSame('last-name', $lastNameInputArgument->getName());
        self::assertFalse($lastNameInputArgument->isRequired());
        self::assertSame('', $lastNameInputArgument->getDefault());

        $bioInputArgument = $command->getDefinition()->getArgument('bio');
        self::assertSame('bio', $bioInputArgument->getName());