diff --git a/.atoum.bootstrap.php b/.atoum.bootstrap.php deleted file mode 100644 index 0ab10d8..0000000 --- a/.atoum.bootstrap.php +++ /dev/null @@ -1,3 +0,0 @@ -bootstrapFile(__DIR__ . DIRECTORY_SEPARATOR . '.atoum.bootstrap.php'); - -$cliReport = $script->addDefaultReport(); -$cliReport->addField(new atoum\report\fields\runner\result\logo()); - -$runner->addReport($cliReport); -$runner->addTestsFromDirectory(__DIR__.'/Tests/Units'); diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..655c087 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: Application CI + +on: pull_request + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + tests: + runs-on: ubuntu-latest + name: PHP CI ${{ matrix.php-versions }} + strategy: + matrix: + php-versions: + - 8.3 + - 8.4 + + steps: + - name: Checkout sources + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + tools: composer:v2 + env: + runner: self-hosted + - name: Install dependencies + run: composer install --no-interaction --no-progress + - name: Run unit tests + run: ./bin/phpunit diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 0000000..2977ee2 --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,23 @@ +name: Static Analysis + +on: pull_request + +jobs: + + phpcsfixer: + name: PHP Coding Standards Fixer + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP environment + uses: shivammathur/setup-php@v2 + with: + php-version: 8.3 + + - name: Install dependencies + run: composer install --no-interaction --no-progress + + - name: PHP Coding Standards Fixer + run: ./bin/php-cs-fixer fix --dry-run --diff diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a6832df..0000000 --- a/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -language: php - -php: - - 8.0 - -env: - global: - - XDEBUG_MODE=coverage - -install: composer install -n - -script: - - bin/atoum - -branches: - only: - - master diff --git a/Command/DeployActionCommand.php b/Command/DeployActionCommand.php index 846492f..a54e9b5 100644 --- a/Command/DeployActionCommand.php +++ b/Command/DeployActionCommand.php @@ -5,6 +5,7 @@ use Psr\Log\LoggerInterface; use Spy\Timeline\Driver\ActionManagerInterface; use Spy\Timeline\Spread\Deployer; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -14,11 +15,12 @@ * This command will deploy each actions (see limit option) which * has PUBLISHED on status_wanted. */ +#[AsCommand( + name: 'spy_timeline:deploy', + description: 'Deploy on spreads for waiting action', +)] class DeployActionCommand extends Command { - protected static $defaultName = 'spy_timeline:deploy'; - protected static $defaultDescription = 'Deploy on spreads for waiting action'; - private ActionManagerInterface $actionManager; private Deployer $deployer; private LoggerInterface $logger; @@ -36,10 +38,9 @@ public function __construct( $this->logger = $logger; } - protected function configure() + protected function configure(): void { $this - ->setDescription(self::$defaultDescription) ->addOption('limit', 'l', InputOption::VALUE_OPTIONAL, 'How many actions will be deployed', 200) ; } diff --git a/Command/SpreadListCommand.php b/Command/SpreadListCommand.php index 43162f9..3ab9d44 100644 --- a/Command/SpreadListCommand.php +++ b/Command/SpreadListCommand.php @@ -3,6 +3,7 @@ namespace Spy\TimelineBundle\Command; use Spy\Timeline\Spread\Deployer; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -10,11 +11,12 @@ /** * This command will show all services which are defined as spread. */ +#[AsCommand( + name: 'spy_timeline:spreads', + description: 'Deploy on spreads for waiting action', +)] class SpreadListCommand extends Command { - protected static $defaultName = 'spy_timeline:spreads'; - protected static $defaultDescription = 'Deploy on spreads for waiting action'; - private Deployer $deployer; public function __construct( @@ -24,11 +26,6 @@ public function __construct( $this->deployer = $deployer; } - protected function configure() - { - $this->setDescription(self::$defaultDescription); - } - /** * {@inheritdoc} */ diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 81f34ff..ef92b62 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -13,7 +13,7 @@ class Configuration implements ConfigurationInterface * * @return TreeBuilder The tree builder */ - public function getConfigTreeBuilder() + public function getConfigTreeBuilder(): TreeBuilder { $tb = new TreeBuilder('spy_timeline'); $rootNode = $tb->getRootNode(); diff --git a/Tests/Units/Command/DeployActionCommandTest.php b/Tests/Units/Command/DeployActionCommandTest.php new file mode 100644 index 0000000..407e4b0 --- /dev/null +++ b/Tests/Units/Command/DeployActionCommandTest.php @@ -0,0 +1,55 @@ +createMock(\Spy\Timeline\Driver\ActionManagerInterface::class); + $deployer = $this->createMock(\Spy\Timeline\Spread\Deployer::class); + $logger = $this->createMock(\Psr\Log\LoggerInterface::class); + + $actionManager->method('findActionsWithStatusWantedPublished')->willReturn([]); + + $command = new DeployActionCommand($actionManager, $deployer, $logger); + + $application = new Application(); + $application->add($command); + + $command = $application->find('spy_timeline:deploy'); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName()], []); + + $this->assertEquals('There is 0 action(s) to deploy'.PHP_EOL.'Done'.PHP_EOL, $commandTester->getDisplay()); + } + + public function testOneTimeline() + { + $actionManager = $this->createMock(\Spy\Timeline\Driver\ActionManagerInterface::class); + $deployer = $this->createMock(\Spy\Timeline\Spread\Deployer::class); + $action = $this->createMock(\Spy\Timeline\Model\ActionInterface::class); + $logger = $this->createMock(\Psr\Log\LoggerInterface::class); + + $action->method('getId')->willReturn(1); + $actionManager->method('findActionsWithStatusWantedPublished')->willReturn([$action]); + + $command = new DeployActionCommand($actionManager, $deployer, $logger); + + $application = new Application(); + $application->add($command); + + $command = $application->find('spy_timeline:deploy'); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName()], []); + + $this->assertEquals('There is 1 action(s) to deploy'.PHP_EOL.'Deploy action 1'.PHP_EOL.'Done'.PHP_EOL, $commandTester->getDisplay()); + } +} diff --git a/Tests/Units/Command/SpreadListCommandTest.php b/Tests/Units/Command/SpreadListCommandTest.php new file mode 100644 index 0000000..b0832b8 --- /dev/null +++ b/Tests/Units/Command/SpreadListCommandTest.php @@ -0,0 +1,50 @@ +createMock(\Spy\Timeline\Spread\Deployer::class); + $deployer->method('getSpreads')->willReturn([]); + + $command = new SpreadListCommand($deployer); + + $application = new Application(); + $application->add($command); + + $command = $application->find('spy_timeline:spreads'); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName()], []); + + $this->assertEquals('There is 0 timeline spread(s) defined'.PHP_EOL, $commandTester->getDisplay()); + } + + public function testExecuteWithOneSpread() + { + // one spread + $spread = $this->createMock(\Spy\Timeline\Spread\SpreadInterface::class); + + $deployer = $this->createMock(\Spy\Timeline\Spread\Deployer::class); + $deployer->method('getSpreads')->willReturn([$spread]); + + $command = new SpreadListCommand($deployer); + + $application = new Application(); + $application->add($command); + + $command = $application->find('spy_timeline:spreads'); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName()]); + + $this->assertEquals('There is 1 timeline spread(s) defined'.PHP_EOL.'- '.get_class($spread).PHP_EOL, $commandTester->getDisplay()); + } +} diff --git a/Tests/Units/DependencyInjection/Compiler/AddLocatorCompilerPassTest.php b/Tests/Units/DependencyInjection/Compiler/AddLocatorCompilerPassTest.php new file mode 100644 index 0000000..f9b3434 --- /dev/null +++ b/Tests/Units/DependencyInjection/Compiler/AddLocatorCompilerPassTest.php @@ -0,0 +1,72 @@ + [], 'foo.service' => []]; + + //setup mocks + $definition = $this->createMock(Definition::class); + $definition + ->expects($this->exactly(3)) + ->method('addMethodCall') + ->with('addLocator', [$definition]) + ->willReturn($definition); + + $containerBuilder = $this->createMock(ContainerBuilder::class); + $containerBuilder + ->expects($this->exactly(1)) + ->method('findTaggedServiceIds') + ->with('spy_timeline.filter.data_hydrator.locator') + ->willReturn($taggedServicesResult); + + $containerBuilder->method('hasParameter')->willReturnCallback(function ($argument) { + switch ($argument) { + case "spy_timeline.filter.data_hydrator.locators_config": + return true; + } + }); + + $matcherGetParameter = $this->exactly(1); + $containerBuilder + ->expects($matcherGetParameter) + ->method('getParameter') + ->willReturnCallback(function ($value) use ($matcherGetParameter, $configLocators) { + match ($matcherGetParameter->getInvocationCount()) { + 1 => $this->assertEquals('spy_timeline.filter.data_hydrator.locators_config', $value), + }; + + return $configLocators; + }); + + + $matcherGetDefinition = $this->exactly(5); + $containerBuilder + ->expects($matcherGetDefinition) + ->method('getDefinition') + ->willReturnCallback(function (string $value) use ($matcherGetDefinition, $definition) { + match ($matcherGetDefinition->getInvocationCount()) { + 1, 4 => $this->assertEquals('foo.service', $value), + 2 => $this->assertEquals('bar.service', $value), + 3 => $this->assertEquals('baz.service', $value), + 5 => $this->assertEquals('spy_timeline.filter.data_hydrator', $value), + }; + + return $definition; + }); + + + $compiler = new AddLocatorCompilerPass(); + $compiler->process($containerBuilder); + } +} diff --git a/Tests/Units/DependencyInjection/Compiler/AddSpreadCompilerPassTest.php b/Tests/Units/DependencyInjection/Compiler/AddSpreadCompilerPassTest.php new file mode 100644 index 0000000..6932102 --- /dev/null +++ b/Tests/Units/DependencyInjection/Compiler/AddSpreadCompilerPassTest.php @@ -0,0 +1,56 @@ + array(array('priority' => 10)), 'bar.spread' => array(), 'baz.spread' => array(array('priority' => 10))); + + $definition = $this->createMock(Definition::class); + + $definition + ->expects($this->exactly(3)) + ->method('addMethodCall') + ->willReturn($definition); + + + $containerBuilder = $this->createMock(ContainerBuilder::class); + $containerBuilder + ->expects($this->exactly(1)) + ->method('getAlias') + ->with('spy_timeline.spread.deployer') + ->willReturn(new \Symfony\Component\DependencyInjection\Alias('spy_timeline.spread.deployer')); + + $matcherGetDefinition = $this->exactly(4); + $containerBuilder + ->expects($matcherGetDefinition) + ->method('getDefinition') + ->willReturnCallback(function (string $value) use ($matcherGetDefinition, $definition) { + match ($matcherGetDefinition->getInvocationCount()) { + 1 => $this->assertEquals('spy_timeline.spread.deployer', $value), + 2 => $this->assertEquals('foo.spread', $value), + 3 => $this->assertEquals('bar.spread', $value), + 4 => $this->assertEquals('baz.spread', $value), + }; + + return $definition; + }); + + $containerBuilder + ->expects($this->exactly(1)) + ->method('findTaggedServiceIds') + ->with('spy_timeline.spread') + ->willReturn($taggedServicesResult); + + $compiler = new AddSpreadCompilerPass(); + $compiler->process($containerBuilder); + } +} diff --git a/Tests/Units/DependencyInjection/Configuration.php b/Tests/Units/DependencyInjection/ConfigurationTest.php similarity index 62% rename from Tests/Units/DependencyInjection/Configuration.php rename to Tests/Units/DependencyInjection/ConfigurationTest.php index ed3c961..7444ffd 100644 --- a/Tests/Units/DependencyInjection/Configuration.php +++ b/Tests/Units/DependencyInjection/ConfigurationTest.php @@ -2,48 +2,40 @@ namespace Spy\TimelineBundle\Tests\Units\DependencyInjection; -use atoum\atoum\test; +use PHPUnit\Framework\TestCase; use Spy\TimelineBundle\DependencyInjection\Configuration as ConfigurationTested; use Symfony\Component\Config\Definition\Processor; -class Configuration extends test +class ConfigurationTest extends TestCase { public function testNoConfiguration() { - $this->array($this->processConfiguration(array($this->getDefaultInput()))) - ->isEqualTo($this->getDefaultOutput()); + $this->assertEquals($this->getDefaultOutput(), $this->processConfiguration(array($this->getDefaultInput()))); } public function testNoDriversAndNoManagers() { - $self = $this; + $this->expectException(\Symfony\Component\Config\Definition\Exception\InvalidConfigurationException::class); + $this->expectExceptionMessage('Invalid configuration for path "spy_timeline": Please define a driver or timeline_manager, action_manager'); - $this->exception(function () use ($self) { - $self->processConfiguration(array([])); - }) - ->isInstanceOf('\Symfony\Component\Config\Definition\Exception\InvalidConfigurationException') - ->hasMessage('Invalid configuration for path "spy_timeline": Please define a driver or timeline_manager, action_manager') - ; + $this->processConfiguration(array(array())); } public function testMultipleDrivers() { - $self = $this; - $this->exception(function () use ($self) { - $self->processConfiguration(array(array( - 'drivers' => array( - 'orm' => array( - 'object_manager' => 'foo', - ), - 'odm' => array( - 'object_manager' => 'foo', - ), + $this->expectException(\Symfony\Component\Config\Definition\Exception\InvalidConfigurationException::class); + $this->expectExceptionMessage('Invalid configuration for path "spy_timeline.drivers": Please define only one driver.'); + + $this->processConfiguration(array(array( + 'drivers' => array( + 'orm' => array( + 'object_manager' => 'foo', + ), + 'odm' => array( + 'object_manager' => 'foo', ), - ))); - }) - ->isInstanceOf('\Symfony\Component\Config\Definition\Exception\InvalidConfigurationException') - ->hasMessage('Invalid configuration for path "spy_timeline.drivers": Please define only one driver.') - ; + ), + ))); } public function processConfiguration($config) diff --git a/Tests/Units/Driver/ORM/ActionManager.php b/Tests/Units/Driver/ORM/ActionManager.php deleted file mode 100644 index 8a40abe..0000000 --- a/Tests/Units/Driver/ORM/ActionManager.php +++ /dev/null @@ -1,102 +0,0 @@ -and($objectManager = new \mock\Doctrine\Persistence\ObjectManager()) - ->and($resultBuilder = new \mock\Spy\Timeline\ResultBuilder\ResultBuilderInterface()) - ->and($componentDataResolver = new \mock\Spy\Timeline\ResolveComponent\ComponentDataResolverInterface()) - ->and($this->calling($componentDataResolver)->resolveComponentData = function () use ($model, $identifier) { - return new ResolvedComponentData($model, $identifier); - }) - ->and($actionClass = 'Spy\Timeline\Model\Action') - ->and($componentClass = 'Spy\Timeline\Model\Component') - ->and($actionComponentClass = 'Spy\Timeline\Model\ActionComponent') - ->and($actionManager = new TestedModel($objectManager, $resultBuilder, $actionClass, $componentClass, $actionComponentClass)) - ->exception( - function () use ($actionManager) { - $actionManager->getComponentDataResolver(); - } - )->hasMessage('Component data resolver not set') - ->and($actionManager->setComponentDataResolver($componentDataResolver)) - ->when($result = $actionManager->createComponent($model, $identifier)) - ->mock($objectManager)->call('persist')->withArguments($result)->exactly(1) - ->mock($objectManager)->call('flush')->exactly(1) - ->mock($componentDataResolver)->call('resolveComponentData')->withArguments($resolve)->exactly(1) - ->string($result->getIdentifier())->isEqualTo($identifier) - ->string($result->getModel())->isEqualto($model) - ->variable($result->getData())->isNull() - ; - } - - public function testfindOrCreateComponentWithExistingComponent() - { - $resolve = new ResolveComponentModelIdentifier('user', 1); - $resolvedComponentData = new ResolvedComponentData('user', 1); - $this - ->and($this->mockGenerator->orphanize('__construct')) - ->and($this->mockGenerator->shuntParentClassCalls()) - ->and($entityRepository = new \mock\Doctrine\ORM\EntityRepository()) - ->and($objectManager = new \mock\Doctrine\Persistence\ObjectManager()) - ->and($resultBuilder = new \mock\Spy\Timeline\ResultBuilder\ResultBuilderInterface()) - ->and($componentDataResolver = new \mock\Spy\Timeline\ResolveComponent\ComponentDataResolverInterface()) - ->and($queryBuilder = new \mock\Doctrine\Orm\QueryBuilder()) - ->and($this->mockGenerator->orphanize('__construct')) - ->and($this->mockGenerator->shuntParentClassCalls()) - ->and($query = new \mock\Doctrine\ORM\AbstractQuery()) - ->and($component = new \mock\Spy\Timeline\Model\Component()) - ->and($this->calling($componentDataResolver)->resolveComponentData = function () use ($resolvedComponentData) { - return $resolvedComponentData; - }) - ->and($this->calling($objectManager)->getRepository = function () use ($entityRepository) { - return $entityRepository; - }) - ->and($this->calling($entityRepository)->createQueryBuilder = function () use ($queryBuilder) { - return $queryBuilder; - }) - //here we return the component as result of the query - ->and($this->calling($query)->getOneOrNullResult = function () use ($component) { - return $component; - }) - //grouping those did not work the method was __call - ->and($this->calling($queryBuilder)->where = function () use ($queryBuilder) { - return $queryBuilder; - }) - ->and($this->calling($queryBuilder)->andWhere = function () use ($queryBuilder) { - return $queryBuilder; - }) - ->and($this->calling($queryBuilder)->setParameter = function () use ($queryBuilder) { - return $queryBuilder; - }) - ->and($this->calling($queryBuilder)->getQuery = function () use ($query) { - return $query; - }) - ->and($actionClass = 'Spy\Timeline\Model\Action') - ->and($componentClass = 'Spy\Timeline\Model\Component') - ->and($actionComponentClass = 'Spy\Timeline\Model\ActionComponent') - ->and($actionManager = new TestedModel($objectManager, $resultBuilder, $actionClass, $componentClass, $actionComponentClass)) - ->and($actionManager->setComponentDataResolver($componentDataResolver)) - ->and($this->calling($componentDataResolver)->resolveComponentData = function () { - return new ResolvedComponentData('user', '1'); - }) - ->when($result = $actionManager->findOrCreateComponent('user', 1)) - ->mock($componentDataResolver)->call('resolveComponentData')->withArguments($resolve)->exactly(1) - ->mock($queryBuilder)->call('where')->withArguments('c.hash = :hash')->exactly(1) - ->mock($queryBuilder)->call('setParameter')->withArguments('hash', $resolvedComponentData->getHAsh())->exactly(1) - ->object($result)->isEqualTo($component) - ; - } -} diff --git a/Tests/Units/Driver/ORM/ActionManagerTest.php b/Tests/Units/Driver/ORM/ActionManagerTest.php new file mode 100644 index 0000000..6bd67a8 --- /dev/null +++ b/Tests/Units/Driver/ORM/ActionManagerTest.php @@ -0,0 +1,76 @@ +createMock(\Doctrine\Persistence\ObjectManager::class); + $resultBuilder = $this->createMock(\Spy\Timeline\ResultBuilder\ResultBuilderInterface::class); + $componentDataResolver = $this->createMock(\Spy\Timeline\ResolveComponent\ComponentDataResolverInterface::class); + + $componentDataResolver->method('resolveComponentData')->willReturn(new ResolvedComponentData($model, $identifier)); + + $actionClass = 'Spy\Timeline\Model\Action'; + $componentClass = 'Spy\Timeline\Model\Component'; + $actionComponentClass = 'Spy\Timeline\Model\ActionComponent'; + $actionManager = new ActionManager($objectManager, $resultBuilder, $actionClass, $componentClass, $actionComponentClass); + + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Component data resolver not set'); + + $actionManager->getComponentDataResolver(); + + $actionManager->setComponentDataResolver($componentDataResolver); + + $result = $actionManager->createComponent($model, $identifier); + + $this->assertEquals($identifier, $result->getIdentifier()); + $this->assertEquals($model, $result->getModel()); + $this->assertNull($result->getData()); + } + + public function testfindOrCreateComponentWithExistingComponent() + { + $resolve = new ResolveComponentModelIdentifier('user', 1); + $resolvedComponentData = new ResolvedComponentData('user', 1); + + $entityRepository = $this->createMock(\Doctrine\ORM\EntityRepository::class); + $objectManager = $this->createMock(\Doctrine\Persistence\ObjectManager::class); + $resultBuilder = $this->createMock(\Spy\Timeline\ResultBuilder\ResultBuilderInterface::class); + $componentDataResolver = $this->createMock(\Spy\Timeline\ResolveComponent\ComponentDataResolverInterface::class); + $queryBuilder = $this->createMock(\Doctrine\ORM\QueryBuilder::class); + $query = $this->createMock(\Doctrine\ORM\AbstractQuery::class); + $component = $this->createMock(\Spy\Timeline\Model\Component::class); + + $componentDataResolver->method('resolveComponentData')->willReturn($resolvedComponentData); + $objectManager->method('getRepository')->willReturn($entityRepository); + $entityRepository->method('createQueryBuilder')->willReturn($queryBuilder); + $query->method('getOneOrNullResult')->willReturn($component); + $queryBuilder->method('where')->willReturn($queryBuilder); + $queryBuilder->method('andWhere')->willReturn($queryBuilder); + $queryBuilder->method('setParameter')->willReturn($queryBuilder); + $queryBuilder->method('getQuery')->willReturn($query); + + $actionClass = \Spy\Timeline\Model\Action::class; + $componentClass = \Spy\Timeline\Model\Component::class; + $actionComponentClass = \Spy\Timeline\Model\ActionComponent::class; + $actionManager = new ActionManager($objectManager, $resultBuilder, $actionClass, $componentClass, $actionComponentClass); + + $actionManager->setComponentDataResolver($componentDataResolver); + + $result = $actionManager->findOrCreateComponent('user', 1); + + $this->assertEquals($component, $result); + } +} diff --git a/Tests/Units/ResolveComponent/DoctrineComponentDataResolver.php b/Tests/Units/ResolveComponent/DoctrineComponentDataResolver.php deleted file mode 100644 index 5d8db54..0000000 --- a/Tests/Units/ResolveComponent/DoctrineComponentDataResolver.php +++ /dev/null @@ -1,98 +0,0 @@ -if($classMetadata = new \mock\Doctrine\Persistence\Mapping\ClassMetadata()) - ->and($managerRegistry = new \mock\Doctrine\Persistence\ManagerRegistry()) - ->and($this->mockGenerator->orphanize('__construct')) - ->and($this->mockGenerator->shuntParentClassCalls()) - ->and($objectManager = new \mock\Doctrine\Persistence\ObjectManager()) - ->and($this->calling($managerRegistry)->getManagerForClass = function () use ($objectManager) { - return $objectManager; - }) - ->and($this->calling($objectManager)->getClassMetadata = function () use ($classMetadata) { - return $classMetadata; - }) - ->and($this->calling($classMetadata)->getIdentifier = function () { return array('id'); - - }) - ->and($this->calling($classMetadata)->getName = function () { - return 'Spy\Timeline\ResolveComponent\TestHelper\User'; - - }) - ->and($resolver = new TestedModel()) - ->and($resolver->addRegistry($managerRegistry)) - ->when($result = $resolver->resolveComponentData($resolve)) - ->then( - $this->mock($managerRegistry)->call('getManagerForClass')->withArguments('Spy\Timeline\ResolveComponent\TestHelper\User')->exactly(1) - ->and($this->mock($objectManager)->call('getClassMetadata')->withArguments('Spy\Timeline\ResolveComponent\TestHelper\User')->exactly(1)) - ->and($this->mock($classMetadata)->call('getIdentifier')->exactly(1)) - ->and($this->string($result->getIdentifier())->isEqualTo(5)) - ->and($this->string($result->getModel())->isEqualTo('Spy\Timeline\ResolveComponent\TestHelper\User')) - ) - ; - } - - public function testObjectNotManagedByDoctrine() - { - $object = new User(5); - $resolve = new ResolveComponentModelIdentifier($object); - - $this->if($managerRegistry = new \mock\Doctrine\Persistence\ManagerRegistry()) - ->and($resolver = new TestedModel()) - ->and($resolver->addRegistry($managerRegistry)) - ->when($result = $resolver->resolveComponentData($resolve)) - ->then( - $this->mock($managerRegistry)->call('getManagerForClass')->withArguments('Spy\Timeline\ResolveComponent\TestHelper\User')->exactly(1) - ->and($this->string($result->getIdentifier())->isEqualTo(5)) - ->and($this->string($result->getModel())->isEqualTo('Spy\Timeline\ResolveComponent\TestHelper\User')) - ) - ; - } - - public function testObjectNotManagedByDoctrineWithoutGetIdMethod() - { - $object = new \stdClass(); - $resolve = new ResolveComponentModelIdentifier($object); - - $this->if($managerRegistry = new \mock\Doctrine\Persistence\ManagerRegistry()) - ->and($resolver = new TestedModel()) - ->and($resolver->addRegistry($managerRegistry)) - ->exception(function () use ($resolver, $resolve) { - $resolver->resolveComponentData($resolve); - }) - ->isInstanceOf('Spy\Timeline\Exception\ResolveComponentDataException') - ->hasMessage('Model must have a getId method.') - ; - } - - public function testStringModelAndIdentifierGiven() - { - $model = 'foo'; - $identifier = array('foo' => 'bar'); - $resolve = new ResolveComponentModelIdentifier($model, $identifier); - - $this->if($managerRegistry = new \mock\Doctrine\Persistence\ManagerRegistry()) - ->and($resolver = new TestedModel()) - ->and($resolver->addRegistry($managerRegistry)) - ->when($result = $resolver->resolveComponentData($resolve)) - ->then( - $this->mock($managerRegistry)->call('getManagerForClass')->withArguments('Spy\Timeline\ResolveComponent\TestHelper\User')->exactly(0) - ->and($this->array($result->getIdentifier())->isEqualTo($identifier)) - ->and($this->string($result->getModel())->isEqualTo($model)) - ) - ; - } -} diff --git a/Tests/Units/ResolveComponent/DoctrineComponentDataResolverTest.php b/Tests/Units/ResolveComponent/DoctrineComponentDataResolverTest.php new file mode 100644 index 0000000..a4995c4 --- /dev/null +++ b/Tests/Units/ResolveComponent/DoctrineComponentDataResolverTest.php @@ -0,0 +1,83 @@ +createMock(\Doctrine\Persistence\Mapping\ClassMetadata::class); + $managerRegistry = $this->createMock(\Doctrine\Persistence\ManagerRegistry::class); + $objectManager = $this->createMock(\Doctrine\Persistence\ObjectManager::class); + + $managerRegistry->method('getManagerForClass')->willReturn($objectManager); + $objectManager->method('getClassMetadata')->willReturn($classMetadata); + $classMetadata->method('getIdentifier')->willReturn(['id']); + $classMetadata->method('getName')->willReturn('Spy\Timeline\ResolveComponent\TestHelper\User'); + + $resolver = new TestedModel(); + $resolver->addRegistry($managerRegistry); + + $result = $resolver->resolveComponentData($resolve); + + $this->assertEquals('Spy\Timeline\ResolveComponent\TestHelper\User', $result->getModel()); + $this->assertEquals(5, $result->getIdentifier()); + } + + public function testObjectNotManagedByDoctrine() + { + $object = new User(5); + $resolve = new ResolveComponentModelIdentifier($object); + + $managerRegistry = $this->createMock(\Doctrine\Persistence\ManagerRegistry::class); + + $resolver = new TestedModel(); + $resolver->addRegistry($managerRegistry); + + $result = $resolver->resolveComponentData($resolve); + + $this->assertEquals('Spy\Timeline\ResolveComponent\TestHelper\User', $result->getModel()); + $this->assertEquals(5, $result->getIdentifier()); + } + + public function testObjectNotManagedByDoctrineWithoutGetIdMethod() + { + $object = new \stdClass(); + $resolve = new ResolveComponentModelIdentifier($object); + + $managerRegistry = $this->createMock(\Doctrine\Persistence\ManagerRegistry::class); + + $resolver = new TestedModel(); + $resolver->addRegistry($managerRegistry); + + $this->expectException(\Spy\Timeline\Exception\ResolveComponentDataException::class); + $this->expectExceptionMessage('Model must have a getId method.'); + + $resolver->resolveComponentData($resolve); + } + + public function testStringModelAndIdentifierGiven() + { + $model = 'foo'; + $identifier = array('foo' => 'bar'); + $resolve = new ResolveComponentModelIdentifier($model, $identifier); + + $managerRegistry = $this->createMock(\Doctrine\Persistence\ManagerRegistry::class); + + $resolver = new TestedModel(); + $resolver->addRegistry($managerRegistry); + + $result = $resolver->resolveComponentData($resolve); + + $this->assertEquals($model, $result->getModel()); + $this->assertEquals($identifier, $result->getIdentifier()); + } +} diff --git a/Tests/Units/SpyTimelineBundle.php b/Tests/Units/SpyTimelineBundle.php deleted file mode 100644 index 9970e76..0000000 --- a/Tests/Units/SpyTimelineBundle.php +++ /dev/null @@ -1,25 +0,0 @@ -if($containerBuilder = new \mock\Symfony\Component\DependencyInjection\ContainerBuilder()) - ->and($bundle = new TestedModel()) - ->when($bundle->build($containerBuilder)) - ->then( - $this->mock($containerBuilder)->call('addCompilerPass')->withArguments(new AddLocatorCompilerPass())->exactly(1) - ->and($this->mock($containerBuilder)->call('addCompilerPass')->withArguments(new AddDeliveryMethodCompilerPass())->exactly(1)) - ->and($this->mock($containerBuilder)->call('addCompilerPass')->withArguments(new AddComponentDataResolver())->exactly(1)) - ) - ; - } -} diff --git a/Tests/Units/SpyTimelineBundleTest.php b/Tests/Units/SpyTimelineBundleTest.php new file mode 100644 index 0000000..95e7e58 --- /dev/null +++ b/Tests/Units/SpyTimelineBundleTest.php @@ -0,0 +1,41 @@ +createMock(ContainerBuilder::class); + + $matcher = $this->exactly(6); + $containerBuilder + ->expects($matcher) + ->method('addCompilerPass') + ->willReturnCallback(function ($value) use ($matcher, $containerBuilder) { + match ($matcher->getInvocationCount()) { + 1 => $this->assertInstanceOf(AddSpreadCompilerPass::class, $value), + 2 => $this->assertInstanceOf(AddFilterCompilerPass::class, $value), + 3 => $this->assertInstanceOf(AddRegistryCompilerPass::class, $value), + 4 => $this->assertInstanceOf(AddDeliveryMethodCompilerPass::class, $value), + 5 => $this->assertInstanceOf(AddLocatorCompilerPass::class, $value), + 6 => $this->assertInstanceOf(AddComponentDataResolver::class, $value), + }; + + return $containerBuilder; + }); + + $bundle = new SpyTimelineBundle(); + $bundle->build($containerBuilder); + } +} diff --git a/composer.json b/composer.json index 461154a..148311b 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "stephpy/timeline-bundle", - "description": "Symfony2 bundle to make timeline", + "description": "Symfony bundle to make timeline", "keywords": ["timeline", "notification", "symfony", "bundle"], "type": "symfony-bundle", "homepage": "https://github.com/stephpy/timeline-bundle", @@ -10,15 +10,16 @@ "homepage": "https://github.com/stephpy/timeline-bundle/contributors" }], "require": { - "php": ">=8.0", + "php": ">=8.3", "stephpy/timeline": "^1.0", "symfony/framework-bundle": ">=5.4", "symfony/options-resolver": ">=5.4", "twig/twig": ">=3.0" }, "require-dev": { - "atoum/atoum": "4.*", - "doctrine/orm": ">=2.6", + "friendsofphp/php-cs-fixer": "^3.64", + "phpunit/phpunit": "^9.6", + "doctrine/orm": "^2.6", "symfony/console": ">=5.4", "symfony/twig-bundle": ">=5.4", "symfony/expression-language": ">=5.4" diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..aedafe7 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,14 @@ + + + + + + src + + + + + ./Tests/Units + + +