-
-
Notifications
You must be signed in to change notification settings - Fork 48
debug:expression command #294
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 10 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
b68f693
first draft of debug:expression command
fain182 e55ea45
removed psalm warning
fain182 a428d1c
Adds option for target PHP version
fain182 1964a97
fix typo
fain182 698e273
improve error message for too few or too many arguments in debug:expr…
fain182 6ffdbde
improve error message for invalid expression in debug:expression
fain182 9a22600
remove constants that are available only on recent symfony versions
fain182 ab54b6a
show parse errors when running debug:expression
fain182 4a0d60f
fix HEREDOC indentation to make it work in PHP 7.1
fain182 38b6812
adds hint in the README
fain182 a1d6cdd
refactoring
fain182 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| <?php | ||
| declare(strict_types=1); | ||
|
|
||
| namespace Arkitect\CLI\Command; | ||
|
|
||
| use Arkitect\Analyzer\FileParserFactory; | ||
| use Arkitect\ClassSet; | ||
| use Arkitect\CLI\TargetPhpVersion; | ||
| use Arkitect\Rules\ParsingError; | ||
| use Arkitect\Rules\Violations; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputArgument; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Input\InputOption; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class DebugExpression extends Command | ||
| { | ||
| /** @var string|null */ | ||
| public static $defaultName = 'debug:expression'; | ||
|
|
||
| /** @var string|null */ | ||
| public static $defaultDescription = <<< 'EOT' | ||
| Check which classes respect an expression | ||
| EOT; | ||
|
|
||
| /** @var string */ | ||
| public static $help = <<< 'EOT' | ||
| Check which classes respect an expression | ||
| EOT; | ||
|
|
||
| protected function configure(): void | ||
| { | ||
| $this | ||
| ->setHelp(self::$help) | ||
| ->addArgument('expression', InputArgument::REQUIRED) | ||
| ->addArgument('arguments', InputArgument::IS_ARRAY) | ||
| ->addOption( | ||
| 'from-dir', | ||
| 'd', | ||
| InputOption::VALUE_REQUIRED, | ||
| 'The folder in which to search the classes', | ||
| '.' | ||
| ) | ||
| ->addOption( | ||
| 'target-php-version', | ||
| 't', | ||
| InputOption::VALUE_OPTIONAL, | ||
| 'Target php version to use for parsing' | ||
| ); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output): int | ||
| { | ||
| $phpVersion = $input->getOption('target-php-version'); | ||
| $targetPhpVersion = TargetPhpVersion::create($phpVersion); | ||
| $fileParser = FileParserFactory::createFileParser($targetPhpVersion); | ||
|
|
||
| $classSet = ClassSet::fromDir($input->getOption('from-dir')); | ||
| foreach ($classSet as $file) { | ||
| $fileParser->parse($file->getContents(), $file->getRelativePathname()); | ||
| $parsedErrors = $fileParser->getParsingErrors(); | ||
|
|
||
| if (\count($parsedErrors) > 0) { | ||
| $output->writeln('WARNING: Some files could not be parsed for these errors:'); | ||
| /** @var ParsingError $parsedError */ | ||
| foreach ($parsedErrors as $parsedError) { | ||
| $output->writeln(' - '.$parsedError->getError().': '.$parsedError->getRelativeFilePath()); | ||
| } | ||
| $output->writeln(''); | ||
| } | ||
|
|
||
| $ruleName = $input->getArgument('expression'); | ||
| /** @var class-string $ruleFQCN */ | ||
| $ruleFQCN = 'Arkitect\Expression\ForClasses\\'.$ruleName; | ||
| $arguments = $input->getArgument('arguments'); | ||
|
|
||
| try { | ||
| $expressionReflection = new \ReflectionClass($ruleFQCN); | ||
| } catch (\ReflectionException $exception) { | ||
| $output->writeln("Error: Expression '$ruleName' not found."); | ||
|
|
||
| return 2; | ||
| } | ||
|
|
||
| $constructorReflection = $expressionReflection->getConstructor(); | ||
AlessandroMinoccheri marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (null === $constructorReflection) { | ||
| $maxNumberOfArguments = 0; | ||
| $minNumberOfArguments = 0; | ||
| } else { | ||
| $maxNumberOfArguments = $constructorReflection->getNumberOfParameters(); | ||
| $minNumberOfArguments = $constructorReflection->getNumberOfRequiredParameters(); | ||
| } | ||
|
|
||
| if (\count($arguments) < $minNumberOfArguments) { | ||
| $output->writeln("Error: Too few arguments for '$ruleName'."); | ||
|
|
||
| return 2; | ||
| } | ||
|
|
||
| if (\count($arguments) > $maxNumberOfArguments) { | ||
| $output->writeln("Error: Too many arguments for '$ruleName'."); | ||
|
|
||
| return 2; | ||
| } | ||
|
|
||
| $rule = new $ruleFQCN(...$arguments); | ||
| foreach ($fileParser->getClassDescriptions() as $classDescription) { | ||
| $violations = new Violations(); | ||
| $rule->evaluate($classDescription, $violations, ''); | ||
| if (0 === $violations->count()) { | ||
| $output->writeln($classDescription->getFQCN()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace Arkitect\Tests\E2E\Cli; | ||
|
|
||
| use Arkitect\CLI\PhpArkitectApplication; | ||
| use PHPUnit\Framework\TestCase; | ||
| use Symfony\Component\Console\Tester\ApplicationTester; | ||
|
|
||
| class DebugExpressionCommandTest extends TestCase | ||
| { | ||
| public function test_you_need_to_specify_the_expression(): void | ||
| { | ||
| $appTester = $this->createAppTester(); | ||
| $appTester->run(['debug:expression']); | ||
| $this->assertEquals(1, $appTester->getStatusCode()); | ||
| } | ||
|
|
||
| public function test_zero_results(): void | ||
| { | ||
| $appTester = $this->createAppTester(); | ||
| $appTester->run(['debug:expression', 'expression' => 'Extend', 'arguments' => ['NotFound'], '--from-dir' => __DIR__]); | ||
| $this->assertEquals('', $appTester->getDisplay()); | ||
| $this->assertEquals(0, $appTester->getStatusCode()); | ||
| } | ||
|
|
||
| public function test_some_classes_found(): void | ||
| { | ||
| $appTester = $this->createAppTester(); | ||
| $appTester->run(['debug:expression', 'expression' => 'NotExtend', 'arguments' => ['NotFound'], '--from-dir' => __DIR__.'/../_fixtures/mvc/Domain']); | ||
| $this->assertEquals("App\Domain\Model\n", $appTester->getDisplay()); | ||
| $this->assertEquals(0, $appTester->getStatusCode()); | ||
| } | ||
|
|
||
| public function test_meaningful_errors_for_too_few_arguments_for_the_expression(): void | ||
| { | ||
| $appTester = $this->createAppTester(); | ||
| $appTester->run(['debug:expression', 'expression' => 'NotExtend', 'arguments' => [], '--from-dir' => __DIR__.'/../_fixtures/mvc/Domain']); | ||
| $this->assertEquals("Error: Too few arguments for 'NotExtend'.\n", $appTester->getDisplay()); | ||
| $this->assertEquals(2, $appTester->getStatusCode()); | ||
| } | ||
|
|
||
| public function test_meaningful_errors_for_too_many_arguments_for_the_expression(): void | ||
| { | ||
| $appTester = $this->createAppTester(); | ||
| $appTester->run(['debug:expression', 'expression' => 'NotExtend', 'arguments' => ['First', 'Second'], '--from-dir' => __DIR__.'/../_fixtures/mvc/Domain']); | ||
| $this->assertEquals("Error: Too many arguments for 'NotExtend'.\n", $appTester->getDisplay()); | ||
| $this->assertEquals(2, $appTester->getStatusCode()); | ||
| } | ||
|
|
||
| public function test_optional_argument_for_expression_can_be_avoided(): void | ||
| { | ||
| $appTester = $this->createAppTester(); | ||
| $appTester->run(['debug:expression', 'expression' => 'NotHaveDependencyOutsideNamespace', 'arguments' => ['NotFound'], '--from-dir' => __DIR__]); | ||
| $this->assertEquals('', $appTester->getDisplay()); | ||
| $this->assertEquals(0, $appTester->getStatusCode()); | ||
| } | ||
|
|
||
| public function test_expression_not_found(): void | ||
| { | ||
| $appTester = $this->createAppTester(); | ||
| $appTester->run(['debug:expression', 'expression' => 'blabla', 'arguments' => ['NotFound'], '--from-dir' => __DIR__]); | ||
| $this->assertEquals("Error: Expression 'blabla' not found.\n", $appTester->getDisplay()); | ||
| $this->assertEquals(2, $appTester->getStatusCode()); | ||
| } | ||
|
|
||
| public function test_parse_error_dont_stop_execution(): void | ||
| { | ||
| $appTester = $this->createAppTester(); | ||
| $appTester->run(['debug:expression', 'expression' => 'NotExtend', 'arguments' => ['NotFound'], '--from-dir' => __DIR__.'/../_fixtures/parse_error']); | ||
| $errorMessage = <<<END | ||
| WARNING: Some files could not be parsed for these errors: | ||
| - Syntax error, unexpected T_STRING, expecting '{' on line 8: Services/CartService.php | ||
|
|
||
| App\Services\UserService | ||
|
|
||
| END; | ||
| $this->assertEquals($errorMessage, $appTester->getDisplay()); | ||
| $this->assertEquals(0, $appTester->getStatusCode()); | ||
| } | ||
|
|
||
| private function createAppTester(): ApplicationTester | ||
| { | ||
| $app = new PhpArkitectApplication(); | ||
| $app->setAutoExit(false); | ||
|
|
||
| return new ApplicationTester($app); | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.