From 0edeaafad353210fc7975b31ac6dfb666d3657da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Mat=C4=9Bj=C4=8Dek?= Date: Wed, 20 Dec 2023 12:56:01 +0100 Subject: [PATCH 1/5] feat(Testing): Add new attribute for mark interface for automatic generated expectation --- .../ComposerAutoloadAbsoluteAction.php | 73 +++++++++++++ .../Actions/GetNamespaceForStubsAction.php | 11 +- src/Testing/Actions/PathToClassAction.php | 62 +++++++++++ src/Testing/Attributes/TestAssert.php | 12 ++ .../Commands/MakeExpectationCommand.php | 103 ++++++++++++++---- .../Contracts/FinderFactoryContract.php | 12 ++ src/Testing/Factories/FinderFactory.php | 25 +++++ .../Services/ComposerJsonDataService.php | 47 ++++++++ src/Testing/TestServiceProvider.php | 3 + 9 files changed, 318 insertions(+), 30 deletions(-) create mode 100644 src/Testing/Actions/ComposerAutoloadAbsoluteAction.php create mode 100644 src/Testing/Actions/PathToClassAction.php create mode 100644 src/Testing/Attributes/TestAssert.php create mode 100644 src/Testing/Contracts/FinderFactoryContract.php create mode 100644 src/Testing/Factories/FinderFactory.php create mode 100644 src/Testing/Services/ComposerJsonDataService.php diff --git a/src/Testing/Actions/ComposerAutoloadAbsoluteAction.php b/src/Testing/Actions/ComposerAutoloadAbsoluteAction.php new file mode 100644 index 00000000..3f0dc5b6 --- /dev/null +++ b/src/Testing/Actions/ComposerAutoloadAbsoluteAction.php @@ -0,0 +1,73 @@ + + */ + private array $dirs = []; + + public function __construct( + private readonly ComposerJsonDataService $getComposerJsonDataAction, + private readonly Filesystem $filesystem, + GetBasePathForStubsActionContract $getBasePathForStubsAction, + ) { + $this->dirs = $this->makeDirs($getBasePathForStubsAction->execute()); + } + + /** + * @return array + */ + public function execute(?string $path = null): array + { + if ($path !== null) { + $this->dirs += $this->loadNewComposer($path); + } + + return $this->dirs; + } + + /** + * @return array + */ + private function makeDirs(string $basePath): array + { + $data = $this->getComposerJsonDataAction->data($basePath); + $dirs = []; + + if (isset($data['autoload']['psr-4']) && is_array($data['autoload']['psr-4'])) { + foreach ($data['autoload']['psr-4'] as $ns => $path) { + $dirs[$ns] = $basePath . DIRECTORY_SEPARATOR . trim((string) $path, '\\/'); + } + } + + return $dirs; + } + + /** + * @return array + */ + private function loadNewComposer(string $path): array + { + if ($this->filesystem->isFile($path)) { + $path = $this->filesystem->dirname($path); + } elseif ($this->filesystem->isDirectory($path) === false) { + throw new Exception(sprintf('The path is not dir "%s".', $path)); + } + + while ($this->getComposerJsonDataAction->isExist($path) === false) { + $path = $this->filesystem->dirname($path); + } + + return $this->makeDirs($path); + } +} diff --git a/src/Testing/Actions/GetNamespaceForStubsAction.php b/src/Testing/Actions/GetNamespaceForStubsAction.php index 5e64d34e..25e31e1d 100644 --- a/src/Testing/Actions/GetNamespaceForStubsAction.php +++ b/src/Testing/Actions/GetNamespaceForStubsAction.php @@ -5,10 +5,10 @@ namespace LaraStrict\Testing\Actions; use Illuminate\Console\Command; -use Illuminate\Filesystem\Filesystem; use LaraStrict\Testing\Constants\StubConstants; use LaraStrict\Testing\Contracts\GetNamespaceForStubsActionContract; use LaraStrict\Testing\Entities\NamespaceEntity; +use LaraStrict\Testing\Services\ComposerJsonDataService; use LogicException; class GetNamespaceForStubsAction implements GetNamespaceForStubsActionContract @@ -17,14 +17,14 @@ class GetNamespaceForStubsAction implements GetNamespaceForStubsActionContract final public const ComposerPsr4 = 'psr-4'; public function __construct( - private readonly Filesystem $filesystem, + private readonly ComposerJsonDataService $getComposerJsonDataAction, ) { } public function execute(Command $command, string $basePath, string $inputClass): NamespaceEntity { // Ask for which namespace which to use for "tests" - $composer = $this->getComposerJsonData($basePath); + $composer = $this->getComposerJsonDataAction->data($basePath); $autoLoad = $this->getComposerDevAutoLoad($composer); if ($autoLoad !== []) { if (count($autoLoad) === 1) { @@ -47,11 +47,6 @@ public function execute(Command $command, string $basePath, string $inputClass): return new NamespaceEntity($folder, $baseNamespace); } - protected function getComposerJsonData(string $basePath): mixed - { - return json_decode($this->filesystem->get($basePath . '/composer.json'), true, 512, JSON_THROW_ON_ERROR); - } - private function getComposerDevAutoLoad(array $composer): array { if (isset($composer[self::ComposerAutoLoadDev]) diff --git a/src/Testing/Actions/PathToClassAction.php b/src/Testing/Actions/PathToClassAction.php new file mode 100644 index 00000000..71e3ae8c --- /dev/null +++ b/src/Testing/Actions/PathToClassAction.php @@ -0,0 +1,62 @@ +composerAutoloadAbsoluteAction->execute(); + + $class = $this->replacePathToClass($dirs, $path); + if ($class === null) { + $dirs = $this->composerAutoloadAbsoluteAction->execute($path); + $class = $this->replacePathToClass($dirs, $path); + + if ($class === null) { + throw new Exception(sprintf('Path "%s" not found in composer psr-4.', $path)); + } + } + + return $class; + } + + /** + * @param array $dirs + * + * @return class-string|null + */ + private function replacePathToClass(array $dirs, string $path): ?string + { + foreach ($dirs as $ns => $dir) { + if (str_starts_with($path, $dir) === false) { + continue; + } + /** @var class-string $class */ + $class = preg_replace_callback( + sprintf('~^%s[/\\\](?.*)\.php$~', preg_quote($dir, '~')), + static fn (array $matches) => $ns . strtr($matches['path'], [ + '/' => '\\', + ]), + $path + ); + assert(is_string($class)); + + return $class; + } + + return null; + } +} diff --git a/src/Testing/Attributes/TestAssert.php b/src/Testing/Attributes/TestAssert.php new file mode 100644 index 00000000..8cc112b6 --- /dev/null +++ b/src/Testing/Attributes/TestAssert.php @@ -0,0 +1,12 @@ +execute(); - $inputClass = $this->getInputClass($basePath, $filesystem); + /** @phpstan-var class-string|string $class */ + $class = (string) $this->input->getArgument('class'); + + if ($class === 'all') { + $inputClasses = $this->findAllClasses($finderFactory->create(), $pathToClassAction); + } else { + $inClass = $this->normalizeToClass($class, $basePath, $filesystem, $pathToClassAction); + $inputClasses = $inClass === null ? [] : [$inClass]; + } - if ($inputClass === null) { + if ($inputClasses === []) { return 1; } + foreach ($inputClasses as $inputClass) { + $this->generateExpectationFiles( + $inputClass, + $getFolderAndNamespaceForStubsAction, + $basePath, + $filesystem, + $parsePhpDocAction + ); + } + + return 0; + } + + /** + * @param class-string $inputClass + */ + public function generateExpectationFiles( + string $inputClass, + GetNamespaceForStubsActionContract $getFolderAndNamespaceForStubsAction, + string $basePath, + Filesystem $filesystem, + ParsePhpDocAction $parsePhpDocAction + ): void { $class = new ReflectionClass($inputClass); $methods = $class->getMethods(ReflectionMethod::IS_PUBLIC); @@ -175,8 +211,6 @@ className: $assertClassName, fileContents: $printer->printFile($assertFileState->file) ); } - - return 0; } /** @@ -479,11 +513,25 @@ protected function canReturnExpectation(ReflectionNamedType $returnType): bool /** * @return class-string|null */ - private function getInputClass(string $basePath, Filesystem $filesystem): ?string + private function checkInterface(string $class): ?string { - /** @phpstan-var class-string|string $class */ - $class = (string) $this->input->getArgument('class'); + if (class_exists($class) === false && interface_exists($class) === false) { + $this->writeError(sprintf('Provided class does not exists [%s]', $class)); + return null; + } + + return $class; + } + /** + * @return class-string|null + */ + private function normalizeToClass( + string $class, + string $basePath, + Filesystem $filesystem, + PathToClassAction $pathToClassAction + ): ?string { if (str_ends_with($class, '.php')) { $fullPath = $basePath . '/' . $class; @@ -492,23 +540,34 @@ private function getInputClass(string $basePath, Filesystem $filesystem): ?strin return null; } - $file = PhpFile::fromCode($filesystem->get($fullPath)); + return $pathToClassAction->execute($fullPath); + } - /** @phpstan-var array $classes */ - $classes = $file->getClasses(); - if ($classes === []) { - $this->writeError(sprintf('Provided file does not contain any class [%s]', $class)); - return null; - } + return $this->checkInterface($class); + } - $class = array_keys($classes)[0]; - } + /** + * @return array + */ + private function findAllClasses(Finder $finder, PathToClassAction $pathToClassAction): array + { + $classes = []; + foreach ($finder as $file) { + $interface = $pathToClassAction->execute($file->getRealPath()); + require_once $file->getPathname(); - if (class_exists($class) === false && interface_exists($class) === false) { - $this->writeError(sprintf('Provided class does not exists [%s]', $class)); - return null; + if (interface_exists($interface, false) === false) { + continue; + } + + $classReflection = new ReflectionClass($interface); + $attributes = $classReflection->getAttributes(TestAssert::class); + if ($attributes === []) { + continue; + } + $classes[] = $interface; } - return $class; + return $classes; } } diff --git a/src/Testing/Contracts/FinderFactoryContract.php b/src/Testing/Contracts/FinderFactoryContract.php new file mode 100644 index 00000000..5a61a97b --- /dev/null +++ b/src/Testing/Contracts/FinderFactoryContract.php @@ -0,0 +1,12 @@ +files() + ->name('*.php') + ->in($this->composerAutoloadAbsoluteAction->execute()) + ->notName('*.blade.php'); + } +} diff --git a/src/Testing/Services/ComposerJsonDataService.php b/src/Testing/Services/ComposerJsonDataService.php new file mode 100644 index 00000000..72089634 --- /dev/null +++ b/src/Testing/Services/ComposerJsonDataService.php @@ -0,0 +1,47 @@ +filesystem->isFile(self::composerJson($basePath)); + } + + public function data(string $basePath): mixed + { + $path = realpath($basePath); + if ($path === false) { + throw new RuntimeException(sprintf('File does not exists %s.', $basePath)); + } + return $this->cacheMeServiceContract->get( + key: sprintf('larasctrict.composer.%s', $path), + getValue: fn (): mixed => json_decode( + $this->filesystem->get(self::composerJson($path)), + true, + 512, + JSON_THROW_ON_ERROR + ), + strategy: CacheMeStrategy::Memory, + ); + } + + private static function composerJson(string $path): string + { + return $path . '/composer.json'; + } +} diff --git a/src/Testing/TestServiceProvider.php b/src/Testing/TestServiceProvider.php index 2fa845c7..ada45da2 100644 --- a/src/Testing/TestServiceProvider.php +++ b/src/Testing/TestServiceProvider.php @@ -11,15 +11,18 @@ use LaraStrict\Testing\Actions\GetBasePathForStubsAction; use LaraStrict\Testing\Actions\GetNamespaceForStubsAction; use LaraStrict\Testing\Commands\MakeExpectationCommand; +use LaraStrict\Testing\Contracts\FinderFactoryContract; use LaraStrict\Testing\Contracts\GetBasePathForStubsActionContract; use LaraStrict\Testing\Contracts\GetNamespaceForStubsActionContract; use LaraStrict\Testing\Core\Services\NoSleepService; +use LaraStrict\Testing\Factories\FinderFactory; class TestServiceProvider extends ServiceProvider { public array $bindings = [ GetBasePathForStubsActionContract::class => GetBasePathForStubsAction::class, GetNamespaceForStubsActionContract::class => GetNamespaceForStubsAction::class, + FinderFactoryContract::class => FinderFactory::class, ]; public function register(): void From e194c9091a9c01efaf3412b57693e75fcbe79721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Mat=C4=9Bj=C4=8Dek?= Date: Thu, 21 Dec 2023 13:17:43 +0100 Subject: [PATCH 2/5] constants --- .../Actions/ComposerAutoloadAbsoluteAction.php | 15 ++++++++++----- .../Actions/GetNamespaceForStubsAction.php | 9 +++------ src/Testing/Constants/ComposerConstants.php | 10 ++++++++++ 3 files changed, 23 insertions(+), 11 deletions(-) create mode 100644 src/Testing/Constants/ComposerConstants.php diff --git a/src/Testing/Actions/ComposerAutoloadAbsoluteAction.php b/src/Testing/Actions/ComposerAutoloadAbsoluteAction.php index 3f0dc5b6..5c5df475 100644 --- a/src/Testing/Actions/ComposerAutoloadAbsoluteAction.php +++ b/src/Testing/Actions/ComposerAutoloadAbsoluteAction.php @@ -6,6 +6,7 @@ use Exception; use Illuminate\Filesystem\Filesystem; +use LaraStrict\Testing\Constants\ComposerConstants; use LaraStrict\Testing\Contracts\GetBasePathForStubsActionContract; use LaraStrict\Testing\Services\ComposerJsonDataService; @@ -21,7 +22,7 @@ public function __construct( private readonly Filesystem $filesystem, GetBasePathForStubsActionContract $getBasePathForStubsAction, ) { - $this->dirs = $this->makeDirs($getBasePathForStubsAction->execute()); + $this->dirs = $this->prepareSourceDirs($getBasePathForStubsAction->execute()); } /** @@ -39,13 +40,17 @@ public function execute(?string $path = null): array /** * @return array */ - private function makeDirs(string $basePath): array + private function prepareSourceDirs(string $basePath): array { $data = $this->getComposerJsonDataAction->data($basePath); $dirs = []; - if (isset($data['autoload']['psr-4']) && is_array($data['autoload']['psr-4'])) { - foreach ($data['autoload']['psr-4'] as $ns => $path) { + foreach ([ComposerConstants::AutoLoad, ComposerConstants::AutoLoadDev] as $section) { + if (isset($data[$section][ComposerConstants::Psr4]) === false || is_array($data[$section][ComposerConstants::Psr4]) === false) { + continue; + } + + foreach ($data[$section][ComposerConstants::Psr4] as $ns => $path) { $dirs[$ns] = $basePath . DIRECTORY_SEPARATOR . trim((string) $path, '\\/'); } } @@ -68,6 +73,6 @@ private function loadNewComposer(string $path): array $path = $this->filesystem->dirname($path); } - return $this->makeDirs($path); + return $this->prepareSourceDirs($path); } } diff --git a/src/Testing/Actions/GetNamespaceForStubsAction.php b/src/Testing/Actions/GetNamespaceForStubsAction.php index 25e31e1d..b15247f3 100644 --- a/src/Testing/Actions/GetNamespaceForStubsAction.php +++ b/src/Testing/Actions/GetNamespaceForStubsAction.php @@ -5,6 +5,7 @@ namespace LaraStrict\Testing\Actions; use Illuminate\Console\Command; +use LaraStrict\Testing\Constants\ComposerConstants; use LaraStrict\Testing\Constants\StubConstants; use LaraStrict\Testing\Contracts\GetNamespaceForStubsActionContract; use LaraStrict\Testing\Entities\NamespaceEntity; @@ -13,9 +14,6 @@ class GetNamespaceForStubsAction implements GetNamespaceForStubsActionContract { - final public const ComposerAutoLoadDev = 'autoload-dev'; - final public const ComposerPsr4 = 'psr-4'; - public function __construct( private readonly ComposerJsonDataService $getComposerJsonDataAction, ) { @@ -49,9 +47,8 @@ public function execute(Command $command, string $basePath, string $inputClass): private function getComposerDevAutoLoad(array $composer): array { - if (isset($composer[self::ComposerAutoLoadDev]) - && isset($composer[self::ComposerAutoLoadDev][self::ComposerPsr4])) { - return $composer[self::ComposerAutoLoadDev][self::ComposerPsr4]; + if (isset($composer[ComposerConstants::AutoLoadDev][ComposerConstants::Psr4])) { + return $composer[ComposerConstants::AutoLoadDev][ComposerConstants::Psr4]; } return []; diff --git a/src/Testing/Constants/ComposerConstants.php b/src/Testing/Constants/ComposerConstants.php new file mode 100644 index 00000000..017d11b0 --- /dev/null +++ b/src/Testing/Constants/ComposerConstants.php @@ -0,0 +1,10 @@ + Date: Thu, 21 Dec 2023 17:05:12 +0100 Subject: [PATCH 3/5] WIP [ci skip] --- src/Testing/Actions/PathToClassAction.php | 34 +++++++---- .../MakeExpectationCommand/composer.json | 7 +++ .../Commands/MakeExpectationCommandTest.php | 58 ++++++++++++++----- 3 files changed, 76 insertions(+), 23 deletions(-) create mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/composer.json diff --git a/src/Testing/Actions/PathToClassAction.php b/src/Testing/Actions/PathToClassAction.php index 71e3ae8c..6253ad66 100644 --- a/src/Testing/Actions/PathToClassAction.php +++ b/src/Testing/Actions/PathToClassAction.php @@ -40,23 +40,37 @@ public function execute(string $path): string */ private function replacePathToClass(array $dirs, string $path): ?string { + $map = []; foreach ($dirs as $ns => $dir) { if (str_starts_with($path, $dir) === false) { continue; } - /** @var class-string $class */ - $class = preg_replace_callback( - sprintf('~^%s[/\\\](?.*)\.php$~', preg_quote($dir, '~')), - static fn (array $matches) => $ns . strtr($matches['path'], [ + + $map[] = [ + 'count' => strlen($ns), + 'data' => ['ns' => $ns, 'dir' => $dir], + ]; + } + + if ($map === []) { + return null; + } + + usort($map, static fn(array $a, array $b) => $b['count'] <=> $a['count']); + ['dir' => $dir, 'ns' => $ns] = $map[0]['data']; + + /** @var class-string $class */ + $class = preg_replace_callback( + sprintf('~^%s[/\\\](?.*)\.php$~', preg_quote($dir, '~')), + static fn (array $matches) => $ns . strtr($matches['path'], [ '/' => '\\', ]), - $path - ); - assert(is_string($class)); + $path + ); + assert(is_string($class)); + + return $class; - return $class; - } - return null; } } diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/composer.json b/tests/Feature/Testing/Commands/MakeExpectationCommand/composer.json new file mode 100644 index 00000000..450ac9ed --- /dev/null +++ b/tests/Feature/Testing/Commands/MakeExpectationCommand/composer.json @@ -0,0 +1,7 @@ +{ + "autoload-dev": { + "psr-4": { + "App\\Tests\\": "app/tests/" + } + } +} diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommandTest.php b/tests/Feature/Testing/Commands/MakeExpectationCommandTest.php index fb4de6a1..c2db1e4a 100644 --- a/tests/Feature/Testing/Commands/MakeExpectationCommandTest.php +++ b/tests/Feature/Testing/Commands/MakeExpectationCommandTest.php @@ -242,6 +242,15 @@ protected function expectClass(bool $useClass, string $fileName = 'TestAction'): ->once() ->withArgs($this->expectClassFileExistsArgClosure()) ->andReturn(file_get_contents($realPath)); + $this->fileSystem->shouldReceive('isFile') + ->once() + ->withArgs($this->expectClassFileExistsArgClosure()) + ->andReturn(true); + + $this->fileSystem->shouldReceive('dirname') + ->once() + ->withArgs($this->expectClassFileExistsArgClosure()) + ->andReturn(dirname($realPath)); } } @@ -254,23 +263,47 @@ protected function assertCommand( bool $expectComposerJson = true, ): void { if ($expectComposerJson) { + if ($variantPrefix !== null) { + $composerPath = __DIR__ . DIRECTORY_SEPARATOR . 'MakeExpectationCommand' . DIRECTORY_SEPARATOR . $variantPrefix . '.composer.json'; + } else { + $composerPath = __DIR__ . DIRECTORY_SEPARATOR . 'MakeExpectationCommand' . DIRECTORY_SEPARATOR . 'composer.json'; + } + + $expectedComposerCheck = __DIR__ . DIRECTORY_SEPARATOR . 'MakeExpectationCommand' . DIRECTORY_SEPARATOR . 'composer.json'; + + // We are checking if the composer we detect exists + // our implementation expets always composer.json file + $this->fileSystem->shouldReceive('isFile') + ->once() + ->with(function($arg) use ($expectedComposerCheck){ + + $x = 1; + }) + ->andReturn(true); + $this->fileSystem->shouldReceive('get') ->once() - ->withArgs( - static fn (string $path): bool => str_contains( - $path, - '/vendor/orchestra/testbench-core/laravel/composer.json' - ) - ) - ->andReturnUsing(static function (string $path) use ($variantPrefix): string { - if ($variantPrefix !== null) { - $variantPrefix = __DIR__ . DIRECTORY_SEPARATOR . 'MakeExpectationCommand' . DIRECTORY_SEPARATOR . $variantPrefix . '.composer.json'; + ->with($expectedComposerCheck) + ->andReturnUsing(static function (string $path) use ($composerPath): string { + $fileGetContents = file_get_contents($composerPath); + if ($fileGetContents === false) { + throw new LogicException('File not loaded' . $composerPath); } - $filePath = $variantPrefix ?? $path; - $fileGetContents = file_get_contents($filePath); + return $fileGetContents; + }); + + //Transform real testbanch composer to our expectation composer + $this->fileSystem->shouldReceive('get') + ->once() + ->withArgs(static fn (string $path): bool => str_contains( + $path, + '/vendor/orchestra/testbench-core/laravel/composer.json' + )) + ->andReturnUsing(static function (string $path) use ($composerPath): string { + $fileGetContents = file_get_contents($composerPath); if ($fileGetContents === false) { - throw new LogicException('File not loaded' . $filePath); + throw new LogicException('File not loaded' . $composerPath); } return $fileGetContents; @@ -328,7 +361,6 @@ protected function expectResultFile( ]); $this->fileSystem->shouldReceive('ensureDirectoryExists') - ->once() ->withArgs(static fn (string $path): bool => str_contains($path, $expectedPath)); $this->fileSystem->shouldReceive('put') From 2cd407a24e1f7224fc6450c66edb3d4aa9b8ff25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Mat=C4=9Bj=C4=8Dek?= Date: Thu, 15 Feb 2024 16:12:28 +0100 Subject: [PATCH 4/5] WIP [ci skip] --- artisan | 3 + .../Actions/ExpectationFileContentAction.php | 183 ++++++ .../Actions/ExpectationMethodAssertAction.php | 86 +++ src/Testing/Actions/FindAllClassesAction.php | 44 ++ .../Actions/GenerateAssertClassAction.php | 39 ++ .../GenerateExpectationClassAction.php | 167 ++++++ .../Actions/GetBasePathForAssertsAction.php | 21 + .../GetDevBasePathForAssertsAction.php | 30 + .../Actions/GetDevBasePathForStubs.php | 6 +- .../Actions/GetDevNamespaceForStubsAction.php | 3 +- .../Actions/GetNamespaceForStubsAction.php | 5 +- .../InputArgumentClassToClassesAction.php | 65 +++ src/Testing/Actions/ParsePhpDocAction.php | 3 +- ...on.php => PathToClassByComposerAction.php} | 2 +- src/Testing/Actions/WritePhpFileAction.php | 21 + src/Testing/Attributes/Expectation.php | 13 + .../Commands/MakeExpectationCommand.php | 531 +----------------- .../FindAllClassesActionContract.php | 11 + .../GetBasePathForAssertsActionContract.php | 8 + .../GetNamespaceForStubsActionContract.php | 2 +- .../Entities/AssertFileStateEntity.php | 6 +- src/Testing/Exceptions/LogicException.php | 16 + src/Testing/TestServiceProvider.php | 6 + .../MultiFunctionContractAssert.php.stub | 266 --------- ...iFunctionContractMixedExpectation.php.stub | 20 - ...nctionContractNoParamsExpectation.php.stub | 17 - ...nctionContractNoReturnExpectation.php.stub | 19 - ...tionContractPhpDocBoolExpectation.php.stub | 20 - ...ionContractPhpDocFloatExpectation.php.stub | 20 - ...ionContractPhpDocMixedExpectation.php.stub | 20 - ...onContractPhpDocStaticExpectation.php.stub | 19 - ...onContractPhpDocStringExpectation.php.stub | 20 - ...tionContractPhpDocThisExpectation.php.stub | 19 - ...ntractPhpDocThisParamsExpectation.php.stub | 19 - ...tiFunctionContractSelfExpectation.php.stub | 19 - ...onContractSelfViaClassExpectation.php.stub | 20 - .../SimpleActionContractAssert.php | 7 +- ...impleActionContractExecuteExpectation.php} | 2 +- .../TestActionContractAssert.php.stub | 64 --- .../TestActionContractExpectation.php.stub | 33 -- .../TestActionExpectation.php.stub | 33 -- .../TestReturnActionContractAssert.php.stub | 66 --- ...stReturnActionContractExpectation.php.stub | 34 -- .../TestReturnActionExpectation.php.stub | 34 -- ...turnIntersectionActionExpectation.php.stub | 34 -- ...stReturnRequiredActionExpectation.php.stub | 34 -- ...stReturnUnionActionContractAssert.php.stub | 66 --- ...urnUnionActionContractExpectation.php.stub | 34 -- .../TestReturnUnionActionExpectation.php.stub | 34 -- .../one.TestActionContractAssert.php.stub | 64 --- ...one.TestActionContractExpectation.php.stub | 33 -- .../one.TestActionExpectation.php.stub | 33 -- ...ne.TestReturnActionContractAssert.php.stub | 66 --- ...stReturnActionContractExpectation.php.stub | 34 -- .../one.TestReturnActionExpectation.php.stub | 34 -- ...turnIntersectionActionExpectation.php.stub | 34 -- ...stReturnRequiredActionExpectation.php.stub | 34 -- ...stReturnUnionActionContractAssert.php.stub | 66 --- ...urnUnionActionContractExpectation.php.stub | 34 -- ....TestReturnUnionActionExpectation.php.stub | 34 -- .../two.TestActionContractAssert.php.stub | 64 --- ...two.TestActionContractExpectation.php.stub | 33 -- .../two.TestActionExpectation.php.stub | 33 -- ...wo.TestReturnActionContractAssert.php.stub | 66 --- ...stReturnActionContractExpectation.php.stub | 34 -- .../two.TestReturnActionExpectation.php.stub | 34 -- ...turnIntersectionActionExpectation.php.stub | 34 -- ...stReturnRequiredActionExpectation.php.stub | 34 -- ...stReturnUnionActionContractAssert.php.stub | 66 --- ...urnUnionActionContractExpectation.php.stub | 34 -- ....TestReturnUnionActionExpectation.php.stub | 34 -- .../Commands/MakeExpectationCommandTest.php | 45 +- .../one.MultiFunctionContractAssert.stub.php} | 12 + ...FunctionContractMixedExpectation.stub.php} | 0 ...ctionContractNoParamsExpectation.stub.php} | 0 ...ctionContractNoReturnExpectation.stub.php} | 0 ...ionContractPhpDocBoolExpectation.stub.php} | 0 ...onContractPhpDocFloatExpectation.stub.php} | 0 ...onContractPhpDocMixedExpectation.stub.php} | 0 ...nContractPhpDocStaticExpectation.stub.php} | 0 ...nContractPhpDocStringExpectation.stub.php} | 0 ...ionContractPhpDocThisExpectation.stub.php} | 0 ...tractPhpDocThisParamsExpectation.stub.php} | 0 ...iFunctionContractSelfExpectation.stub.php} | 0 ...nContractSelfViaClassExpectation.stub.php} | 0 .../two.MultiFunctionContractAssert.stub.php} | 12 + ...FunctionContractMixedExpectation.stub.php} | 0 ...ctionContractNoParamsExpectation.stub.php} | 0 ...ctionContractNoReturnExpectation.stub.php} | 0 ...ionContractPhpDocBoolExpectation.stub.php} | 0 ...onContractPhpDocFloatExpectation.stub.php} | 0 ...onContractPhpDocMixedExpectation.stub.php} | 0 ...nContractPhpDocStaticExpectation.stub.php} | 0 ...nContractPhpDocStringExpectation.stub.php} | 0 ...ionContractPhpDocThisExpectation.stub.php} | 0 ...tractPhpDocThisParamsExpectation.stub.php} | 0 ...iFunctionContractSelfExpectation.stub.php} | 0 ...nContractSelfViaClassExpectation.stub.php} | 0 .../GetDevNamespaceForStubsActionTest.php | 2 +- 99 files changed, 810 insertions(+), 2437 deletions(-) create mode 100644 src/Testing/Actions/ExpectationFileContentAction.php create mode 100644 src/Testing/Actions/ExpectationMethodAssertAction.php create mode 100644 src/Testing/Actions/FindAllClassesAction.php create mode 100644 src/Testing/Actions/GenerateAssertClassAction.php create mode 100644 src/Testing/Actions/GenerateExpectationClassAction.php create mode 100644 src/Testing/Actions/GetBasePathForAssertsAction.php create mode 100644 src/Testing/Actions/GetDevBasePathForAssertsAction.php create mode 100644 src/Testing/Actions/InputArgumentClassToClassesAction.php rename src/Testing/Actions/{PathToClassAction.php => PathToClassByComposerAction.php} (97%) create mode 100644 src/Testing/Actions/WritePhpFileAction.php create mode 100644 src/Testing/Attributes/Expectation.php create mode 100644 src/Testing/Contracts/FindAllClassesActionContract.php create mode 100644 src/Testing/Contracts/GetBasePathForAssertsActionContract.php create mode 100644 src/Testing/Exceptions/LogicException.php delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractAssert.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractMixedExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractNoParamsExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractNoReturnExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractPhpDocBoolExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractPhpDocFloatExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractPhpDocMixedExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractPhpDocStaticExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractPhpDocStringExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractPhpDocThisExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractPhpDocThisParamsExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractSelfExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractSelfViaClassExpectation.php.stub rename tests/Feature/Testing/Commands/MakeExpectationCommand/{SimpleActionContractExpectation.php => SimpleActionContractExecuteExpectation.php} (88%) delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/TestActionContractAssert.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/TestActionContractExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/TestActionExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/TestReturnActionContractAssert.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/TestReturnActionContractExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/TestReturnActionExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/TestReturnIntersectionActionExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/TestReturnRequiredActionExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/TestReturnUnionActionContractAssert.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/TestReturnUnionActionContractExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/TestReturnUnionActionExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestActionContractAssert.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestActionContractExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestActionExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestReturnActionContractAssert.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestReturnActionContractExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestReturnActionExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestReturnIntersectionActionExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestReturnRequiredActionExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestReturnUnionActionContractAssert.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestReturnUnionActionContractExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestReturnUnionActionExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestActionContractAssert.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestActionContractExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestActionExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestReturnActionContractAssert.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestReturnActionContractExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestReturnActionExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestReturnIntersectionActionExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestReturnRequiredActionExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestReturnUnionActionContractAssert.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestReturnUnionActionContractExpectation.php.stub delete mode 100644 tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestReturnUnionActionExpectation.php.stub rename tests/{Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractAssert.php.stub => Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractAssert.stub.php} (89%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractMixedExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractMixedExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractNoParamsExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractNoParamsExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractNoReturnExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractNoReturnExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocBoolExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocBoolExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocFloatExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocFloatExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocMixedExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocMixedExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocStaticExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocStaticExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocStringExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocStringExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocThisExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocThisExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocThisParamsExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocThisParamsExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractSelfExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractSelfExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractSelfViaClassExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractSelfViaClassExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractAssert.php.stub => Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractAssert.stub.php} (89%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractMixedExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractMixedExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractNoParamsExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractNoParamsExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractNoReturnExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractNoReturnExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocBoolExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocBoolExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocFloatExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocFloatExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocMixedExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocMixedExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocStaticExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocStaticExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocStringExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocStringExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocThisExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocThisExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocThisParamsExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocThisParamsExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractSelfExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractSelfExpectation.stub.php} (100%) rename tests/{Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractSelfViaClassExpectation.php.stub => Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractSelfViaClassExpectation.stub.php} (100%) diff --git a/artisan b/artisan index 8bbce776..51b9586a 100755 --- a/artisan +++ b/artisan @@ -2,8 +2,10 @@ providers() as $provider) { $app->register(\LaraStrict\Core\LaraStrictServiceProvider::class); $app->bind(GetBasePathForStubsActionContract::class, GetDevBasePathForStubs::class); +$app->bind(GetBasePathForAssertsActionContract::class, GetDevBasePathForAssertsAction::class); $app->bind(GetNamespaceForStubsActionContract::class, GetDevNamespaceForStubsAction::class); $status = $kernel->handle( diff --git a/src/Testing/Actions/ExpectationFileContentAction.php b/src/Testing/Actions/ExpectationFileContentAction.php new file mode 100644 index 00000000..7ec7961c --- /dev/null +++ b/src/Testing/Actions/ExpectationFileContentAction.php @@ -0,0 +1,183 @@ +getParameters(); + + $file = new PhpFile(); + $file->setStrictTypes(); + + $class = $file + ->addNamespace($namespace) + ->addClass($className); + + $constructor = $class + ->setFinal() + ->addMethod('__construct'); + + $returnType = $method->getReturnType(); + if ($returnType !== null && + ($returnType instanceof ReflectionNamedType === false || self::canReturnExpectation($returnType)) || + $phpDoc->returnType === PhpType::Mixed) { + $constructorParameter = $constructor + ->addPromotedParameter('return') + ->setReadOnly(); + + $this->setParameterType($returnType, $constructorParameter); + } + + $parameterTypes = []; + foreach ($parameters as $parameter) { + $constructorParameter = $constructor + ->addPromotedParameter($parameter->name) + ->setReadOnly(); + + $parameterTypes[] = $this->setParameterType($parameter->getType(), $constructorParameter); + $this->setParameterDefaultValue($parameter, $constructorParameter); + } + $parameterTypes[] = 'self'; + + $constructor + ->addPromotedParameter(self::HookProperty) + ->setReadOnly() + ->setType('\Closure') + ->setNullable() + ->setDefaultValue(null); + + $constructor->addComment( + sprintf('@param \Closure(%s):void|null $%s', implode(',', $parameterTypes), self::HookProperty) + ); + + return $printer->printFile($file); + } + + + private static function canReturnExpectation(ReflectionNamedType $returnType): bool + { + return $returnType->getName() !== PhpType::Void->value + && $returnType->getName() !== PhpType::Self->value + && $returnType->getName() !== PhpType::Static ->value; + } + + + private function setParameterType( + ReflectionType|ReflectionNamedType|ReflectionUnionType|ReflectionIntersectionType|null $type, + PromotedParameter $constructorParameter + ): string + { + $proposedType = ''; + + $allowNull = false; + $mapToName = static function (ReflectionType $type) use (&$allowNull): ?string { + if ($type instanceof ReflectionNamedType) { + $name = $type->getName(); + if ($name === 'null') { + $allowNull = false; + } + + // Fix global namespace + if (class_exists($name)) { + return '\\' . $name; + } + + return $name; + } + + return null; + }; + + // TODO move to separate action and test with unit test + if ($type instanceof ReflectionNamedType) { + $allowNull = $type->allowsNull(); + $proposedType = $type->getName(); + + if (class_exists($proposedType)) { + // Fix global namespace + $proposedType = '\\' . $proposedType; + } + + $constructorParameter->setNullable($type->allowsNull()); + } elseif ($type instanceof ReflectionUnionType) { + $allowNull = $type->allowsNull(); + $proposedType = implode('|', array_filter(array_map($mapToName, $type->getTypes()))); + } elseif ($type instanceof ReflectionIntersectionType) { + $allowNull = $type->allowsNull(); + $proposedType = implode('&', array_filter(array_map($mapToName, $type->getTypes()))); + } + + if ($proposedType === '') { + $proposedType = 'mixed'; + } + + if ($allowNull) { + $constructorParameter->setNullable($allowNull); + } + + // Callable not supported in property + if ($proposedType === 'callable') { + $proposedType = '\Closure'; + } + + $constructorParameter->setType($proposedType); + + return $proposedType; + } + + + private function setParameterDefaultValue( + ReflectionParameter $parameter, + PromotedParameter $constructorParameter + ): void + { + if ($parameter->isDefaultValueAvailable() === false) { + return; + } + + if ($parameter->isDefaultValueConstant()) { + $constant = $parameter->getDefaultValueConstantName(); + // Ensure that constants are from global scope + $constantLiteral = new Literal(StubConstants::NameSpaceSeparator . $constant); + $constructorParameter->setDefaultValue($constantLiteral); + + return; + } + + $defaultValue = $parameter->getDefaultValue(); + + if (is_object($defaultValue)) { + $objectLiteral = new Literal( + 'new ' . StubConstants::NameSpaceSeparator . $defaultValue::class . '(/* unknown */)' + ); + $constructorParameter->setDefaultValue($objectLiteral); + } else { + $constructorParameter->setDefaultValue($defaultValue); + } + } +} diff --git a/src/Testing/Actions/ExpectationMethodAssertAction.php b/src/Testing/Actions/ExpectationMethodAssertAction.php new file mode 100644 index 00000000..7b7bc94c --- /dev/null +++ b/src/Testing/Actions/ExpectationMethodAssertAction.php @@ -0,0 +1,86 @@ +getParameters(); + + $assertMethod = (new Factory())->fromMethodReflection($method); + $assertClass->addMember($assertMethod); + + $assertMethod->addBody(sprintf( + '$_expectation = $this->getExpectation(%s);', + $expectationClassName . '::class' + )); + + $hookParameters = []; + + if ($parameters !== []) { + $assertMethod->addBody('$_message = $this->getDebugMessage();'); + $assertMethod->addBody(''); + + foreach ($parameters as $parameter) { + $hookParameters[] = sprintf('$%s', $parameter->name); + $assertMethod->addBody(sprintf( + 'Assert::assertEquals($_expectation->%s, $%s, $_message);', + $parameter->name, + $parameter->name + )); + } + } + + $hookParameters[] = '$_expectation'; + + $assertMethod->addBody(''); + + $assertMethod->addBody(sprintf('if (is_callable($_expectation->%s)) {', ExpectationFileContentAction::HookProperty)); + $assertMethod->addBody(sprintf( + ' call_user_func($_expectation->%s, %s);', + ExpectationFileContentAction::HookProperty, + implode(', ', $hookParameters), + )); + $assertMethod->addBody('}'); + + $returnType = $method->getReturnType(); + + if ($returnType instanceof ReflectionNamedType) { + $enumReturnType = PhpType::tryFrom($returnType->getName()) ?? PhpType::Mixed; + } elseif ($returnType instanceof ReflectionUnionType) { + $enumReturnType = PhpType::Mixed; + } else { + $enumReturnType = $phpDoc->returnType; + } + + switch ($enumReturnType) { + case PhpType::Mixed: + $assertMethod->addBody(''); + $assertMethod->addBody('return $_expectation->return;'); + break; + case PhpType::Self: + case PhpType::Static: + $assertMethod->addBody(''); + $assertMethod->addBody('return $this;'); + break; + } + } +} diff --git a/src/Testing/Actions/FindAllClassesAction.php b/src/Testing/Actions/FindAllClassesAction.php new file mode 100644 index 00000000..4d21fc4b --- /dev/null +++ b/src/Testing/Actions/FindAllClassesAction.php @@ -0,0 +1,44 @@ + + */ + public function execute(): array + { + $classes = []; + foreach ($this->finderFactory->create() as $file) { + $interface = $this->pathToClassAction->execute($file->getRealPath()); + require_once $file->getPathname(); + + if (interface_exists($interface, false) === false) { + continue; + } + + $classReflection = new ReflectionClass($interface); + $attributes = $classReflection->getAttributes(TestAssert::class); + if ($attributes === []) { + continue; + } + $classes[] = $interface; + } + + return $classes; + } +} diff --git a/src/Testing/Actions/GenerateAssertClassAction.php b/src/Testing/Actions/GenerateAssertClassAction.php new file mode 100644 index 00000000..f1e99405 --- /dev/null +++ b/src/Testing/Actions/GenerateAssertClassAction.php @@ -0,0 +1,39 @@ + $class + */ + public function execute( + ReflectionClass $class, + string $namespace, + ): AssertFileStateEntity + { + $file = new PhpFile(); + $file->setStrictTypes(); + + $assertNamespace = $file->addNamespace($namespace); + $assertNamespace->addUse(Assert::class); + + $assertClass = $assertNamespace->addClass($class->getShortName() . 'Assert'); + $assertClass->addImplement($class->getName()); + + $assertConstructor = new Method('__construct'); + $assertClass->setExtends(AbstractExpectationCallsMap::class); + $assertClass->addMember($assertConstructor); + + $assertConstructor->addBody('parent::__construct();'); + + return new AssertFileStateEntity($file, $assertClass, $assertConstructor); + } +} diff --git a/src/Testing/Actions/GenerateExpectationClassAction.php b/src/Testing/Actions/GenerateExpectationClassAction.php new file mode 100644 index 00000000..041df9ca --- /dev/null +++ b/src/Testing/Actions/GenerateExpectationClassAction.php @@ -0,0 +1,167 @@ +} + */ + public function execute( + string $inputClass, + NamespaceEntity $namespace, + ): array { + $class = new ReflectionClass($inputClass); + $methods = self::checkInputClass($class); + + $fileNamespace = self::makeFileNamespace($class, $namespace); + + // Base namespace can contain + $directory = $this->getBasePathForAssetsAction->execute() . DIRECTORY_SEPARATOR . $namespace->folder . strtr( + $fileNamespace, + StubConstants::NameSpaceSeparator, + DIRECTORY_SEPARATOR, + ); + $fullNamespace = $namespace->baseNamespace . $fileNamespace; + + $this->filesystem->ensureDirectoryExists($directory); + + // Generate assert file that uses generated expectation in a construct + $assertFileState = $this->generateAssertClassAction->execute( + class: $class, + namespace: $fullNamespace, + ); + + $assertClassName = $assertFileState->class->getName(); + assert(is_string($assertClassName)); + + $printer = new PsrPrinter(); + $expectations = []; + foreach ($methods as $method) { + $expectationClassName = self::makeExpectationClassName($class, $method); + $phpDoc = $this->parsePhpDocAction->execute($method); + + $expectationContent = $this->expectationFileContentAction->execute( + printer: $printer, + namespace: $fullNamespace, + className: $expectationClassName, + method: $method, + phpDoc: $phpDoc, + ); + + $this->expectationMethodAssertAction->execute( + assertClass: $assertFileState->class, + method: $method, + expectationClassName: $expectationClassName, + phpDoc: $phpDoc, + ); + + $expectations[] = $this->writePhpFileAction->execute($directory, $expectationClassName, $expectationContent); + $assertFileState->expectationClasses[$method->getName()] = $expectationClassName; + } + + $this->addAttributes($assertFileState); + + $assertFilePath = $this->writePhpFileAction->execute( + directory: $directory, + className: $assertClassName, + content: $printer->printFile($assertFileState->file), + ); + + return ['assert' => $assertFilePath, 'expectations' => $expectations]; + } + + /** + * @param ReflectionClass $class + */ + private static function makeFileNamespace(ReflectionClass $class, NamespaceEntity $namespace): string + { + $classNamespace = $class->getNamespaceName(); + if (str_starts_with($classNamespace, $namespace->baseNamespace) === false) { + $namespaceParts = explode(StubConstants::NameSpaceSeparator, $classNamespace); + array_shift($namespaceParts); + + return implode(StubConstants::NameSpaceSeparator, $namespaceParts); + } + + return str_replace($namespace->baseNamespace, '', $classNamespace); + } + + /** + * @param ReflectionClass $class + * @return array + */ + private static function checkInputClass(ReflectionClass $class): array + { + $methods = $class->getMethods(ReflectionMethod::IS_PUBLIC); + + if ($methods === []) { + throw new LogicException('Class %s does not contain any public', $class->getName()); + } else if ($class->isInterface() === false) { + throw new LogicException('Class %s is not interface', $class->getName()); + } + + return $methods; + } + + /** + * @param ReflectionClass $class + */ + private static function makeExpectationClassName(ReflectionClass $class, ReflectionMethod $method): string + { + $methodSuffix = Str::ucfirst($method->getName()); + + return $class->getShortName() . $methodSuffix . 'Expectation'; + } + + private function addAttributes(AssertFileStateEntity $assertFileState): void + { + foreach ($assertFileState->expectationClasses as $methodName => $expectationClass) { + $assertFileState->constructor->addComment(sprintf( + '@param array<%s|null> $%s', + $expectationClass, + $methodName, + )); + + $assertFileState->constructor->addBody(sprintf( + '$this->setExpectations(%s::class, $%s);', + $expectationClass, + $methodName, + )); + + $assertFileState->constructor + ->addParameter($methodName) + ->setType('array') + ->setDefaultValue(new Literal('[]')); + + $assertFileState->class->addAttribute(Expectation::class, [ + 'class' => new Literal($expectationClass . '::class'), + ]); + } + } + +} diff --git a/src/Testing/Actions/GetBasePathForAssertsAction.php b/src/Testing/Actions/GetBasePathForAssertsAction.php new file mode 100644 index 00000000..508e461a --- /dev/null +++ b/src/Testing/Actions/GetBasePathForAssertsAction.php @@ -0,0 +1,21 @@ +application->basePath(); + } +} diff --git a/src/Testing/Actions/GetDevBasePathForAssertsAction.php b/src/Testing/Actions/GetDevBasePathForAssertsAction.php new file mode 100644 index 00000000..2a858c7e --- /dev/null +++ b/src/Testing/Actions/GetDevBasePathForAssertsAction.php @@ -0,0 +1,30 @@ +application->basePath(); + $path = realpath($basePath . '/../../../../tests/Stubs/Asserts'); + + if (is_string($path) === false) { + throw new LogicException('Failed to create dev base path'); + } + + return $path; + } +} diff --git a/src/Testing/Actions/GetDevBasePathForStubs.php b/src/Testing/Actions/GetDevBasePathForStubs.php index 1e2287f5..8be57745 100644 --- a/src/Testing/Actions/GetDevBasePathForStubs.php +++ b/src/Testing/Actions/GetDevBasePathForStubs.php @@ -6,15 +6,17 @@ use Illuminate\Contracts\Foundation\Application; use LaraStrict\Testing\Contracts\GetBasePathForStubsActionContract; -use LogicException; +use LaraStrict\Testing\Exceptions\LogicException; class GetDevBasePathForStubs implements GetBasePathForStubsActionContract { public function __construct( private readonly Application $application, - ) { + ) + { } + public function execute(): string { // Go to LaraStrict root from orchestra diff --git a/src/Testing/Actions/GetDevNamespaceForStubsAction.php b/src/Testing/Actions/GetDevNamespaceForStubsAction.php index fbeba36c..8fcc8938 100644 --- a/src/Testing/Actions/GetDevNamespaceForStubsAction.php +++ b/src/Testing/Actions/GetDevNamespaceForStubsAction.php @@ -11,7 +11,8 @@ class GetDevNamespaceForStubsAction implements GetNamespaceForStubsActionContract { - public function execute(Command $command, string $basePath, string $inputClass): NamespaceEntity + + public function execute(Command $command, string $inputClass): NamespaceEntity { // We want to place Laravel assert / expectations to Laravel Folder. diff --git a/src/Testing/Actions/GetNamespaceForStubsAction.php b/src/Testing/Actions/GetNamespaceForStubsAction.php index b15247f3..8374bfd9 100644 --- a/src/Testing/Actions/GetNamespaceForStubsAction.php +++ b/src/Testing/Actions/GetNamespaceForStubsAction.php @@ -7,6 +7,7 @@ use Illuminate\Console\Command; use LaraStrict\Testing\Constants\ComposerConstants; use LaraStrict\Testing\Constants\StubConstants; +use LaraStrict\Testing\Contracts\GetBasePathForStubsActionContract; use LaraStrict\Testing\Contracts\GetNamespaceForStubsActionContract; use LaraStrict\Testing\Entities\NamespaceEntity; use LaraStrict\Testing\Services\ComposerJsonDataService; @@ -16,11 +17,13 @@ class GetNamespaceForStubsAction implements GetNamespaceForStubsActionContract { public function __construct( private readonly ComposerJsonDataService $getComposerJsonDataAction, + private readonly GetBasePathForStubsActionContract $getBasePathAction, ) { } - public function execute(Command $command, string $basePath, string $inputClass): NamespaceEntity + public function execute(Command $command, string $inputClass): NamespaceEntity { + $basePath = $this->getBasePathAction->execute(); // Ask for which namespace which to use for "tests" $composer = $this->getComposerJsonDataAction->data($basePath); $autoLoad = $this->getComposerDevAutoLoad($composer); diff --git a/src/Testing/Actions/InputArgumentClassToClassesAction.php b/src/Testing/Actions/InputArgumentClassToClassesAction.php new file mode 100644 index 00000000..1bdff799 --- /dev/null +++ b/src/Testing/Actions/InputArgumentClassToClassesAction.php @@ -0,0 +1,65 @@ + + */ + public function execute(string $class): array + { + if ($class === 'all') { + return $this->findAllClassesAction->execute(); + } elseif (str_ends_with($class, '.php') === false) { + $inClass = $this->checkInterface($class); + } else { + $inClass = $this->normalizeToClass($class); + } + + return $inClass === null ? [] : [$inClass]; + } + + + /** + * @return class-string + */ + private function checkInterface(string $class): ?string + { + if (class_exists($class) === false && interface_exists($class) === false) { + return null; + } + + return $class; + } + + + /** + * @return class-string|null + */ + private function normalizeToClass(string $class): ?string + { + $fullPath = $this->getBasePathAction->execute() . DIRECTORY_SEPARATOR . $class; + + if ($this->filesystem->exists($fullPath) === false) { + return null; + } + + return $this->pathToClassAction->execute($fullPath); + } +} diff --git a/src/Testing/Actions/ParsePhpDocAction.php b/src/Testing/Actions/ParsePhpDocAction.php index bfef1a1d..34983e58 100644 --- a/src/Testing/Actions/ParsePhpDocAction.php +++ b/src/Testing/Actions/ParsePhpDocAction.php @@ -46,7 +46,8 @@ public function execute(ReflectionMethod $method): PhpDocEntity if ($returnTags !== []) { $name = (string) $returnTags[0]->type; $returnType = match ($name) { - '$this', 'self', 'static' => PhpType::Self, + '$this', 'static' => PhpType::Static, + 'self' => PhpType::Self, 'void' => PhpType::Void, default => PhpType::Mixed, }; diff --git a/src/Testing/Actions/PathToClassAction.php b/src/Testing/Actions/PathToClassByComposerAction.php similarity index 97% rename from src/Testing/Actions/PathToClassAction.php rename to src/Testing/Actions/PathToClassByComposerAction.php index 6253ad66..81e31795 100644 --- a/src/Testing/Actions/PathToClassAction.php +++ b/src/Testing/Actions/PathToClassByComposerAction.php @@ -6,7 +6,7 @@ use Exception; -final class PathToClassAction +final class PathToClassByComposerAction { public function __construct( private readonly ComposerAutoloadAbsoluteAction $composerAutoloadAbsoluteAction, diff --git a/src/Testing/Actions/WritePhpFileAction.php b/src/Testing/Actions/WritePhpFileAction.php new file mode 100644 index 00000000..60e584d5 --- /dev/null +++ b/src/Testing/Actions/WritePhpFileAction.php @@ -0,0 +1,21 @@ +filesystem->put($filePath, $content); + + return $filePath; + } +} diff --git a/src/Testing/Attributes/Expectation.php b/src/Testing/Attributes/Expectation.php new file mode 100644 index 00000000..c8b63a55 --- /dev/null +++ b/src/Testing/Attributes/Expectation.php @@ -0,0 +1,13 @@ +execute(); - - /** @phpstan-var class-string|string $class */ + /** @var class-string|string $class */ $class = (string) $this->input->getArgument('class'); - - if ($class === 'all') { - $inputClasses = $this->findAllClasses($finderFactory->create(), $pathToClassAction); - } else { - $inClass = $this->normalizeToClass($class, $basePath, $filesystem, $pathToClassAction); - $inputClasses = $inClass === null ? [] : [$inClass]; - } + $inputClasses = $inputArgumentClassToClassesAction->execute($class); if ($inputClasses === []) { + $this->writeError(sprintf('File or class does not exists at [%s]', $class)); return 1; } foreach ($inputClasses as $inputClass) { - $this->generateExpectationFiles( - $inputClass, - $getFolderAndNamespaceForStubsAction, - $basePath, - $filesystem, - $parsePhpDocAction - ); - } - - return 0; - } - - /** - * @param class-string $inputClass - */ - public function generateExpectationFiles( - string $inputClass, - GetNamespaceForStubsActionContract $getFolderAndNamespaceForStubsAction, - string $basePath, - Filesystem $filesystem, - ParsePhpDocAction $parsePhpDocAction - ): void { - $class = new ReflectionClass($inputClass); - - $methods = $class->getMethods(ReflectionMethod::IS_PUBLIC); - - if ($methods === []) { - throw new LogicException(sprintf('Class %s does not contain any public', $inputClass)); - } + // Ask for which namespace which to use for "tests" + $namespace = $getFolderAndNamespaceForStubsAction->execute($this, $inputClass); - // Ask for which namespace which to use for "tests" - $namespace = $getFolderAndNamespaceForStubsAction->execute($this, $basePath, $inputClass); - - // 1. The first part of namespace should is in 99% App => app. We need to create a valid - // namespace in tests folder, lets remove the first namespace and rebuild the correct - // namespace and file path from it. - // 2. We can get a class within same namespace as a "tests/app" namespace, just remove the base namespace - // to rebuild it later on - $classNamespace = $class->getNamespaceName(); - if (str_starts_with($classNamespace, $namespace->baseNamespace) === false) { - $namespaceParts = explode(StubConstants::NameSpaceSeparator, $classNamespace); - array_shift($namespaceParts); - $fileNamespace = implode(StubConstants::NameSpaceSeparator, $namespaceParts); - } else { - $fileNamespace = str_replace($namespace->baseNamespace, '', $classNamespace); - } - - // Base namespace can contain - $directory = $basePath . DIRECTORY_SEPARATOR . $namespace->folder . strtr( - $fileNamespace, - StubConstants::NameSpaceSeparator, - DIRECTORY_SEPARATOR - ); - $fullNamespace = $namespace->baseNamespace . $fileNamespace; - - $filesystem->ensureDirectoryExists($directory); - - $useSingleMethodCallMap = count($methods) === 1; - - // Generate assert file that uses generated expectation in a construct - $assertClassName = $class->getShortName() . 'Assert'; - $assertFileState = $this->createAssertFileAndClass( - class: $class, - namespace: $fullNamespace, - className: $assertClassName, - ); - - $printer = new PsrPrinter(); - - foreach ($methods as $method) { - $methodSuffix = $useSingleMethodCallMap ? '' : Str::ucfirst($method->getName()); - $expectationClassName = $this->getExpectationClassName($class, $methodSuffix); - - $phpDoc = $parsePhpDocAction->execute($method); - - $this->writeFile( - directory: $directory, - className: $expectationClassName, - filesystem: $filesystem, - fileContents: $this->getExpectationFileContents( - printer: $printer, - namespace: $fullNamespace, - className: $expectationClassName, - method: $method, - phpDoc: $phpDoc, - ), - ); - - if ($assertFileState !== null) { - $methodName = $method->getName(); - - $assertFileState->constructorComments[] = sprintf( - '@param array<%s|null> $%s', - $expectationClassName, - $methodName - ); - $assertFileState->constructorBodies[] = sprintf( - '$this->setExpectations(%s::class, $%s);', - $expectationClassName, - $methodName - ); - - $assertFileState - ->constructor - ->addParameter($methodName) - ->setType('array') - ->setDefaultValue(new Literal('[]')); - - $this->generateExpectationMethodAssert( - assertClass: $assertFileState->class, - method: $method, - expectationClassName: $expectationClassName, - phpDoc: $phpDoc, - ); - } - } - - if ($assertFileState !== null) { - if ($assertFileState->constructor !== null) { - $assertFileState->constructor->addComment(implode(PHP_EOL, $assertFileState->constructorComments)); - $assertFileState->constructor->addBody(implode(PHP_EOL, $assertFileState->constructorBodies)); - } - - $this->writeFile( - directory: $directory, - className: $assertClassName, - filesystem: $filesystem, - fileContents: $printer->printFile($assertFileState->file) + [ + 'assert' => $assertFile, + 'expectations' => $expectations, + ] = $generateExpectationClassAction->execute( + $inputClass, + $namespace, ); - } - } - - /** - * Generates a method assert in assert class. Generates __construct if $expectationClassName is passed (requires - * extending AbstractExpectationCallsMap). - */ - protected function generateExpectationMethodAssert( - ClassType $assertClass, - ReflectionMethod $method, - string $expectationClassName, - PhpDocEntity $phpDoc, - ): void { - $parameters = $method->getParameters(); - - $assertMethod = (new Factory())->fromMethodReflection($method); - $assertClass->addMember($assertMethod); - $assertMethod->addBody(sprintf( - '$_expectation = $this->getExpectation(%s);', - $expectationClassName . '::class' - )); - - $hookParameters = []; - - if ($parameters !== []) { - $assertMethod->addBody('$_message = $this->getDebugMessage();'); - $assertMethod->addBody(''); - - foreach ($parameters as $parameter) { - $hookParameters[] = sprintf('$%s', $parameter->name); - $assertMethod->addBody(sprintf( - 'Assert::assertEquals($_expectation->%s, $%s, $_message);', - $parameter->name, - $parameter->name - )); + foreach ($expectations as $expectation) { + $this->writeFile($expectation); } + $this->writeFile($assertFile); } - $hookParameters[] = '$_expectation'; - - $assertMethod->addBody(''); - - $assertMethod->addBody(sprintf('if (is_callable($_expectation->%s)) {', self::HookProperty)); - $assertMethod->addBody(sprintf( - ' call_user_func($_expectation->%s, %s);', - self::HookProperty, - implode(', ', $hookParameters), - )); - $assertMethod->addBody('}'); - - $returnType = $method->getReturnType(); - - if ($returnType instanceof ReflectionNamedType) { - $enumReturnType = PhpType::tryFrom($returnType->getName()) ?? PhpType::Mixed; - } elseif ($returnType instanceof ReflectionUnionType) { - $enumReturnType = PhpType::Mixed; - } else { - $enumReturnType = $phpDoc->returnType; - } - - switch ($enumReturnType) { - case PhpType::Mixed: - $assertMethod->addBody(''); - $assertMethod->addBody('return $_expectation->return;'); - break; - case PhpType::Self: - case PhpType::Static: - $assertMethod->addBody(''); - $assertMethod->addBody('return $this;'); - break; - } - } - - /** - * @param ReflectionClass $class - */ - protected function createAssertFileAndClass( - ReflectionClass $class, - string $namespace, - string $className, - ): ?AssertFileStateEntity { - if ($class->isInterface() === false) { - return null; - } - - $file = new PhpFile(); - $file->setStrictTypes(); - - $assertNamespace = $file->addNamespace($namespace); - $assertNamespace->addUse(Assert::class); - - $assertClass = $assertNamespace->addClass($className); - $assertClass->addImplement($class->getName()); - - $assertConstructor = new Method('__construct'); - $assertClass->setExtends(AbstractExpectationCallsMap::class); - $assertClass->addMember($assertConstructor); - - $assertConstructor->addBody('parent::__construct();'); - - return new AssertFileStateEntity($file, $assertClass, $assertConstructor); - } - - protected function getExpectationFileContents( - PsrPrinter $printer, - string $namespace, - string $className, - ReflectionMethod $method, - PhpDocEntity $phpDoc, - ): string { - $parameters = $method->getParameters(); - - $file = new PhpFile(); - $file->setStrictTypes(); - - $class = $file - ->addNamespace($namespace) - ->addClass($className); - - $constructor = $class - ->setFinal() - ->addMethod('__construct'); - - $returnType = $method->getReturnType(); - if ($returnType !== null && - ($returnType instanceof ReflectionNamedType === false || $this->canReturnExpectation($returnType)) || - $phpDoc->returnType === PhpType::Mixed) { - $constructorParameter = $constructor - ->addPromotedParameter('return') - ->setReadOnly(); - - $this->setParameterType($returnType, $constructorParameter); - } - - $parameterTypes = []; - foreach ($parameters as $parameter) { - $constructorParameter = $constructor - ->addPromotedParameter($parameter->name) - ->setReadOnly(); - - $parameterTypes[] = $this->setParameterType($parameter->getType(), $constructorParameter); - $this->setParameterDefaultValue($parameter, $constructorParameter); - } - - $constructor - ->addPromotedParameter(self::HookProperty) - ->setReadOnly() - ->setType('\Closure') - ->setNullable() - ->setDefaultValue(null); - - $parameterTypes[] = 'self'; - - $constructor->addComment( - sprintf('@param \Closure(%s):void|null $%s', implode(',', $parameterTypes), self::HookProperty) - ); - - return $printer->printFile($file); - } - - protected function setParameterType( - ReflectionType|ReflectionNamedType|ReflectionUnionType|ReflectionIntersectionType|null $type, - PromotedParameter $constructorParameter - ): string { - $proposedType = ''; - - $allowNull = false; - $mapToName = static function (ReflectionType $type) use (&$allowNull): ?string { - if ($type instanceof ReflectionNamedType) { - $name = $type->getName(); - if ($name === 'null') { - $allowNull = false; - } - - // Fix global namespace - if (class_exists($name)) { - return '\\' . $name; - } - - return $name; - } - - return null; - }; - - // TODO move to separate action and test with unit test - if ($type instanceof ReflectionNamedType) { - $allowNull = $type->allowsNull(); - $proposedType = $type->getName(); - - if (class_exists($proposedType)) { - // Fix global namespace - $proposedType = '\\' . $proposedType; - } - - $constructorParameter->setNullable($type->allowsNull()); - } elseif ($type instanceof ReflectionUnionType) { - $allowNull = $type->allowsNull(); - $proposedType = implode('|', array_filter(array_map($mapToName, $type->getTypes()))); - } elseif ($type instanceof ReflectionIntersectionType) { - $allowNull = $type->allowsNull(); - $proposedType = implode('&', array_filter(array_map($mapToName, $type->getTypes()))); - } - - if ($proposedType === '') { - $proposedType = 'mixed'; - } - - if ($allowNull) { - $constructorParameter->setNullable($allowNull); - } - - // Callable not supported in property - if ($proposedType === 'callable') { - $proposedType = '\Closure'; - } - - $constructorParameter->setType($proposedType); - - return $proposedType; + return 0; } - protected function setParameterDefaultValue( - ReflectionParameter $parameter, - PromotedParameter $constructorParameter - ): void { - if ($parameter->isDefaultValueAvailable() === false) { - return; - } - - if ($parameter->isDefaultValueConstant()) { - $constant = $parameter->getDefaultValueConstantName(); - // Ensure that constants are from global scope - $constantLiteral = new Literal(StubConstants::NameSpaceSeparator . $constant); - $constructorParameter->setDefaultValue($constantLiteral); - - return; - } - - $defaultValue = $parameter->getDefaultValue(); - if (is_object($defaultValue)) { - $objectLiteral = new Literal( - 'new ' . StubConstants::NameSpaceSeparator . $defaultValue::class . '(/* unknown */)' - ); - $constructorParameter->setDefaultValue($objectLiteral); - } else { - $constructorParameter->setDefaultValue($defaultValue); - } - } - - protected function writeError(string $message): void + private function writeError(string $message): void { if (property_exists($this, 'components')) { $this->components->error($message); @@ -472,15 +76,10 @@ protected function writeError(string $message): void } } - protected function writeFile( - string $directory, - string $className, - Filesystem $filesystem, - string $fileContents - ): void { - $filePath = $directory . DIRECTORY_SEPARATOR . $className . '.php'; - $filesystem->put($filePath, $fileContents); + private function writeFile(string $filePath): void + { + $className = basename($filePath, '.php'); $successMessage = 'File generated [' . $className . ']'; if (property_exists($this, 'components')) { $this->components->info($successMessage); @@ -492,82 +91,4 @@ protected function writeFile( $this->newLine(); } - /** - * @param ReflectionClass $class - */ - protected function getExpectationClassName(ReflectionClass $class, string $methodSuffix): string - { - return $class->getShortName() . $methodSuffix . 'Expectation'; - } - - protected function canReturnExpectation(ReflectionNamedType $returnType): bool - { - return $returnType->getName() !== PhpType::Void - ->value - && $returnType->getName() !== PhpType::Self - ->value - && $returnType->getName() !== PhpType::Static - ->value; - } - - /** - * @return class-string|null - */ - private function checkInterface(string $class): ?string - { - if (class_exists($class) === false && interface_exists($class) === false) { - $this->writeError(sprintf('Provided class does not exists [%s]', $class)); - return null; - } - - return $class; - } - - /** - * @return class-string|null - */ - private function normalizeToClass( - string $class, - string $basePath, - Filesystem $filesystem, - PathToClassAction $pathToClassAction - ): ?string { - if (str_ends_with($class, '.php')) { - $fullPath = $basePath . '/' . $class; - - if ($filesystem->exists($fullPath) === false) { - $this->writeError(sprintf('File does not exists at [%s]', $class)); - return null; - } - - return $pathToClassAction->execute($fullPath); - } - - return $this->checkInterface($class); - } - - /** - * @return array - */ - private function findAllClasses(Finder $finder, PathToClassAction $pathToClassAction): array - { - $classes = []; - foreach ($finder as $file) { - $interface = $pathToClassAction->execute($file->getRealPath()); - require_once $file->getPathname(); - - if (interface_exists($interface, false) === false) { - continue; - } - - $classReflection = new ReflectionClass($interface); - $attributes = $classReflection->getAttributes(TestAssert::class); - if ($attributes === []) { - continue; - } - $classes[] = $interface; - } - - return $classes; - } } diff --git a/src/Testing/Contracts/FindAllClassesActionContract.php b/src/Testing/Contracts/FindAllClassesActionContract.php new file mode 100644 index 00000000..933b014b --- /dev/null +++ b/src/Testing/Contracts/FindAllClassesActionContract.php @@ -0,0 +1,11 @@ + + */ + public function execute(): array; +} diff --git a/src/Testing/Contracts/GetBasePathForAssertsActionContract.php b/src/Testing/Contracts/GetBasePathForAssertsActionContract.php new file mode 100644 index 00000000..2e7a4990 --- /dev/null +++ b/src/Testing/Contracts/GetBasePathForAssertsActionContract.php @@ -0,0 +1,8 @@ + $expectationClasses + */ public function __construct( public readonly PhpFile $file, public readonly ClassType $class, public readonly Method $constructor, - public array $constructorComments = [], - public array $constructorBodies = [], + public array $expectationClasses = [], ) { } } diff --git a/src/Testing/Exceptions/LogicException.php b/src/Testing/Exceptions/LogicException.php new file mode 100644 index 00000000..9a4c705d --- /dev/null +++ b/src/Testing/Exceptions/LogicException.php @@ -0,0 +1,16 @@ + GetBasePathForStubsAction::class, + GetBasePathForAssertsActionContract::class => GetBasePathForAssertsAction::class, GetNamespaceForStubsActionContract::class => GetNamespaceForStubsAction::class, FinderFactoryContract::class => FinderFactory::class, + FindAllClassesActionContract::class => FindAllClassesAction::class, ]; public function register(): void diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractAssert.php.stub b/tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractAssert.php.stub deleted file mode 100644 index 03ccfb36..00000000 --- a/tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractAssert.php.stub +++ /dev/null @@ -1,266 +0,0 @@ - $self - * @param array $phpDocThis - * @param array $phpDocThisParams - * @param array $phpDocBool - * @param array $phpDocString - * @param array $phpDocFloat - * @param array $phpDocMixed - * @param array $phpDocStatic - * @param array $selfViaClass - * @param array $noReturn - * @param array $mixed - * @param array $noParams - */ - function __construct( - array $self = [], - array $phpDocThis = [], - array $phpDocThisParams = [], - array $phpDocBool = [], - array $phpDocString = [], - array $phpDocFloat = [], - array $phpDocMixed = [], - array $phpDocStatic = [], - array $selfViaClass = [], - array $noReturn = [], - array $mixed = [], - array $noParams = [], - ) { - parent::__construct(); - $this->setExpectations(MultiFunctionContractSelfExpectation::class, $self); - $this->setExpectations(MultiFunctionContractPhpDocThisExpectation::class, $phpDocThis); - $this->setExpectations(MultiFunctionContractPhpDocThisParamsExpectation::class, $phpDocThisParams); - $this->setExpectations(MultiFunctionContractPhpDocBoolExpectation::class, $phpDocBool); - $this->setExpectations(MultiFunctionContractPhpDocStringExpectation::class, $phpDocString); - $this->setExpectations(MultiFunctionContractPhpDocFloatExpectation::class, $phpDocFloat); - $this->setExpectations(MultiFunctionContractPhpDocMixedExpectation::class, $phpDocMixed); - $this->setExpectations(MultiFunctionContractPhpDocStaticExpectation::class, $phpDocStatic); - $this->setExpectations(MultiFunctionContractSelfViaClassExpectation::class, $selfViaClass); - $this->setExpectations(MultiFunctionContractNoReturnExpectation::class, $noReturn); - $this->setExpectations(MultiFunctionContractMixedExpectation::class, $mixed); - $this->setExpectations(MultiFunctionContractNoParamsExpectation::class, $noParams); - } - - function self(string $first, int $second, bool $third): self - { - $_expectation = $this->getExpectation(MultiFunctionContractSelfExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->first, $first, $_message); - Assert::assertEquals($_expectation->second, $second, $_message); - Assert::assertEquals($_expectation->third, $third, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $first, $second, $third, $_expectation); - } - - return $this; - } - - /** - * @return $this - */ - function phpDocThis(string $first, int $second, bool $third) - { - $_expectation = $this->getExpectation(MultiFunctionContractPhpDocThisExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->first, $first, $_message); - Assert::assertEquals($_expectation->second, $second, $_message); - Assert::assertEquals($_expectation->third, $third, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $first, $second, $third, $_expectation); - } - - return $this; - } - - /** - * @param string $first - * @param int $second - * @param bool $second - * - * @return $this - */ - function phpDocThisParams($first, $second, $third) - { - $_expectation = $this->getExpectation(MultiFunctionContractPhpDocThisParamsExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->first, $first, $_message); - Assert::assertEquals($_expectation->second, $second, $_message); - Assert::assertEquals($_expectation->third, $third, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $first, $second, $third, $_expectation); - } - - return $this; - } - - /** - * @return bool - */ - function phpDocBool($first, $second, callable $third) - { - $_expectation = $this->getExpectation(MultiFunctionContractPhpDocBoolExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->first, $first, $_message); - Assert::assertEquals($_expectation->second, $second, $_message); - Assert::assertEquals($_expectation->third, $third, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $first, $second, $third, $_expectation); - } - - return $_expectation->return; - } - - /** - * @return string - */ - function phpDocString($first, $second, $third) - { - $_expectation = $this->getExpectation(MultiFunctionContractPhpDocStringExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->first, $first, $_message); - Assert::assertEquals($_expectation->second, $second, $_message); - Assert::assertEquals($_expectation->third, $third, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $first, $second, $third, $_expectation); - } - - return $_expectation->return; - } - - /** - * @return float - */ - function phpDocFloat($first, $second, $third) - { - $_expectation = $this->getExpectation(MultiFunctionContractPhpDocFloatExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->first, $first, $_message); - Assert::assertEquals($_expectation->second, $second, $_message); - Assert::assertEquals($_expectation->third, $third, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $first, $second, $third, $_expectation); - } - - return $_expectation->return; - } - - /** - * @return mixed - */ - function phpDocMixed($first, $second, $third) - { - $_expectation = $this->getExpectation(MultiFunctionContractPhpDocMixedExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->first, $first, $_message); - Assert::assertEquals($_expectation->second, $second, $_message); - Assert::assertEquals($_expectation->third, $third, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $first, $second, $third, $_expectation); - } - - return $_expectation->return; - } - - /** - * @return static - */ - function phpDocStatic($first, $second, $third) - { - $_expectation = $this->getExpectation(MultiFunctionContractPhpDocStaticExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->first, $first, $_message); - Assert::assertEquals($_expectation->second, $second, $_message); - Assert::assertEquals($_expectation->third, $third, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $first, $second, $third, $_expectation); - } - - return $this; - } - - /** - * @return MultiFunctionContract - */ - function selfViaClass($first, $second, $third) - { - $_expectation = $this->getExpectation(MultiFunctionContractSelfViaClassExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->first, $first, $_message); - Assert::assertEquals($_expectation->second, $second, $_message); - Assert::assertEquals($_expectation->third, $third, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $first, $second, $third, $_expectation); - } - - return $_expectation->return; - } - - function noReturn($first, $second, $third) - { - $_expectation = $this->getExpectation(MultiFunctionContractNoReturnExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->first, $first, $_message); - Assert::assertEquals($_expectation->second, $second, $_message); - Assert::assertEquals($_expectation->third, $third, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $first, $second, $third, $_expectation); - } - } - - function mixed($first, $second, $third): mixed - { - $_expectation = $this->getExpectation(MultiFunctionContractMixedExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->first, $first, $_message); - Assert::assertEquals($_expectation->second, $second, $_message); - Assert::assertEquals($_expectation->third, $third, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $first, $second, $third, $_expectation); - } - - return $_expectation->return; - } - - function noParams(): string - { - $_expectation = $this->getExpectation(MultiFunctionContractNoParamsExpectation::class); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $_expectation); - } - - return $_expectation->return; - } -} diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractMixedExpectation.php.stub b/tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractMixedExpectation.php.stub deleted file mode 100644 index fd1cccfe..00000000 --- a/tests/Feature/Testing/Commands/MakeExpectationCommand/MultiFunctionContractMixedExpectation.php.stub +++ /dev/null @@ -1,20 +0,0 @@ - $execute + * @param array $execute */ function __construct(array $execute = []) { parent::__construct(); - $this->setExpectations(SimpleActionContractExpectation::class, $execute); + $this->setExpectations(SimpleActionContractExecuteExpectation::class, $execute); } function execute(string $first, int $second, bool $third) { - $_expectation = $this->getExpectation(SimpleActionContractExpectation::class); + $_expectation = $this->getExpectation(SimpleActionContractExecuteExpectation::class); $_message = $this->getDebugMessage(); Assert::assertEquals($_expectation->first, $first, $_message); diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/SimpleActionContractExpectation.php b/tests/Feature/Testing/Commands/MakeExpectationCommand/SimpleActionContractExecuteExpectation.php similarity index 88% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/SimpleActionContractExpectation.php rename to tests/Feature/Testing/Commands/MakeExpectationCommand/SimpleActionContractExecuteExpectation.php index 1bbd3ffb..2b2ed7dc 100644 --- a/tests/Feature/Testing/Commands/MakeExpectationCommand/SimpleActionContractExpectation.php +++ b/tests/Feature/Testing/Commands/MakeExpectationCommand/SimpleActionContractExecuteExpectation.php @@ -4,7 +4,7 @@ namespace Tests\LaraStrict\Feature\Testing\Commands\MakeExpectationCommand; -final class SimpleActionContractExpectation +final class SimpleActionContractExecuteExpectation { /** * @param \Closure(string,int,bool,self):void|null $_hook diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/TestActionContractAssert.php.stub b/tests/Feature/Testing/Commands/MakeExpectationCommand/TestActionContractAssert.php.stub deleted file mode 100644 index 74d87f3a..00000000 --- a/tests/Feature/Testing/Commands/MakeExpectationCommand/TestActionContractAssert.php.stub +++ /dev/null @@ -1,64 +0,0 @@ - $execute - */ - function __construct(array $execute = []) - { - parent::__construct(); - $this->setExpectations(TestActionContractExpectation::class, $execute); - } - - function execute( - int $int, - string $string, - $noTypeHint, - \LaraStrict\Enums\EnvironmentType $type, - \LaraStrict\Testing\Laravel\TestingApplication $testingApplication, - string|int $multi, - string|int|null $multiNull, - string|int|null $multiNullDefault = 'test', - string $optional = null, - string $optionalString = 'test', - string $constant = DIRECTORY_SEPARATOR, - int $constantClass = \LaraStrict\Cache\Constants\CacheExpirations::Day, - \LaraStrict\Enums\EnvironmentType $enumDefault = \LaraStrict\Enums\EnvironmentType::Testing, - $noTypeHintDefault = null, - string $customConstants = Constants\CustomConstants::TEST, - \LaraStrict\Testing\Laravel\TestingApplication $object = new \LaraStrict\Testing\Laravel\TestingApplication(/* unknown */), - \ArrayAccess&\Illuminate\Support\Enumerable $intersectionType = new \Illuminate\Support\Collection(/* unknown */), - ): void { - $_expectation = $this->getExpectation(TestActionContractExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->int, $int, $_message); - Assert::assertEquals($_expectation->string, $string, $_message); - Assert::assertEquals($_expectation->noTypeHint, $noTypeHint, $_message); - Assert::assertEquals($_expectation->type, $type, $_message); - Assert::assertEquals($_expectation->testingApplication, $testingApplication, $_message); - Assert::assertEquals($_expectation->multi, $multi, $_message); - Assert::assertEquals($_expectation->multiNull, $multiNull, $_message); - Assert::assertEquals($_expectation->multiNullDefault, $multiNullDefault, $_message); - Assert::assertEquals($_expectation->optional, $optional, $_message); - Assert::assertEquals($_expectation->optionalString, $optionalString, $_message); - Assert::assertEquals($_expectation->constant, $constant, $_message); - Assert::assertEquals($_expectation->constantClass, $constantClass, $_message); - Assert::assertEquals($_expectation->enumDefault, $enumDefault, $_message); - Assert::assertEquals($_expectation->noTypeHintDefault, $noTypeHintDefault, $_message); - Assert::assertEquals($_expectation->customConstants, $customConstants, $_message); - Assert::assertEquals($_expectation->object, $object, $_message); - Assert::assertEquals($_expectation->intersectionType, $intersectionType, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $int, $string, $noTypeHint, $type, $testingApplication, $multi, $multiNull, $multiNullDefault, $optional, $optionalString, $constant, $constantClass, $enumDefault, $noTypeHintDefault, $customConstants, $object, $intersectionType, $_expectation); - } - } -} diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/TestActionContractExpectation.php.stub b/tests/Feature/Testing/Commands/MakeExpectationCommand/TestActionContractExpectation.php.stub deleted file mode 100644 index f8d7d3be..00000000 --- a/tests/Feature/Testing/Commands/MakeExpectationCommand/TestActionContractExpectation.php.stub +++ /dev/null @@ -1,33 +0,0 @@ - $execute - */ - function __construct(array $execute = []) - { - parent::__construct(); - $this->setExpectations(TestReturnActionContractExpectation::class, $execute); - } - - function execute( - int $int, - string $string, - $noTypeHint, - \LaraStrict\Enums\EnvironmentType $type, - \LaraStrict\Testing\Laravel\TestingApplication $testingApplication, - string|int $multi, - string|int|null $multiNull, - string|int|null $multiNullDefault = 'test', - string $optional = null, - string $optionalString = 'test', - string $constant = DIRECTORY_SEPARATOR, - int $constantClass = \LaraStrict\Cache\Constants\CacheExpirations::Day, - \LaraStrict\Enums\EnvironmentType $enumDefault = \LaraStrict\Enums\EnvironmentType::Testing, - $noTypeHintDefault = null, - string $customConstants = Constants\CustomConstants::TEST, - \LaraStrict\Testing\Laravel\TestingApplication $object = new \LaraStrict\Testing\Laravel\TestingApplication(/* unknown */), - \ArrayAccess&\Illuminate\Support\Enumerable $intersectionType = new \Illuminate\Support\Collection(/* unknown */), - ): ?int { - $_expectation = $this->getExpectation(TestReturnActionContractExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->int, $int, $_message); - Assert::assertEquals($_expectation->string, $string, $_message); - Assert::assertEquals($_expectation->noTypeHint, $noTypeHint, $_message); - Assert::assertEquals($_expectation->type, $type, $_message); - Assert::assertEquals($_expectation->testingApplication, $testingApplication, $_message); - Assert::assertEquals($_expectation->multi, $multi, $_message); - Assert::assertEquals($_expectation->multiNull, $multiNull, $_message); - Assert::assertEquals($_expectation->multiNullDefault, $multiNullDefault, $_message); - Assert::assertEquals($_expectation->optional, $optional, $_message); - Assert::assertEquals($_expectation->optionalString, $optionalString, $_message); - Assert::assertEquals($_expectation->constant, $constant, $_message); - Assert::assertEquals($_expectation->constantClass, $constantClass, $_message); - Assert::assertEquals($_expectation->enumDefault, $enumDefault, $_message); - Assert::assertEquals($_expectation->noTypeHintDefault, $noTypeHintDefault, $_message); - Assert::assertEquals($_expectation->customConstants, $customConstants, $_message); - Assert::assertEquals($_expectation->object, $object, $_message); - Assert::assertEquals($_expectation->intersectionType, $intersectionType, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $int, $string, $noTypeHint, $type, $testingApplication, $multi, $multiNull, $multiNullDefault, $optional, $optionalString, $constant, $constantClass, $enumDefault, $noTypeHintDefault, $customConstants, $object, $intersectionType, $_expectation); - } - - return $_expectation->return; - } -} diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/TestReturnActionContractExpectation.php.stub b/tests/Feature/Testing/Commands/MakeExpectationCommand/TestReturnActionContractExpectation.php.stub deleted file mode 100644 index eccde567..00000000 --- a/tests/Feature/Testing/Commands/MakeExpectationCommand/TestReturnActionContractExpectation.php.stub +++ /dev/null @@ -1,34 +0,0 @@ - $execute - */ - function __construct(array $execute = []) - { - parent::__construct(); - $this->setExpectations(TestReturnUnionActionContractExpectation::class, $execute); - } - - function execute( - int $int, - string $string, - $noTypeHint, - \LaraStrict\Enums\EnvironmentType $type, - \LaraStrict\Testing\Laravel\TestingApplication $testingApplication, - string|int $multi, - string|int|null $multiNull, - string|int|null $multiNullDefault = 'test', - string $optional = null, - string $optionalString = 'test', - string $constant = DIRECTORY_SEPARATOR, - int $constantClass = \LaraStrict\Cache\Constants\CacheExpirations::Day, - \LaraStrict\Enums\EnvironmentType $enumDefault = \LaraStrict\Enums\EnvironmentType::Testing, - $noTypeHintDefault = null, - string $customConstants = Constants\CustomConstants::TEST, - \LaraStrict\Testing\Laravel\TestingApplication $object = new \LaraStrict\Testing\Laravel\TestingApplication(/* unknown */), - \ArrayAccess&\Illuminate\Support\Enumerable $intersectionType = new \Illuminate\Support\Collection(/* unknown */), - ): \LaraStrict\Testing\Laravel\TestingApplication|string|int|null { - $_expectation = $this->getExpectation(TestReturnUnionActionContractExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->int, $int, $_message); - Assert::assertEquals($_expectation->string, $string, $_message); - Assert::assertEquals($_expectation->noTypeHint, $noTypeHint, $_message); - Assert::assertEquals($_expectation->type, $type, $_message); - Assert::assertEquals($_expectation->testingApplication, $testingApplication, $_message); - Assert::assertEquals($_expectation->multi, $multi, $_message); - Assert::assertEquals($_expectation->multiNull, $multiNull, $_message); - Assert::assertEquals($_expectation->multiNullDefault, $multiNullDefault, $_message); - Assert::assertEquals($_expectation->optional, $optional, $_message); - Assert::assertEquals($_expectation->optionalString, $optionalString, $_message); - Assert::assertEquals($_expectation->constant, $constant, $_message); - Assert::assertEquals($_expectation->constantClass, $constantClass, $_message); - Assert::assertEquals($_expectation->enumDefault, $enumDefault, $_message); - Assert::assertEquals($_expectation->noTypeHintDefault, $noTypeHintDefault, $_message); - Assert::assertEquals($_expectation->customConstants, $customConstants, $_message); - Assert::assertEquals($_expectation->object, $object, $_message); - Assert::assertEquals($_expectation->intersectionType, $intersectionType, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $int, $string, $noTypeHint, $type, $testingApplication, $multi, $multiNull, $multiNullDefault, $optional, $optionalString, $constant, $constantClass, $enumDefault, $noTypeHintDefault, $customConstants, $object, $intersectionType, $_expectation); - } - - return $_expectation->return; - } -} diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/TestReturnUnionActionContractExpectation.php.stub b/tests/Feature/Testing/Commands/MakeExpectationCommand/TestReturnUnionActionContractExpectation.php.stub deleted file mode 100644 index 95c00820..00000000 --- a/tests/Feature/Testing/Commands/MakeExpectationCommand/TestReturnUnionActionContractExpectation.php.stub +++ /dev/null @@ -1,34 +0,0 @@ - $execute - */ - function __construct(array $execute = []) - { - parent::__construct(); - $this->setExpectations(TestActionContractExpectation::class, $execute); - } - - function execute( - int $int, - string $string, - $noTypeHint, - \LaraStrict\Enums\EnvironmentType $type, - \LaraStrict\Testing\Laravel\TestingApplication $testingApplication, - string|int $multi, - string|int|null $multiNull, - string|int|null $multiNullDefault = 'test', - string $optional = null, - string $optionalString = 'test', - string $constant = DIRECTORY_SEPARATOR, - int $constantClass = \LaraStrict\Cache\Constants\CacheExpirations::Day, - \LaraStrict\Enums\EnvironmentType $enumDefault = \LaraStrict\Enums\EnvironmentType::Testing, - $noTypeHintDefault = null, - string $customConstants = \Tests\LaraStrict\Feature\Testing\Commands\MakeExpectationCommand\Constants\CustomConstants::TEST, - \LaraStrict\Testing\Laravel\TestingApplication $object = new \LaraStrict\Testing\Laravel\TestingApplication(/* unknown */), - \ArrayAccess&\Illuminate\Support\Enumerable $intersectionType = new \Illuminate\Support\Collection(/* unknown */), - ): void { - $_expectation = $this->getExpectation(TestActionContractExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->int, $int, $_message); - Assert::assertEquals($_expectation->string, $string, $_message); - Assert::assertEquals($_expectation->noTypeHint, $noTypeHint, $_message); - Assert::assertEquals($_expectation->type, $type, $_message); - Assert::assertEquals($_expectation->testingApplication, $testingApplication, $_message); - Assert::assertEquals($_expectation->multi, $multi, $_message); - Assert::assertEquals($_expectation->multiNull, $multiNull, $_message); - Assert::assertEquals($_expectation->multiNullDefault, $multiNullDefault, $_message); - Assert::assertEquals($_expectation->optional, $optional, $_message); - Assert::assertEquals($_expectation->optionalString, $optionalString, $_message); - Assert::assertEquals($_expectation->constant, $constant, $_message); - Assert::assertEquals($_expectation->constantClass, $constantClass, $_message); - Assert::assertEquals($_expectation->enumDefault, $enumDefault, $_message); - Assert::assertEquals($_expectation->noTypeHintDefault, $noTypeHintDefault, $_message); - Assert::assertEquals($_expectation->customConstants, $customConstants, $_message); - Assert::assertEquals($_expectation->object, $object, $_message); - Assert::assertEquals($_expectation->intersectionType, $intersectionType, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $int, $string, $noTypeHint, $type, $testingApplication, $multi, $multiNull, $multiNullDefault, $optional, $optionalString, $constant, $constantClass, $enumDefault, $noTypeHintDefault, $customConstants, $object, $intersectionType, $_expectation); - } - } -} diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestActionContractExpectation.php.stub b/tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestActionContractExpectation.php.stub deleted file mode 100644 index e66c49ec..00000000 --- a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestActionContractExpectation.php.stub +++ /dev/null @@ -1,33 +0,0 @@ - $execute - */ - function __construct(array $execute = []) - { - parent::__construct(); - $this->setExpectations(TestReturnActionContractExpectation::class, $execute); - } - - function execute( - int $int, - string $string, - $noTypeHint, - \LaraStrict\Enums\EnvironmentType $type, - \LaraStrict\Testing\Laravel\TestingApplication $testingApplication, - string|int $multi, - string|int|null $multiNull, - string|int|null $multiNullDefault = 'test', - string $optional = null, - string $optionalString = 'test', - string $constant = DIRECTORY_SEPARATOR, - int $constantClass = \LaraStrict\Cache\Constants\CacheExpirations::Day, - \LaraStrict\Enums\EnvironmentType $enumDefault = \LaraStrict\Enums\EnvironmentType::Testing, - $noTypeHintDefault = null, - string $customConstants = \Tests\LaraStrict\Feature\Testing\Commands\MakeExpectationCommand\Constants\CustomConstants::TEST, - \LaraStrict\Testing\Laravel\TestingApplication $object = new \LaraStrict\Testing\Laravel\TestingApplication(/* unknown */), - \ArrayAccess&\Illuminate\Support\Enumerable $intersectionType = new \Illuminate\Support\Collection(/* unknown */), - ): ?int { - $_expectation = $this->getExpectation(TestReturnActionContractExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->int, $int, $_message); - Assert::assertEquals($_expectation->string, $string, $_message); - Assert::assertEquals($_expectation->noTypeHint, $noTypeHint, $_message); - Assert::assertEquals($_expectation->type, $type, $_message); - Assert::assertEquals($_expectation->testingApplication, $testingApplication, $_message); - Assert::assertEquals($_expectation->multi, $multi, $_message); - Assert::assertEquals($_expectation->multiNull, $multiNull, $_message); - Assert::assertEquals($_expectation->multiNullDefault, $multiNullDefault, $_message); - Assert::assertEquals($_expectation->optional, $optional, $_message); - Assert::assertEquals($_expectation->optionalString, $optionalString, $_message); - Assert::assertEquals($_expectation->constant, $constant, $_message); - Assert::assertEquals($_expectation->constantClass, $constantClass, $_message); - Assert::assertEquals($_expectation->enumDefault, $enumDefault, $_message); - Assert::assertEquals($_expectation->noTypeHintDefault, $noTypeHintDefault, $_message); - Assert::assertEquals($_expectation->customConstants, $customConstants, $_message); - Assert::assertEquals($_expectation->object, $object, $_message); - Assert::assertEquals($_expectation->intersectionType, $intersectionType, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $int, $string, $noTypeHint, $type, $testingApplication, $multi, $multiNull, $multiNullDefault, $optional, $optionalString, $constant, $constantClass, $enumDefault, $noTypeHintDefault, $customConstants, $object, $intersectionType, $_expectation); - } - - return $_expectation->return; - } -} diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestReturnActionContractExpectation.php.stub b/tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestReturnActionContractExpectation.php.stub deleted file mode 100644 index aa747f1c..00000000 --- a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestReturnActionContractExpectation.php.stub +++ /dev/null @@ -1,34 +0,0 @@ - $execute - */ - function __construct(array $execute = []) - { - parent::__construct(); - $this->setExpectations(TestReturnUnionActionContractExpectation::class, $execute); - } - - function execute( - int $int, - string $string, - $noTypeHint, - \LaraStrict\Enums\EnvironmentType $type, - \LaraStrict\Testing\Laravel\TestingApplication $testingApplication, - string|int $multi, - string|int|null $multiNull, - string|int|null $multiNullDefault = 'test', - string $optional = null, - string $optionalString = 'test', - string $constant = DIRECTORY_SEPARATOR, - int $constantClass = \LaraStrict\Cache\Constants\CacheExpirations::Day, - \LaraStrict\Enums\EnvironmentType $enumDefault = \LaraStrict\Enums\EnvironmentType::Testing, - $noTypeHintDefault = null, - string $customConstants = \Tests\LaraStrict\Feature\Testing\Commands\MakeExpectationCommand\Constants\CustomConstants::TEST, - \LaraStrict\Testing\Laravel\TestingApplication $object = new \LaraStrict\Testing\Laravel\TestingApplication(/* unknown */), - \ArrayAccess&\Illuminate\Support\Enumerable $intersectionType = new \Illuminate\Support\Collection(/* unknown */), - ): \LaraStrict\Testing\Laravel\TestingApplication|string|int|null { - $_expectation = $this->getExpectation(TestReturnUnionActionContractExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->int, $int, $_message); - Assert::assertEquals($_expectation->string, $string, $_message); - Assert::assertEquals($_expectation->noTypeHint, $noTypeHint, $_message); - Assert::assertEquals($_expectation->type, $type, $_message); - Assert::assertEquals($_expectation->testingApplication, $testingApplication, $_message); - Assert::assertEquals($_expectation->multi, $multi, $_message); - Assert::assertEquals($_expectation->multiNull, $multiNull, $_message); - Assert::assertEquals($_expectation->multiNullDefault, $multiNullDefault, $_message); - Assert::assertEquals($_expectation->optional, $optional, $_message); - Assert::assertEquals($_expectation->optionalString, $optionalString, $_message); - Assert::assertEquals($_expectation->constant, $constant, $_message); - Assert::assertEquals($_expectation->constantClass, $constantClass, $_message); - Assert::assertEquals($_expectation->enumDefault, $enumDefault, $_message); - Assert::assertEquals($_expectation->noTypeHintDefault, $noTypeHintDefault, $_message); - Assert::assertEquals($_expectation->customConstants, $customConstants, $_message); - Assert::assertEquals($_expectation->object, $object, $_message); - Assert::assertEquals($_expectation->intersectionType, $intersectionType, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $int, $string, $noTypeHint, $type, $testingApplication, $multi, $multiNull, $multiNullDefault, $optional, $optionalString, $constant, $constantClass, $enumDefault, $noTypeHintDefault, $customConstants, $object, $intersectionType, $_expectation); - } - - return $_expectation->return; - } -} diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestReturnUnionActionContractExpectation.php.stub b/tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestReturnUnionActionContractExpectation.php.stub deleted file mode 100644 index 091f750b..00000000 --- a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.TestReturnUnionActionContractExpectation.php.stub +++ /dev/null @@ -1,34 +0,0 @@ - $execute - */ - function __construct(array $execute = []) - { - parent::__construct(); - $this->setExpectations(TestActionContractExpectation::class, $execute); - } - - function execute( - int $int, - string $string, - $noTypeHint, - \LaraStrict\Enums\EnvironmentType $type, - \LaraStrict\Testing\Laravel\TestingApplication $testingApplication, - string|int $multi, - string|int|null $multiNull, - string|int|null $multiNullDefault = 'test', - string $optional = null, - string $optionalString = 'test', - string $constant = DIRECTORY_SEPARATOR, - int $constantClass = \LaraStrict\Cache\Constants\CacheExpirations::Day, - \LaraStrict\Enums\EnvironmentType $enumDefault = \LaraStrict\Enums\EnvironmentType::Testing, - $noTypeHintDefault = null, - string $customConstants = \Tests\LaraStrict\Feature\Testing\Commands\MakeExpectationCommand\Constants\CustomConstants::TEST, - \LaraStrict\Testing\Laravel\TestingApplication $object = new \LaraStrict\Testing\Laravel\TestingApplication(/* unknown */), - \ArrayAccess&\Illuminate\Support\Enumerable $intersectionType = new \Illuminate\Support\Collection(/* unknown */), - ): void { - $_expectation = $this->getExpectation(TestActionContractExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->int, $int, $_message); - Assert::assertEquals($_expectation->string, $string, $_message); - Assert::assertEquals($_expectation->noTypeHint, $noTypeHint, $_message); - Assert::assertEquals($_expectation->type, $type, $_message); - Assert::assertEquals($_expectation->testingApplication, $testingApplication, $_message); - Assert::assertEquals($_expectation->multi, $multi, $_message); - Assert::assertEquals($_expectation->multiNull, $multiNull, $_message); - Assert::assertEquals($_expectation->multiNullDefault, $multiNullDefault, $_message); - Assert::assertEquals($_expectation->optional, $optional, $_message); - Assert::assertEquals($_expectation->optionalString, $optionalString, $_message); - Assert::assertEquals($_expectation->constant, $constant, $_message); - Assert::assertEquals($_expectation->constantClass, $constantClass, $_message); - Assert::assertEquals($_expectation->enumDefault, $enumDefault, $_message); - Assert::assertEquals($_expectation->noTypeHintDefault, $noTypeHintDefault, $_message); - Assert::assertEquals($_expectation->customConstants, $customConstants, $_message); - Assert::assertEquals($_expectation->object, $object, $_message); - Assert::assertEquals($_expectation->intersectionType, $intersectionType, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $int, $string, $noTypeHint, $type, $testingApplication, $multi, $multiNull, $multiNullDefault, $optional, $optionalString, $constant, $constantClass, $enumDefault, $noTypeHintDefault, $customConstants, $object, $intersectionType, $_expectation); - } - } -} diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestActionContractExpectation.php.stub b/tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestActionContractExpectation.php.stub deleted file mode 100644 index 1fcd75cf..00000000 --- a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestActionContractExpectation.php.stub +++ /dev/null @@ -1,33 +0,0 @@ - $execute - */ - function __construct(array $execute = []) - { - parent::__construct(); - $this->setExpectations(TestReturnActionContractExpectation::class, $execute); - } - - function execute( - int $int, - string $string, - $noTypeHint, - \LaraStrict\Enums\EnvironmentType $type, - \LaraStrict\Testing\Laravel\TestingApplication $testingApplication, - string|int $multi, - string|int|null $multiNull, - string|int|null $multiNullDefault = 'test', - string $optional = null, - string $optionalString = 'test', - string $constant = DIRECTORY_SEPARATOR, - int $constantClass = \LaraStrict\Cache\Constants\CacheExpirations::Day, - \LaraStrict\Enums\EnvironmentType $enumDefault = \LaraStrict\Enums\EnvironmentType::Testing, - $noTypeHintDefault = null, - string $customConstants = \Tests\LaraStrict\Feature\Testing\Commands\MakeExpectationCommand\Constants\CustomConstants::TEST, - \LaraStrict\Testing\Laravel\TestingApplication $object = new \LaraStrict\Testing\Laravel\TestingApplication(/* unknown */), - \ArrayAccess&\Illuminate\Support\Enumerable $intersectionType = new \Illuminate\Support\Collection(/* unknown */), - ): ?int { - $_expectation = $this->getExpectation(TestReturnActionContractExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->int, $int, $_message); - Assert::assertEquals($_expectation->string, $string, $_message); - Assert::assertEquals($_expectation->noTypeHint, $noTypeHint, $_message); - Assert::assertEquals($_expectation->type, $type, $_message); - Assert::assertEquals($_expectation->testingApplication, $testingApplication, $_message); - Assert::assertEquals($_expectation->multi, $multi, $_message); - Assert::assertEquals($_expectation->multiNull, $multiNull, $_message); - Assert::assertEquals($_expectation->multiNullDefault, $multiNullDefault, $_message); - Assert::assertEquals($_expectation->optional, $optional, $_message); - Assert::assertEquals($_expectation->optionalString, $optionalString, $_message); - Assert::assertEquals($_expectation->constant, $constant, $_message); - Assert::assertEquals($_expectation->constantClass, $constantClass, $_message); - Assert::assertEquals($_expectation->enumDefault, $enumDefault, $_message); - Assert::assertEquals($_expectation->noTypeHintDefault, $noTypeHintDefault, $_message); - Assert::assertEquals($_expectation->customConstants, $customConstants, $_message); - Assert::assertEquals($_expectation->object, $object, $_message); - Assert::assertEquals($_expectation->intersectionType, $intersectionType, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $int, $string, $noTypeHint, $type, $testingApplication, $multi, $multiNull, $multiNullDefault, $optional, $optionalString, $constant, $constantClass, $enumDefault, $noTypeHintDefault, $customConstants, $object, $intersectionType, $_expectation); - } - - return $_expectation->return; - } -} diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestReturnActionContractExpectation.php.stub b/tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestReturnActionContractExpectation.php.stub deleted file mode 100644 index 0c6e3d65..00000000 --- a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestReturnActionContractExpectation.php.stub +++ /dev/null @@ -1,34 +0,0 @@ - $execute - */ - function __construct(array $execute = []) - { - parent::__construct(); - $this->setExpectations(TestReturnUnionActionContractExpectation::class, $execute); - } - - function execute( - int $int, - string $string, - $noTypeHint, - \LaraStrict\Enums\EnvironmentType $type, - \LaraStrict\Testing\Laravel\TestingApplication $testingApplication, - string|int $multi, - string|int|null $multiNull, - string|int|null $multiNullDefault = 'test', - string $optional = null, - string $optionalString = 'test', - string $constant = DIRECTORY_SEPARATOR, - int $constantClass = \LaraStrict\Cache\Constants\CacheExpirations::Day, - \LaraStrict\Enums\EnvironmentType $enumDefault = \LaraStrict\Enums\EnvironmentType::Testing, - $noTypeHintDefault = null, - string $customConstants = \Tests\LaraStrict\Feature\Testing\Commands\MakeExpectationCommand\Constants\CustomConstants::TEST, - \LaraStrict\Testing\Laravel\TestingApplication $object = new \LaraStrict\Testing\Laravel\TestingApplication(/* unknown */), - \ArrayAccess&\Illuminate\Support\Enumerable $intersectionType = new \Illuminate\Support\Collection(/* unknown */), - ): \LaraStrict\Testing\Laravel\TestingApplication|string|int|null { - $_expectation = $this->getExpectation(TestReturnUnionActionContractExpectation::class); - $_message = $this->getDebugMessage(); - - Assert::assertEquals($_expectation->int, $int, $_message); - Assert::assertEquals($_expectation->string, $string, $_message); - Assert::assertEquals($_expectation->noTypeHint, $noTypeHint, $_message); - Assert::assertEquals($_expectation->type, $type, $_message); - Assert::assertEquals($_expectation->testingApplication, $testingApplication, $_message); - Assert::assertEquals($_expectation->multi, $multi, $_message); - Assert::assertEquals($_expectation->multiNull, $multiNull, $_message); - Assert::assertEquals($_expectation->multiNullDefault, $multiNullDefault, $_message); - Assert::assertEquals($_expectation->optional, $optional, $_message); - Assert::assertEquals($_expectation->optionalString, $optionalString, $_message); - Assert::assertEquals($_expectation->constant, $constant, $_message); - Assert::assertEquals($_expectation->constantClass, $constantClass, $_message); - Assert::assertEquals($_expectation->enumDefault, $enumDefault, $_message); - Assert::assertEquals($_expectation->noTypeHintDefault, $noTypeHintDefault, $_message); - Assert::assertEquals($_expectation->customConstants, $customConstants, $_message); - Assert::assertEquals($_expectation->object, $object, $_message); - Assert::assertEquals($_expectation->intersectionType, $intersectionType, $_message); - - if (is_callable($_expectation->_hook)) { - call_user_func($_expectation->_hook, $int, $string, $noTypeHint, $type, $testingApplication, $multi, $multiNull, $multiNullDefault, $optional, $optionalString, $constant, $constantClass, $enumDefault, $noTypeHintDefault, $customConstants, $object, $intersectionType, $_expectation); - } - - return $_expectation->return; - } -} diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestReturnUnionActionContractExpectation.php.stub b/tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestReturnUnionActionContractExpectation.php.stub deleted file mode 100644 index ecdd592c..00000000 --- a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.TestReturnUnionActionContractExpectation.php.stub +++ /dev/null @@ -1,34 +0,0 @@ -assertCommand(0, $classOrFilePath); @@ -100,7 +100,7 @@ public function testWithAutoloadDevButOnlyOneEntry( $fileName, 'one', checkAssert: $checkAssert, - expectationVariants: $expectationVariants + expectationVariants: $expectationVariants, ); $this->assertCommand(0, $classOrFilePath, 'one'); @@ -125,7 +125,7 @@ public function testWithAutoloadDevTwoEntrySelectionSecond( $fileName, 'two', checkAssert: $checkAssert, - expectationVariants: $expectationVariants + expectationVariants: $expectationVariants, ); $this->assertCommand(0, $classOrFilePath, 'two', true); @@ -143,14 +143,14 @@ public function testClassDoesNotExists(): void expectedResult: 1, class: 'Test', expectedMessage: 'Provided class does not exists [Test]', - expectComposerJson: false + expectComposerJson: false, ); } public function testMethodDoesNotExistsDefaultValue(): void { $this->expectExceptionMessage( - 'Class Tests\LaraStrict\Feature\Testing\Commands\MakeExpectationCommand\NoMethods does not contain any public' + 'Class Tests\LaraStrict\Feature\Testing\Commands\MakeExpectationCommand\NoMethods does not contain any public', ); $this->assertCommand(expectedResult: 1, class: NoMethods::class, expectComposerJson: false); } @@ -163,7 +163,7 @@ public function testClassDoesNotExistsAtPath(): void expectedResult: 1, class: self::TestFileName, expectedMessage: 'File does not exists at [' . self::TestFileName . ']', - expectComposerJson: false + expectComposerJson: false, ); } @@ -221,9 +221,9 @@ protected function expectClassFileExists(bool $return): void protected function expectClassFileExistsArgClosure(): Closure { - return static fn (string $path) => str_contains( + return static fn(string $path) => str_contains( $path, - '/vendor/orchestra/testbench-core/laravel/' . self::TestFileName + '/vendor/orchestra/testbench-core/laravel/' . self::TestFileName, ); } @@ -275,8 +275,7 @@ protected function assertCommand( // our implementation expets always composer.json file $this->fileSystem->shouldReceive('isFile') ->once() - ->with(function($arg) use ($expectedComposerCheck){ - + ->with(function($arg) use ($expectedComposerCheck) { $x = 1; }) ->andReturn(true); @@ -284,7 +283,7 @@ protected function assertCommand( $this->fileSystem->shouldReceive('get') ->once() ->with($expectedComposerCheck) - ->andReturnUsing(static function (string $path) use ($composerPath): string { + ->andReturnUsing(static function(string $path) use ($composerPath): string { $fileGetContents = file_get_contents($composerPath); if ($fileGetContents === false) { throw new LogicException('File not loaded' . $composerPath); @@ -296,11 +295,11 @@ protected function assertCommand( //Transform real testbanch composer to our expectation composer $this->fileSystem->shouldReceive('get') ->once() - ->withArgs(static fn (string $path): bool => str_contains( + ->withArgs(static fn(string $path): bool => str_contains( $path, - '/vendor/orchestra/testbench-core/laravel/composer.json' + '/vendor/orchestra/testbench-core/laravel/composer.json', )) - ->andReturnUsing(static function (string $path) use ($composerPath): string { + ->andReturnUsing(static function(string $path) use ($composerPath): string { $fileGetContents = file_get_contents($composerPath); if ($fileGetContents === false) { throw new LogicException('File not loaded' . $composerPath); @@ -361,14 +360,14 @@ protected function expectResultFile( ]); $this->fileSystem->shouldReceive('ensureDirectoryExists') - ->withArgs(static fn (string $path): bool => str_contains($path, $expectedPath)); + ->withArgs(static fn(string $path): bool => str_contains($path, $expectedPath)); $this->fileSystem->shouldReceive('put') ->times(count($expectationVariants)) - ->withArgs(function (string $path, string $contents) use ( + ->withArgs(function(string $path, string $contents) use ( $expectedPath, $variantPrefix, - $expectationVariants + $expectationVariants, ): bool { $expectedExpectationFileName = null; foreach ($expectationVariants as $expectationVariant) { @@ -392,16 +391,17 @@ protected function expectResultFile( $expectedResult = file_get_contents($stubFile); $this->assertEquals($expectedResult, $contents); + return true; }); if ($checkAssert) { $this->fileSystem->shouldReceive('put') ->once() - ->withArgs(function (string $path, string $contents) use ( + ->withArgs(function(string $path, string $contents) use ( $expectedPath, $expectedFileName, - $variantPrefix + $variantPrefix, ): bool { $filePath = $this->getExpectedPath($expectedPath, $expectedFileName . 'Assert'); $this->assertStringContainsString($filePath, $path); @@ -412,6 +412,7 @@ protected function expectResultFile( $expectedResult = file_get_contents($stubFile); $this->assertEquals($expectedResult, $contents); + return true; }); } diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractAssert.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractAssert.stub.php similarity index 89% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractAssert.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractAssert.stub.php index cc6f3176..44ad44b3 100644 --- a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractAssert.php.stub +++ b/tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractAssert.stub.php @@ -6,6 +6,18 @@ use PHPUnit\Framework\Assert; +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractSelfExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractPhpDocThisExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractPhpDocThisParamsExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractPhpDocBoolExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractPhpDocStringExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractPhpDocFloatExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractPhpDocMixedExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractPhpDocStaticExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractSelfViaClassExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractNoReturnExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractMixedExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractNoParamsExpectation::class)] class MultiFunctionContractAssert extends \LaraStrict\Testing\Assert\AbstractExpectationCallsMap implements \Tests\LaraStrict\Feature\Testing\Commands\MakeExpectationCommand\MultiFunctionContract { /** diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractMixedExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractMixedExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractMixedExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractMixedExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractNoParamsExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractNoParamsExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractNoParamsExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractNoParamsExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractNoReturnExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractNoReturnExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractNoReturnExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractNoReturnExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocBoolExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocBoolExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocBoolExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocBoolExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocFloatExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocFloatExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocFloatExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocFloatExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocMixedExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocMixedExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocMixedExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocMixedExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocStaticExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocStaticExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocStaticExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocStaticExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocStringExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocStringExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocStringExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocStringExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocThisExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocThisExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocThisExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocThisExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocThisParamsExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocThisParamsExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocThisParamsExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractPhpDocThisParamsExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractSelfExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractSelfExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractSelfExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractSelfExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractSelfViaClassExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractSelfViaClassExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/one.MultiFunctionContractSelfViaClassExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/one.MultiFunctionContractSelfViaClassExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractAssert.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractAssert.stub.php similarity index 89% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractAssert.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractAssert.stub.php index b6cd487d..de4430ef 100644 --- a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractAssert.php.stub +++ b/tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractAssert.stub.php @@ -6,6 +6,18 @@ use PHPUnit\Framework\Assert; +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractSelfExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractPhpDocThisExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractPhpDocThisParamsExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractPhpDocBoolExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractPhpDocStringExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractPhpDocFloatExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractPhpDocMixedExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractPhpDocStaticExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractSelfViaClassExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractNoReturnExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractMixedExpectation::class)] +#[\LaraStrict\Testing\Attributes\Expectation(class: MultiFunctionContractNoParamsExpectation::class)] class MultiFunctionContractAssert extends \LaraStrict\Testing\Assert\AbstractExpectationCallsMap implements \Tests\LaraStrict\Feature\Testing\Commands\MakeExpectationCommand\MultiFunctionContract { /** diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractMixedExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractMixedExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractMixedExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractMixedExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractNoParamsExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractNoParamsExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractNoParamsExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractNoParamsExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractNoReturnExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractNoReturnExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractNoReturnExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractNoReturnExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocBoolExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocBoolExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocBoolExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocBoolExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocFloatExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocFloatExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocFloatExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocFloatExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocMixedExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocMixedExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocMixedExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocMixedExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocStaticExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocStaticExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocStaticExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocStaticExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocStringExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocStringExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocStringExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocStringExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocThisExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocThisExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocThisExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocThisExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocThisParamsExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocThisParamsExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocThisParamsExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractPhpDocThisParamsExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractSelfExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractSelfExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractSelfExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractSelfExpectation.stub.php diff --git a/tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractSelfViaClassExpectation.php.stub b/tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractSelfViaClassExpectation.stub.php similarity index 100% rename from tests/Feature/Testing/Commands/MakeExpectationCommand/two.MultiFunctionContractSelfViaClassExpectation.php.stub rename to tests/Stubs/Commands/MakeExpectationCommand/two.MultiFunctionContractSelfViaClassExpectation.stub.php diff --git a/tests/Unit/Testing/Actions/GetDevNamespaceForStubsActionTest.php b/tests/Unit/Testing/Actions/GetDevNamespaceForStubsActionTest.php index 197948a7..256a889f 100644 --- a/tests/Unit/Testing/Actions/GetDevNamespaceForStubsActionTest.php +++ b/tests/Unit/Testing/Actions/GetDevNamespaceForStubsActionTest.php @@ -33,7 +33,7 @@ public function data(): array */ public function testNamespace(string $class, string $expectedBaseNamespace, string $expectedFolder): void { - $result = (new GetDevNamespaceForStubsAction())->execute(new Command(), 'test', $class); + $result = (new GetDevNamespaceForStubsAction())->execute(new Command(), $class); $this->assertEquals($expectedFolder, $result->folder); $this->assertEquals($expectedBaseNamespace, $result->baseNamespace); } From 0cadc01b6aa5e3ab1472300016f0666d2869a10c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Mat=C4=9Bj=C4=8Dek?= Date: Thu, 15 Feb 2024 16:16:39 +0100 Subject: [PATCH 5/5] WIP [ci skip] revert --- src/Testing/Actions/GenerateExpectationClassAction.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Testing/Actions/GenerateExpectationClassAction.php b/src/Testing/Actions/GenerateExpectationClassAction.php index 041df9ca..989d8e00 100644 --- a/src/Testing/Actions/GenerateExpectationClassAction.php +++ b/src/Testing/Actions/GenerateExpectationClassAction.php @@ -121,8 +121,8 @@ private static function checkInputClass(ReflectionClass $class): array if ($methods === []) { throw new LogicException('Class %s does not contain any public', $class->getName()); - } else if ($class->isInterface() === false) { - throw new LogicException('Class %s is not interface', $class->getName()); +// } else if ($class->isInterface() === false) { +// throw new LogicException('Class %s is not interface', $class->getName()); } return $methods;