diff --git a/.travis.yml b/.travis.yml index ac469bc..6b1fe7e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ install: - composer update --prefer-dist script: - - vendor/bin/phpunit + - vendor/bin/phpunit --coverage-clover build/logs/clover.xml after_script: - vendor/bin/coveralls diff --git a/composer.json b/composer.json index 26b9db9..79a07ff 100644 --- a/composer.json +++ b/composer.json @@ -12,21 +12,21 @@ "require": { "php": ">=5.5", "simple-bus/symfony-bridge": "^4.1", - "clearcodehq/command-bus-launcher": "dev-master", "symfony/framework-bundle": "~2.3", "symfony/console": "~2.3", "symfony/dependency-injection": "~2.3", "symfony/http-kernel": "~2.3", - "symfony/config": "~2.3" + "symfony/config": "~2.3", + "ramsey/uuid": "~3.0" }, "require-dev": { "phpunit/phpunit": "~4.0", "satooshi/php-coveralls": "^0.6.1" }, "autoload": { - "psr-4" : { "ClearcodeHQ\\CommandBusLauncherBundle\\": "src" } + "psr-4" : { "ClearcodeHQ\\": "src" } }, "autoload-dev": { - "psr-4" : { "tests\\ClearcodeHQ\\CommandBusLauncherBundle\\" : "tests" } + "psr-4" : { "tests\\ClearcodeHQ\\" : "tests" } } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7e32b9c..f264dab 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -3,8 +3,13 @@ - + ./tests + ./tests/Command + + + + ./tests/Command @@ -18,7 +23,4 @@ - - - diff --git a/src/Command/CommandBusLaunchCommand.php b/src/Bundle/CommandBusLauncherBundle/Command/CommandBusLaunchCommand.php similarity index 96% rename from src/Command/CommandBusLaunchCommand.php rename to src/Bundle/CommandBusLauncherBundle/Command/CommandBusLaunchCommand.php index f959637..6ffccd4 100644 --- a/src/Command/CommandBusLaunchCommand.php +++ b/src/Bundle/CommandBusLauncherBundle/Command/CommandBusLaunchCommand.php @@ -1,6 +1,6 @@ valueConverters = $valueConverters; + } + + /** + * @param $arguments + * + * @return mixed + */ + public function process($arguments) + { + foreach ($arguments as $key => $argument) { + $arguments[$key] = $this->convertValue($argument); + } + + return $arguments; + } + + private function convertValue($value) + { + foreach ($this->valueConverters as $valueConverter) { + if (null !== $convertedValue = $valueConverter->convert($value)) { + return $convertedValue; + } + } + + return $value; + } +} diff --git a/src/CommandBusLauncher/CommandCollector.php b/src/CommandBusLauncher/CommandCollector.php new file mode 100644 index 0000000..96a505d --- /dev/null +++ b/src/CommandBusLauncher/CommandCollector.php @@ -0,0 +1,32 @@ +commands[] = CommandReflection::fromClass($service); + } + } + + public function getCommandByName($commandName) + { + foreach ($this->commands as $command) { + if ($command->commandName == $commandName) { + return $command; + } + } + + throw new CommandDoesNotExist(sprintf("Command '%s' does not exists", $commandName)); + } +} diff --git a/src/CommandBusLauncher/CommandDoesNotExist.php b/src/CommandBusLauncher/CommandDoesNotExist.php new file mode 100644 index 0000000..6c6978e --- /dev/null +++ b/src/CommandBusLauncher/CommandDoesNotExist.php @@ -0,0 +1,7 @@ +commandCollector = $commandCollector; + $this->argumentsProcessor = $argumentsProcessor; + } + + /** + * @param $commandName + * + * @return CommandReflection + * + * @throws CommandDoesNotExist + */ + public function getCommandReflection($commandName) + { + return $this->commandCollector->getCommandByName($commandName); + } + + /** + * @param $commandName + * @param $arguments + * + * @return object + * + * @throws CommandDoesNotExist + */ + public function getCommandToLaunch($commandName, $arguments) + { + $commandReflection = $this->commandCollector->getCommandByName($commandName); + + return $commandReflection->createCommand($arguments, $this->argumentsProcessor); + } +} diff --git a/src/CommandBusLauncher/CommandLauncherException.php b/src/CommandBusLauncher/CommandLauncherException.php new file mode 100644 index 0000000..69aae7f --- /dev/null +++ b/src/CommandBusLauncher/CommandLauncherException.php @@ -0,0 +1,7 @@ +commandName = $commandName; + $this->commandClass = $commandClass; + } + + /** + * @param $className + * + * @return CommandReflection + */ + public static function fromClass($className) + { + $reflection = new \ReflectionClass($className); + + return new self($reflection->getShortName(), $className); + } + + /** + * @return \ReflectionParameter[] + */ + public function parameters() + { + $commandReflection = new \ReflectionClass($this->commandClass); + $commandParameters = $commandReflection->getConstructor()->getParameters(); + + return $commandParameters; + } + + /** + * @param array $arguments + * @param ArgumentsProcessor $argumentsProcessor + * + * @return object + * + * @throws InvalidCommandArgument + * @throws MissingCommandArgument + */ + public function createCommand(array $arguments, ArgumentsProcessor $argumentsProcessor) + { + $classReflection = new \ReflectionClass($this->commandClass); + + $inputArguments = $argumentsProcessor->process($arguments); + + foreach ($this->parameters() as $commandArgument) { + if ($commandArgument->getClass() !== null) { + if (!array_key_exists($commandArgument->getPosition(), $inputArguments)) { + throw new MissingCommandArgument( + sprintf("Missing argument %s for '%s' command", $commandArgument->getPosition() + 1, $this->commandName) + ); + } + + $givenArgument = $inputArguments[$commandArgument->getPosition()]; + $requiredArgumentClass = $commandArgument->getClass()->name; + + if (!is_object($givenArgument) || !$givenArgument instanceof $requiredArgumentClass) { + throw new InvalidCommandArgument( + sprintf( + "Invalid argument for '%s' command. Expected parameter %s to be instance of '%s'", + $this->commandName, + $commandArgument->getPosition() + 1, + $requiredArgumentClass + ) + ); + } + } + } + + return $classReflection->newInstanceArgs($inputArguments); + } +} diff --git a/src/CommandBusLauncher/InvalidCommandArgument.php b/src/CommandBusLauncher/InvalidCommandArgument.php new file mode 100644 index 0000000..e440081 --- /dev/null +++ b/src/CommandBusLauncher/InvalidCommandArgument.php @@ -0,0 +1,7 @@ +sut->process(['first_arg', 'second_arg']); + + \PHPUnit_Framework_Assert::assertEquals('first_arg', $arguments[0]); + \PHPUnit_Framework_Assert::assertEquals('second_arg', $arguments[1]); + } + + /** + * @tests + */ + public function it_converts_numeric_strings_to_integer() + { + $arguments = $this->sut->process(['123', 'string_arg']); + + \PHPUnit_Framework_Assert::assertTrue(123 === $arguments[0]); + \PHPUnit_Framework_Assert::assertEquals('string_arg', $arguments[1]); + } + + /** + * @tests + */ + public function it_converts_uuid_like_strings_to_uuid_object() + { + $arguments = $this->sut->process(['b1b250a0-938a-48f6-b0ca-0aeccff1288e']); + + \PHPUnit_Framework_Assert::assertTrue( + Uuid::fromString('b1b250a0-938a-48f6-b0ca-0aeccff1288e')->equals($arguments[0]) + ); + } + + public function setUp() + { + $this->sut = new ArgumentsProcessor([new IntConverter(), new UuidConverter()]); + } +} diff --git a/tests/CommandBusLauncher/CommandCollectorTest.php b/tests/CommandBusLauncher/CommandCollectorTest.php new file mode 100644 index 0000000..7ddc6be --- /dev/null +++ b/tests/CommandBusLauncher/CommandCollectorTest.php @@ -0,0 +1,65 @@ +sut->processCommandServices($this->commands); + + \PHPUnit_Framework_Assert::assertEquals( + 'DummyCommand', + $this->sut->getCommandByName('DummyCommand')->commandName + ); + } + + /** + * @test + */ + public function it_returns_command_reflection_by_command_name() + { + $this->sut->processCommandServices($this->commands); + + $command = $this->sut->getCommandByName('DummyCommand'); + + \PHPUnit_Framework_Assert::assertInstanceOf(CommandReflection::class, $command); + } + + /** + * @test + * @expectedException \ClearcodeHQ\CommandBusLauncher\CommandDoesNotExist + */ + public function it_throws_exception_when_command_does_not_exist() + { + $this->sut->processCommandServices($this->commands); + + $this->sut->getCommandByName('UnexistingCommand'); + } + + public function setUp() + { + $this->sut = new CommandCollector(); + + $this->commands = [ + DummyCommand::class, + ]; + } +} diff --git a/tests/CommandBusLauncher/CommandLauncherTest.php b/tests/CommandBusLauncher/CommandLauncherTest.php new file mode 100644 index 0000000..144a3f7 --- /dev/null +++ b/tests/CommandBusLauncher/CommandLauncherTest.php @@ -0,0 +1,86 @@ +commandCollector->getCommandByName('DummyCommand')->willReturn( + CommandReflection::fromClass(DummyCommand::class) + ); + + $this->argumentsProcessor->process(['lorem ipsum', '123'])->willReturn( + ['lorem ipsum', 123] + ); + + $command = $this->sut->getCommandToLaunch('DummyCommand', ['lorem ipsum', 123]); + + $this->assertInstanceOf(DummyCommand::class, $command); + $this->assertTrue(123 === $command->argument2); + } + + /** @test */ + public function it_returns_command_with_uuid_to_launch() + { + $this->commandCollector->getCommandByName('DummyCommandWithUuid')->willReturn( + CommandReflection::fromClass(DummyCommandWithUuid::class) + ); + + $this->argumentsProcessor->process(['lorem ipsum', 'a1df6294-bcd9-43c5-8731-e3cd43401974'])->willReturn( + ['lorem ipsum', Uuid::fromString('a1df6294-bcd9-43c5-8731-e3cd43401974')] + ); + + $command = $this->sut->getCommandToLaunch('DummyCommandWithUuid', ['lorem ipsum', 'a1df6294-bcd9-43c5-8731-e3cd43401974']); + + $this->assertInstanceOf(DummyCommandWithUuid::class, $command); + $this->assertTrue(Uuid::fromString('a1df6294-bcd9-43c5-8731-e3cd43401974')->equals($command->argument2)); + } + + /** @test */ + public function it_returns_command_reflection() + { + $this->commandCollector->getCommandByName('DummyCommand')->willReturn( + CommandReflection::fromClass(DummyCommand::class) + ); + + $commandReflection = $this->sut->getCommandReflection('DummyCommand'); + + $this->assertInstanceOf(CommandReflection::class, $commandReflection); + } + + /** {@inheritdoc} */ + protected function setUp() + { + $this->commandCollector = $this->prophesize(CommandCollector::class); + $this->argumentsProcessor = $this->prophesize(ArgumentsProcessor::class); + + $this->sut = new CommandLauncher($this->commandCollector->reveal(), $this->argumentsProcessor->reveal()); + } + + /** {@inheritdoc} */ + protected function tearDown() + { + $this->commandCollector = null; + $this->argumentsProcessor = null; + + $this->sut = null; + } +} diff --git a/tests/CommandBusLauncher/CommandReflectionTest.php b/tests/CommandBusLauncher/CommandReflectionTest.php new file mode 100644 index 0000000..df5a7cc --- /dev/null +++ b/tests/CommandBusLauncher/CommandReflectionTest.php @@ -0,0 +1,95 @@ +createCommand($commandParameters, $argumentProcessor); + + \PHPUnit_Framework_Assert::assertInstanceOf(DummyCommand::class, $command); + \PHPUnit_Framework_Assert::assertEquals('lorem ipsum', $command->argument1); + \PHPUnit_Framework_Assert::assertTrue(2 === $command->argument2); + } + + /** + * @test + */ + public function it_returns_new_command_with_uuid_instance() + { + $argumentProcessor = new ArgumentsProcessor([new UuidConverter()]); + $commandReflection = CommandReflection::fromClass(DummyCommandWithUuid::class); + + $commandParameters = ['lorem ipsum', '1a67b1de-e3cb-471e-90d3-005341a29b3d']; + $command = $commandReflection->createCommand($commandParameters, $argumentProcessor); + + \PHPUnit_Framework_Assert::assertInstanceOf(DummyCommandWithUuid::class, $command); + \PHPUnit_Framework_Assert::assertEquals('lorem ipsum', $command->argument1); + \PHPUnit_Framework_Assert::assertTrue(Uuid::fromString('1a67b1de-e3cb-471e-90d3-005341a29b3d')->equals($command->argument2)); + } + + /** + * @test + */ + public function it_returns_command_constructor_parameters() + { + $commandReflection = CommandReflection::fromClass(DummyCommand::class); + + $commandParameters = $commandReflection->parameters(); + + \PHPUnit_Framework_Assert::assertEquals('argument1', $commandParameters[0]->name); + \PHPUnit_Framework_Assert::assertEquals('argument2', $commandParameters[1]->name); + } + + /** + * @test + * @expectedException \ClearcodeHQ\CommandBusLauncher\MissingCommandArgument + */ + public function it_does_not_returns_command_when_arguments_are_missing() + { + $argumentProcessor = new ArgumentsProcessor([new UuidConverter()]); + $commandReflection = CommandReflection::fromClass(DummyCommandWithUuid::class); + + $commandParameters = []; + $commandReflection->createCommand($commandParameters, $argumentProcessor); + } + + /** + * @test + * @expectedException \ClearcodeHQ\CommandBusLauncher\InvalidCommandArgument + */ + public function it_does_not_returns_command_when_invalid_arguments_are_given() + { + $argumentProcessor = new ArgumentsProcessor([new UuidConverter()]); + $commandReflection = CommandReflection::fromClass(DummyCommandWithUuid::class); + + $commandParameters = ['lorem ipsum', 2]; + $commandReflection->createCommand($commandParameters, $argumentProcessor); + } +} diff --git a/tests/CommandBusLauncher/Mocks/DummyCommand.php b/tests/CommandBusLauncher/Mocks/DummyCommand.php new file mode 100644 index 0000000..3ffe2dd --- /dev/null +++ b/tests/CommandBusLauncher/Mocks/DummyCommand.php @@ -0,0 +1,18 @@ +argument1 = $argument1; + $this->argument2 = $argument2; + } +} diff --git a/tests/CommandBusLauncher/Mocks/DummyCommandWithUuid.php b/tests/CommandBusLauncher/Mocks/DummyCommandWithUuid.php new file mode 100644 index 0000000..0a6ada6 --- /dev/null +++ b/tests/CommandBusLauncher/Mocks/DummyCommandWithUuid.php @@ -0,0 +1,20 @@ +argument1 = $argument1; + $this->argument2 = $argumentUuid; + } +} diff --git a/tests/CommandBusLauncher/ValueConverter/IntConverterTest.php b/tests/CommandBusLauncher/ValueConverter/IntConverterTest.php new file mode 100644 index 0000000..a894365 --- /dev/null +++ b/tests/CommandBusLauncher/ValueConverter/IntConverterTest.php @@ -0,0 +1,36 @@ +sut->convert('123'); + + $this->assertTrue(123 === $int); + } + + /** + * @test + */ + public function it_does_not_converts_non_numeric_string_to_int() + { + $invalidInt = $this->sut->convert('string'); + + $this->assertTrue($invalidInt === null); + } + + public function setUp() + { + $this->sut = new IntConverter(); + } +} diff --git a/tests/CommandBusLauncher/ValueConverter/UuidConverterTest.php b/tests/CommandBusLauncher/ValueConverter/UuidConverterTest.php new file mode 100644 index 0000000..8dad81b --- /dev/null +++ b/tests/CommandBusLauncher/ValueConverter/UuidConverterTest.php @@ -0,0 +1,38 @@ +sut->convert('9d3e2d0a-f4d0-496d-9a5f-a00fe99b2053'); + + $this->assertInstanceOf(Uuid::class, $uuid); + $this->assertTrue(Uuid::fromString('9d3e2d0a-f4d0-496d-9a5f-a00fe99b2053')->equals($uuid)); + } + + /** + * @test + */ + public function it_does_not_converts_invalid_string_to_uuid() + { + $uuid = $this->sut->convert('9d3efe99b2053'); + + $this->assertTrue($uuid === null); + } + + public function setUp() + { + $this->sut = new UuidConverter(); + } +}