diff --git a/src/Sylius/Bundle/FlowBundle/Tests/Process/Builder/ProcessBuilderTest.php b/src/Sylius/Bundle/FlowBundle/Tests/Process/Builder/ProcessBuilderTest.php new file mode 100644 index 0000000000..abead90a83 --- /dev/null +++ b/src/Sylius/Bundle/FlowBundle/Tests/Process/Builder/ProcessBuilderTest.php @@ -0,0 +1,294 @@ + + */ +class ProcessBuilderTest extends \PHPUnit_Framework_TestCase +{ + private $builder; + + public function setUp() + { + $this->builder = new TestProcessBuilder($this->getMock('Symfony\Component\DependencyInjection\ContainerInterface')); + } + + /** + * @test + */ + public function shouldCreateProcess() + { + $process = $this->builder->build($this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + + $this->assertInstanceOf('Sylius\Bundle\FlowBundle\Process\Process', $process); + } + + /** + * @test + */ + public function shouldBuildScenario() + { + $scenario = $this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface'); + $scenario->expects($this->once()) + ->method('build') + ->with($this->equalTo($this->builder)); + + $this->builder->build($scenario); + } + + /** + * @test + * @expectedException \RuntimeException + */ + public function shouldNotAddWihtoutProcess() + { + $process = $this->getMock('Sylius\Bundle\FlowBundle\Process\ProcessInterface'); + + $this->builder->registerStep('new', $this->getStep('somename')); + $this->builder->add('somename', 'new'); + } + + /** + * @test + * @covers Sylius\Bundle\FlowBundle\Process\Builder\ProcessBuilder::add + */ + public function shouldInjectContainerToContainerAwareStep() + { + $step = $this->getMock('Sylius\Bundle\FlowBundle\Process\Step\ContainerAwareStep'); + $step->expects($this->once()) + ->method('setContainer') + ->with($this->isInstanceOf('Symfony\Component\DependencyInjection\ContainerInterface')); + + $this->builder->build($this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + $this->builder->add('somename', $step); + } + + /** + * @test + * @covers Sylius\Bundle\FlowBundle\Process\Builder\ProcessBuilder::add + * @covers Sylius\Bundle\FlowBundle\Process\Builder\ProcessBuilder::registerStep + */ + public function shouldAcceptStepAliasWhileAdding() + { + $step = $this->getStep(); + $step->expects($this->any()) + ->method('setName') + ->with($this->equalTo('somename')); + + $this->builder->build($this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + $this->builder->registerStep('new', $step); + $this->builder->add('somename', 'new'); + + $this->assertSame($step, $this->builder->getProcess()->getStepByName('somename')); + $this->assertCount(1, $this->builder->getProcess()->getSteps()); + } + + /** + * @test + * @covers Sylius\Bundle\FlowBundle\Process\Builder\ProcessBuilder::add + * @expectedException InvalidArgumentException + */ + public function shouldNotAddObjectWhichAreNotSteps() + { + $this->builder->build($this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + $this->builder->add('some', new \stdClass); + } + + /** + * @test + * @expectedException \RuntimeException + */ + public function shouldNotRemoveStepWithoutProcess() + { + $this->builder->remove('test'); + } + + /** + * @test + */ + public function shouldRemoveStepFromProcess() + { + $this->builder->build($this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + $this->builder->add('some', $this->getStep('some')); + $this->builder->remove('some'); + + $this->assertCount(0, $this->builder->getProcess()->getSteps()); + } + + /** + * @test + * @expectedException \RuntimeException + */ + public function shouldNotCheckIfStepIsSetWithoutProcess() + { + $this->builder->has('test'); + } + + /** + * @test + */ + public function shouldCheckIfStepIsSet() + { + $this->builder->build($this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + + $this->assertFalse($this->builder->has('some')); + $this->builder->add('some', $this->getStep('some')); + $this->assertTrue($this->builder->has('some')); + } + + /** + * @test + * @expectedException \RuntimeException + */ + public function shouldNotInjectDisplayRouteWithoutProcess() + { + $this->builder->setDisplayRoute('display_route'); + } + + /** + * @test + */ + public function shouldInjectDisplayRouteToProcess() + { + $this->builder->build($this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + $this->builder->setDisplayRoute('display_route'); + + $this->assertEquals('display_route', $this->builder->getProcess()->getDisplayRoute()); + } + + /** + * @test + * @expectedException \RuntimeException + */ + public function shouldNotInjectForwardRouteWithoutProcess() + { + $this->builder->setForwardRoute('forward_route'); + } + + /** + * @test + */ + public function shouldInjectForwardRouteToProcess() + { + $this->builder->build($this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + $this->builder->setForwardRoute('forward_route'); + + $this->assertEquals('forward_route', $this->builder->getProcess()->getForwardRoute()); + } + + /** + * @test + * @expectedException \RuntimeException + */ + public function shouldNotInjectRedirectWithoutProcess() + { + $this->builder->setRedirect('redirect'); + } + + /** + * @test + */ + public function shouldInjectRedirectToProcess() + { + $this->builder->build($this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + $this->builder->setRedirect('redirect'); + + $this->assertEquals('redirect', $this->builder->getProcess()->getRedirect()); + } + + /** + * @test + * @expectedException \RuntimeException + */ + public function shouldNotInjectValidationClosureWithoutProcess() + { + $this->builder->validate(function () { + return 'my-closure'; + }); + } + + /** + * @test + */ + public function shouldInjectValidationClosureToProcess() + { + $this->builder->build($this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + $this->builder->validate(function () { + return 'my-closure'; + }); + + $validator = $this->builder->getProcess()->getValidator(); + $this->assertEquals('my-closure', $validator()); + } + + /** + * @test + * @expectedException InvalidArgumentException + */ + public function shouldNotRegisterTwoThisSameSteps() + { + $this->builder->registerStep('new', $this->getStep('somename')); + $this->builder->registerStep('new', $this->getStep('somename')); + } + + /** + * @test + * @expectedException InvalidArgumentException + */ + public function shouldNotLoadStepWhenWasNotRegisteredBefore() + { + $this->builder->loadStep('new'); + } + + /** + * @test + */ + public function shouldLoadStep() + { + $step = $this->getStep('somename'); + $this->builder->registerStep('new', $step); + + $this->assertSame($this->builder->loadStep('new'), $step); + } + + private function getStep($name = '') + { + $step = $this->getMock('Sylius\Bundle\FlowBundle\Process\Step\StepInterface'); + $step->expects($this->any()) + ->method('getName') + ->will($this->returnValue($name)); + $step->expects($this->any()) + ->method('displayAction') + ->will($this->returnValue('displayActionResponse')); + $step->expects($this->any()) + ->method('forwardAction') + ->will($this->returnValue('forwardActionResponse')); + + return $step; + } +} + +class TestProcessBuilder extends ProcessBuilder +{ + /** + * Method getProcess exists only in TestProcessBuilder to allow testing + */ + public function getProcess() + { + return $this->process; + } +} diff --git a/src/Sylius/Bundle/FlowBundle/Tests/Process/Context/ProcessContextTest.php b/src/Sylius/Bundle/FlowBundle/Tests/Process/Context/ProcessContextTest.php new file mode 100644 index 0000000000..9307032857 --- /dev/null +++ b/src/Sylius/Bundle/FlowBundle/Tests/Process/Context/ProcessContextTest.php @@ -0,0 +1,430 @@ + + */ +class ProcessContextTest extends \PHPUnit_Framework_TestCase +{ + /** + * @test + * @dataProvider getMethodsWithoutInitialize + * @expectedException RuntimeException + */ + public function shouldNotExecuteMethodsWithoutContextInitialize($methodName) + { + $context = new ProcessContext($this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface')); + $context->$methodName(); + } + + public function getMethodsWithoutInitialize() + { + return array( + array('isValid'), + array('getProcess'), + array('getCurrentStep'), + array('getPreviousStep'), + array('getNextStep'), + array('isFirstStep'), + array('isLastStep'), + array('complete'), + array('isCompleted'), + array('close'), + array('getProgress'), + array('getProgress'), + ); + } + + /** + * @test + */ + public function shouldInitializeStorage() + { + $storage = $this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface'); + $storage->expects($this->once()) + ->method('initialize') + ->with($this->equalTo(md5('scenarioOne'))); + + $context = new ProcessContext($storage); + $context->initialize($this->getProcess(), $this->getStep('myStep')); + } + + /** + * @test + */ + public function shouldSetPreviousStepWhenInitialize() + { + $steps = array( + $this->getStep('step1'), + $this->getStep('step2') + ); + $process = $this->getProcess($steps); + $context = new ProcessContext($this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface')); + $context->initialize($process, $steps[1]); + + $this->assertEquals('step1', $context->getPreviousStep()->getName()); + } + + /** + * @test + */ + public function shouldSetNextStepWhenInitialize() + { + $steps = array( + $this->getStep('step1'), + $this->getStep('step2') + ); + $process = $this->getProcess($steps); + $context = new ProcessContext($this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface')); + $context->initialize($process, $steps[0]); + + $this->assertEquals('step2', $context->getNextStep()->getName()); + } + + /** + * @test + */ + public function shouldSetCurrentStepWhenInitialize() + { + $steps = array( + $this->getStep('step1'), + $this->getStep('step2') + ); + $process = $this->getProcess($steps); + $context = new ProcessContext($this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface')); + $context->initialize($process, $steps[0]); + + $this->assertSame($steps[0], $context->getCurrentStep()); + } + + /** + * @test + */ + public function shouldKnowWhenFirstStep() + { + $steps = array( + $this->getStep('step1'), + $this->getStep('step2') + ); + $process = $this->getProcess($steps); + + $firstStepContext = new ProcessContext($this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface')); + $firstStepContext->initialize($process, $steps[0]); + $lastStepContext = new ProcessContext($this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface')); + $lastStepContext->initialize($process, $steps[1]); + + $this->assertTrue($firstStepContext->isFirstStep()); + $this->assertFalse($lastStepContext->isFirstStep()); + } + + /** + * @test + */ + public function shouldClearStorageWhenClose() + { + $storage = $this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface'); + $storage->expects($this->once()) + ->method('clear'); + + $context = new ProcessContext($storage); + $context->initialize($this->getProcess(), $this->getStep('myStep')); + $context->close(); + } + + /** + * @test + */ + public function shouldKnowWhenLastStep() + { + $steps = array( + $this->getStep('step1'), + $this->getStep('step2') + ); + $process = $this->getProcess($steps); + + $firstStepContext = new ProcessContext($this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface')); + $firstStepContext->initialize($process, $steps[0]); + $lastStepContext = new ProcessContext($this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface')); + $lastStepContext->initialize($process, $steps[1]); + + $this->assertFalse($firstStepContext->isLastStep()); + $this->assertTrue($lastStepContext->isLastStep()); + } + + /** + * @test + */ + public function shouldSetRequest() + { + $request = $this->getMock('Symfony\Component\HttpFoundation\Request'); + + $context = new ProcessContext($this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface')); + $context->setRequest($request); + + $this->assertSame($request, $context->getRequest()); + } + + /** + * @test + */ + public function shouldGetProcess() + { + $steps = array( + $this->getStep('step1'), + $this->getStep('step2') + ); + $process = $this->getProcess($steps); + + $context = new ProcessContext($this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface')); + $context->initialize($process, $steps[0]); + + $this->assertSame($process, $context->getProcess()); + } + + /** + * @test + */ + public function shouldNotBeValidWhenProcessValidatorIsNotValid() + { + $steps = array( + $this->getStep('step1'), + $this->getStep('step2') + ); + $process = $this->getProcess($steps); + $process->expects($this->once()) + ->method('getValidator') + ->will($this->returnValue(function () { + return false; + })); + + $context = new ProcessContext($this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface')); + $context->initialize($process, $steps[0]); + + $this->assertFalse($context->isValid()); + } + + /** + * @test + */ + public function shouldNotBeValidWhenOneOfPreviousStepIsCompeleted() + { + $steps = array( + $this->getStep('step1'), + $this->getStep('step2') + ); + $process = $this->getProcess($steps); + + $storage = new TestArrayStorage(); + $storage->set('_status.step1', ProcessContextInterface::STEP_STATE_COMPLETED); + + $context = new ProcessContext($storage); + $context->initialize($process, $steps[1]); + + $this->assertFalse($context->isValid()); + } + + /** + * @test + */ + public function shouldBeValid() + { + $steps = array( + $this->getStep('step1'), + $this->getStep('step2') + ); + $process = $this->getProcess($steps); + + $context = new ProcessContext($this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface')); + $context->initialize($process, $steps[0]); + + $this->assertTrue($context->isValid()); + } + + /** + * @test + */ + public function shouldBeValidWithoutSteps() + { + $process = $this->getProcess(array()); + + $context = new ProcessContext($this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface')); + $context->initialize($process, $this->getStep('someStep')); + + $this->assertTrue($context->isValid()); + } + + /** + * @test + */ + public function shouldCompleteProcess() + { + $storage = new TestArrayStorage(); + + $steps = array( + $this->getStep('step1'), + $this->getStep('step2') + ); + $process = $this->getProcess($steps); + $context = new ProcessContext($storage); + $context->initialize($process, $steps[0]); + $this->assertFalse($context->isCompleted()); + $context->complete(); + + $this->assertEquals(ProcessContextInterface::STEP_STATE_COMPLETED, $storage->get('_state.step1')); + $this->assertTrue($context->isCompleted()); + } + + /** + * @test + * @dataProvider getProgressData + */ + public function shouldCalculateProgress($steps, $index, $expectedProgress) + { + $process = $this->getProcess($steps); + + $context = new ProcessContext($this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface')); + $context->initialize($process, $steps[$index]); + + $this->assertEquals($context->getProgress(), $expectedProgress); + } + + public function getProgressData() + { + return array( + array( + array( + $this->getStep('step1'), + $this->getStep('step2') + ), + 0, + 50 + ), + array( + array( + $this->getStep('step1'), + $this->getStep('step2') + ), + 1, + 100 + ), + array( + array( + $this->getStep('step1'), + $this->getStep('step2'), + $this->getStep('step3') + ), + 0, + 33 + ), + array( + array( + $this->getStep('step1'), + $this->getStep('step2'), + $this->getStep('step3') + ), + 1, + 66 + ), + ); + } + + /** + * @test + */ + public function shouldInjectStorageBySetter() + { + $storage1 = $this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface'); + $storage2 = $this->getMock('Sylius\Bundle\FlowBundle\Storage\StorageInterface'); + + $context = new ProcessContext($storage1); + $context->setStorage($storage2); + + $this->assertSame($storage2, $context->getStorage()); + } + + private function getProcess($steps = array()) + { + $process = $this->getMock('Sylius\Bundle\FlowBundle\Process\ProcessInterface'); + $process->expects($this->any()) + ->method('setScenarioAlias') + ->with($this->equalTo('scenarioOne')); + $process->expects($this->any()) + ->method('getScenarioAlias') + ->will($this->returnValue('scenarioOne')); + $process->expects($this->any()) + ->method('getOrderedSteps') + ->will($this->returnValue($steps)); + $process->expects($this->any()) + ->method('countSteps') + ->will($this->returnValue(count($steps))); + + return $process; + } + + private function getStep($name) + { + $step = $this->getMock('Sylius\Bundle\FlowBundle\Process\Step\StepInterface'); + $step->expects($this->any()) + ->method('getName') + ->will($this->returnValue($name)); + $step->expects($this->any()) + ->method('displayAction') + ->will($this->returnValue('displayActionResponse')); + $step->expects($this->any()) + ->method('forwardAction') + ->will($this->returnValue('forwardActionResponse')); + + return $step; + } +} + +class TestArrayStorage implements StorageInterface +{ + private $data = array(); + + public function initialize($domain) + { + + } + + public function has($key) + { + return isset($this->data[$key]); + } + + public function get($key, $default = null) + { + return $this->has($key) ? $this->data[$key] : $default; + } + + public function set($key, $value) + { + $this->data[$key] = $value; + } + + public function remove($key) + { + unset($this->data[$key]); + } + + public function clear() + { + $this->data = array(); + } +} diff --git a/src/Sylius/Bundle/FlowBundle/Tests/Process/Coordinator/CoordinatorTest.php b/src/Sylius/Bundle/FlowBundle/Tests/Process/Coordinator/CoordinatorTest.php new file mode 100644 index 0000000000..d8163e35eb --- /dev/null +++ b/src/Sylius/Bundle/FlowBundle/Tests/Process/Coordinator/CoordinatorTest.php @@ -0,0 +1,382 @@ + + */ +class CoordinatorTest extends \PHPUnit_Framework_TestCase +{ + private $coordinator; + + public function setUp() + { + $router = $this->getRouter( + 'sylius_flow_display', + array( + 'scenarioAlias' => 'scenarioOne', + 'stepName' => 'firstStepName' + ), + 'http://someurl.dev/step/scenarioOne/firstStepName' + ); + + $processBuilder = $this->getProcessBuilder($this->getProcess()); + + $processContext = $this->getProcessContext(); + $processContext->expects($this->any()) + ->method('isValid') + ->will($this->returnValue(true)); + + $this->coordinator = $this->createCoordinator($router, $processBuilder, $processContext); + } + + /** + * @test + */ + public function shouldRedirectToDefaultDisplayActionWhenStarting() + { + $this->coordinator->registerScenario('scenarioOne', $this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + + $response = $this->coordinator->start('scenarioOne'); + + $this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response); + $this->assertEquals('http://someurl.dev/step/scenarioOne/firstStepName', $response->getTargetUrl()); + } + + /** + * @test + */ + public function shouldRedirectToMyRouteDisplayActionWhenStarting() + { + $router = $this->getRouter( + 'my_route', + array( + 'stepName' => 'firstStepName' + ), + 'http://someurl.dev/my-super-route/firstStepName' + ); + + $process = $this->getProcess(); + $process->expects($this->any()) + ->method('getDisplayRoute') + ->will($this->returnValue('my_route')); + + $processBuilder = $this->getProcessBuilder($process); + + $processContext = $this->getProcessContext(); + $processContext->expects($this->any()) + ->method('isValid') + ->will($this->returnValue(true)); + + $this->coordinator = $this->createCoordinator($router, $processBuilder, $processContext); + $this->coordinator->registerScenario('scenarioOne', $this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + $response = $this->coordinator->start('scenarioOne'); + + $this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response); + $this->assertEquals('http://someurl.dev/my-super-route/firstStepName', $response->getTargetUrl()); + } + + /** + * @test + * @expectedException InvalidArgumentException + * @expectedExceptionMessage Process scenario with alias "scenarioOne" is not registered + */ + public function shouldNotStartWhenScenarioIsNotRegistered() + { + $this->coordinator->start('scenarioOne'); + } + + /** + * @test + * @expectedException Symfony\Component\HttpKernel\Exception\NotFoundHttpException + */ + public function shouldNotStartWhenProcessIsNotValid() + { + $router = $this->getRouter(); + + $processBuilder = $this->getProcessBuilder($this->getProcess()); + + $processContext = $this->getProcessContext(); + $processContext->expects($this->any()) + ->method('isValid') + ->will($this->returnValue(false)); + + $this->coordinator = $this->createCoordinator($router, $processBuilder, $processContext); + $this->coordinator->registerScenario('scenarioOne', $this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + $this->coordinator->start('scenarioOne'); + } + + /** + * @test + */ + public function shouldShowDisplayAction() + { + $this->coordinator->registerScenario('scenarioOne', $this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + + $this->assertEquals('displayActionResponse', $this->coordinator->display('scenarioOne', 'someStepName')); + } + + /** + * @test + * @expectedException Symfony\Component\HttpKernel\Exception\NotFoundHttpException + */ + public function shouldNotShowDisplayActionWhenProcessIsNotValid() + { + $router = $this->getRouter(); + + $processBuilder = $this->getProcessBuilder($this->getProcess()); + + $processContext = $this->getProcessContext(); + $processContext->expects($this->any()) + ->method('isValid') + ->will($this->returnValue(false)); + + $this->coordinator = $this->createCoordinator($router, $processBuilder, $processContext); + $this->coordinator->registerScenario('scenarioOne', $this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + $this->coordinator->display('scenarioOne', 'someStepName'); + } + + /** + * @test + * @expectedException InvalidArgumentException + * @expectedExceptionMessage Process scenario with alias "scenarioOne" is not registered + */ + public function shouldNotShowDisplayActionWhenScenarioIsNotRegistered() + { + $this->coordinator->display('scenarioOne', 'someStepName'); + } + + /** + * @test + * @expectedException InvalidArgumentException + * @expectedExceptionMessage Process scenario with alias "scenarioOne" is not registered + */ + public function shouldNotShowForwardActionWhenScenarioIsNotRegistered() + { + $this->coordinator->forward('scenarioOne', 'someStepName'); + } + + /** + * @test + * @expectedException Symfony\Component\HttpKernel\Exception\NotFoundHttpException + */ + public function shouldNotShowForwardWhenProcessIsNotValid() + { + $router = $this->getRouter(); + + $processBuilder = $this->getProcessBuilder($this->getProcess()); + + $processContext = $this->getProcessContext(); + $processContext->expects($this->any()) + ->method('isValid') + ->will($this->returnValue(false)); + + $this->coordinator = $this->createCoordinator($router, $processBuilder, $processContext); + $this->coordinator->registerScenario('scenarioOne', $this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + $this->coordinator->forward('scenarioOne', 'someStepName'); + } + + /** + * @test + * @covers Sylius\Bundle\FlowBundle\Process\Coordinator\Coordinator::forward + */ + public function shouldShowForwardActionWhenStepIsNotCompleted() + { + $router = $this->getRouter(); + + $processBuilder = $this->getProcessBuilder($this->getProcess()); + + $processContext = $this->getProcessContext(); + $processContext->expects($this->any()) + ->method('isValid') + ->will($this->returnValue(true)); + $processContext->expects($this->any()) + ->method('isCompleted') + ->will($this->returnValue(false)); + + $this->coordinator = $this->createCoordinator($router, $processBuilder, $processContext); + $this->coordinator->registerScenario('scenarioOne', $this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + + $this->assertEquals('forwardActionResponse', $this->coordinator->forward('scenarioOne', 'someStepName')); + } + + /** + * @test + * @expectedException InvalidArgumentException + * @expectedExceptionMessage Process scenario with alias "scenarioOne" is already registered + */ + public function shouldNotRegisterScenarioAgain() + { + $this->coordinator->registerScenario('scenarioOne', $this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + $this->coordinator->registerScenario('scenarioOne', $this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + } + + /** + * @test + * @covers Sylius\Bundle\FlowBundle\Process\Coordinator\Coordinator::forward + */ + public function shouldRedirectToNextStepDisplayActionWhenStepIsCompleted() + { + $router = $this->getRouter( + 'sylius_flow_display', + array( + 'scenarioAlias' => 'scenarioOne', + 'stepName' => 'nextStepName' + ), + 'http://someurl.dev/step/scenarioOne/nextStepName' + ); + + $processBuilder = $this->getProcessBuilder($this->getProcess()); + + $processContext = $this->getProcessContext(); + $processContext->expects($this->any()) + ->method('isValid') + ->will($this->returnValue(true)); + $processContext->expects($this->any()) + ->method('getNextStep') + ->will($this->returnValue( + $this->getStep('nextStepName') + )); + $processContext->expects($this->any()) + ->method('isCompleted') + ->will($this->returnValue(true)); + + $this->coordinator = $this->createCoordinator($router, $processBuilder, $processContext); + $this->coordinator->registerScenario('scenarioOne', $this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + + $response = $this->coordinator->forward('scenarioOne', 'someStepName'); + + $this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response); + $this->assertEquals('http://someurl.dev/step/scenarioOne/nextStepName', $response->getTargetUrl()); + } + + /** + * @test + * @covers Sylius\Bundle\FlowBundle\Process\Coordinator\Coordinator::forward + */ + public function shouldDoProcessRedirectWhenLastStepIsCompleted() + { + + $router = $this->getRouter( + 'http://localhost/processRedirect', + array(), + 'http://localhost/processRedirect' + ); + + $processBuilder = $this->getProcessBuilder($this->getProcess()); + + $processContext = $this->getProcessContext(); + $processContext->expects($this->any()) + ->method('isValid') + ->will($this->returnValue(true)); + $processContext->expects($this->any()) + ->method('isCompleted') + ->will($this->returnValue(true)); + $processContext->expects($this->once()) + ->method('close'); + $processContext->expects($this->once()) + ->method('isLastStep') + ->will($this->returnValue(true)); + + $this->coordinator = $this->createCoordinator($router, $processBuilder, $processContext); + $this->coordinator->registerScenario('scenarioOne', $this->getMock('Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface')); + + $response = $this->coordinator->forward('scenarioOne', 'someStepName'); + + $this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response); + $this->assertEquals('http://localhost/processRedirect', $response->getTargetUrl()); + } + + private function createCoordinator($router, $processBuilder, $processContext) + { + return new Coordinator( + $router, + $processBuilder, + $processContext + ); + } + + private function getRouter($route = '', $secondParam = array(), $url = 'http://someurl.dev') + { + $router = $this->getMock('Symfony\Component\Routing\RouterInterface'); + $router->expects($this->any()) + ->method('generate') + ->with($this->equalTo($route), $this->equalTo($secondParam)) + ->will($this->returnValue($url)); + + return $router; + } + + private function getProcessBuilder($process) + { + $builder = $this->getMock('Sylius\Bundle\FlowBundle\Process\Builder\ProcessBuilderInterface'); + $builder->expects($this->any()) + ->method('build') + ->will($this->returnValue( + $process + )); + + return $builder; + } + + private function getProcessContext() + { + return $this->getMock('Sylius\Bundle\FlowBundle\Process\Context\ProcessContextInterface'); + } + + private function getProcess() + { + $process = $this->getMock('Sylius\Bundle\FlowBundle\Process\ProcessInterface'); + $process->expects($this->any()) + ->method('getFirstStep') + ->will($this->returnValue( + $this->getStep('firstStepName') + )); + $process->expects($this->any()) + ->method('getStepByName') + ->with($this->equalTo('someStepName')) + ->will($this->returnValue( + $this->getStep('someStepName') + )); + $process->expects($this->any()) + ->method('setScenarioAlias') + ->with($this->equalTo('scenarioOne')); + $process->expects($this->any()) + ->method('getScenarioAlias') + ->will($this->returnValue('scenarioOne')); + $process->expects($this->any()) + ->method('getRedirect') + ->will($this->returnValue('http://localhost/processRedirect')); + + return $process; + } + + private function getStep($name) + { + $step = $this->getMock('Sylius\Bundle\FlowBundle\Process\Step\StepInterface'); + $step->expects($this->any()) + ->method('getName') + ->will($this->returnValue($name)); + $step->expects($this->any()) + ->method('displayAction') + ->will($this->returnValue('displayActionResponse')); + $step->expects($this->any()) + ->method('forwardAction') + ->will($this->returnValue('forwardActionResponse')); + + return $step; + } +} diff --git a/src/Sylius/Bundle/FlowBundle/Tests/Process/ProcessTest.php b/src/Sylius/Bundle/FlowBundle/Tests/Process/ProcessTest.php index 60b653e153..f220b287e4 100644 --- a/src/Sylius/Bundle/FlowBundle/Tests/Process/ProcessTest.php +++ b/src/Sylius/Bundle/FlowBundle/Tests/Process/ProcessTest.php @@ -19,6 +19,7 @@ use Sylius\Bundle\FlowBundle\Process\Step\Step; * Process test. * * @author Paweł Jędrzejewski + * @author Leszek Prabucki */ class ProcessTest extends \PHPUnit_Framework_TestCase { @@ -43,6 +44,276 @@ class ProcessTest extends \PHPUnit_Framework_TestCase $this->assertSame($name, $process->getStepByIndex($i)->getName()); } } + + /** + * @test + */ + public function shouldKeepStepsInOrderAfterSetSteps() + { + $process = new Process(); + + $process->setSteps(array( + 'foo' => new TestStep(), + 'bar' => new TestStep(), + 'foobar' => new TestStep() + )); + + $correctOrder = array('foo', 'bar', 'foobar'); + + foreach ($process->getOrderedSteps() as $i => $step) { + $this->assertSame($correctOrder[$i], $step->getName()); + } + + foreach ($correctOrder as $i => $name) { + $this->assertSame($name, $process->getStepByIndex($i)->getName()); + } + } + + /** + * @test + */ + public function shouldAddStep() + { + $process = new Process(); + $step1 = new TestStep(); + $process->addStep('foo', $step1); + + $steps = $process->getSteps(); + $this->assertSame($step1, $steps['foo']); + } + + /** + * @test + * @covers Sylius\Bundle\FlowBundle\Process\Process::removeStep + */ + public function shouldRemoveStep() + { + $process = new Process(); + $process->addStep('foo', new TestStep()); + $process->removeStep('foo'); + + $this->assertCount(0, $process->getSteps()); + } + + /** + * @test + * @covers Sylius\Bundle\FlowBundle\Process\Process::removeStep + * @expectedException \InvalidArgumentException + */ + public function shouldNotRemoveStepWhenWasNotSet() + { + $process = new Process(); + $process->removeStep('foo'); + } + + /** + * @test + */ + public function shouldSetSteps() + { + $process = new Process(); + $step1 = new TestStep(); + $process->setSteps(array('foo' => $step1)); + + $steps = $process->getSteps(); + $this->assertSame($step1, $steps['foo']); + } + + /** + * @test + * @expectedException \InvalidArgumentException + */ + public function shouldNotAddStepWithThisSameNameAgain() + { + $process = new Process(); + + $process->addStep('foo', new TestStep()); + $process->addStep('foo', new TestStep()); + } + + /** + * @test + */ + public function shouldGetStepUsingIndexAfterSetSteps() + { + $process = new Process(); + + $step1 = new TestStep(); + $step2 = new TestStep(); + + $process->setSteps(array( + 'foo' => $step1, + 'bar' => $step2, + )); + + $this->assertSame($step1, $process->getStepByIndex(0)); + $this->assertSame($step2, $process->getStepByIndex(1)); + } + + /** + * @test + */ + public function shouldGetStepUsingIndexAfterStepAddition() + { + $process = new Process(); + + $step1 = new TestStep(); + $step2 = new TestStep(); + + $process->addStep('foo', $step1); + $process->addStep('bar', $step2); + + $this->assertSame($step1, $process->getStepByIndex(0)); + $this->assertSame($step2, $process->getStepByIndex(1)); + } + + /** + * @test + * @expectedException \InvalidArgumentException + */ + public function shouldNotGetStepUsingIndexWhenWasNotSet() + { + $process = new Process(); + $process->getStepByIndex(0); + } + + /** + * @test + */ + public function shouldGetStepUsingNameAfterSetSteps() + { + $process = new Process(); + + $step1 = new TestStep(); + $step2 = new TestStep(); + + $process->setSteps(array( + 'foo' => $step1, + 'bar' => $step2, + )); + + $this->assertSame($step1, $process->getStepByName('foo')); + $this->assertSame($step2, $process->getStepByName('bar')); + } + + /** + * @test + */ + public function shouldGetStepUsingNameAfterStepAddition() + { + $process = new Process(); + + $step1 = new TestStep(); + $step2 = new TestStep(); + + $process->addStep('foo', $step1); + $process->addStep('bar', $step2); + + $this->assertSame($step1, $process->getStepByName('foo')); + $this->assertSame($step2, $process->getStepByName('bar')); + } + + /** + * @test + * @expectedException \InvalidArgumentException + */ + public function shouldNotGetStepUsingNameWhenWasNotSet() + { + $process = new Process(); + $process->getStepByName('foo'); + } + + /** + * @test + * @covers Sylius\Bundle\FlowBundle\Process\Process::getLastStep + */ + public function shouldGetLastStep() + { + $process = new Process(); + + $step1 = new TestStep(); + $step2 = new TestStep(); + + $process->addStep('foo', $step1); + $process->addStep('bar', $step2); + + $this->assertSame($step2, $process->getLastStep()); + } + + /** + * @test + * @covers Sylius\Bundle\FlowBundle\Process\Process::getFirstStep + */ + public function shouldGetFirstStep() + { + $process = new Process(); + + $step1 = new TestStep(); + $step2 = new TestStep(); + + $process->addStep('foo', $step1); + $process->addStep('bar', $step2); + + $this->assertSame($step1, $process->getFirstStep()); + } + + /** + * @test + */ + public function shouldSetNeededDataUsingSetter() + { + $process = new Process(); + $process->setScenarioAlias('alias'); + $process->setDisplayRoute('displayRoute'); + $process->setForwardRoute('forwardRoute'); + $process->setRedirect('http://somepage'); + $process->setValidator(function () { + return 'Awesome validator'; + }); + + $validator = $process->getValidator(); + $this->assertSame('alias', $process->getScenarioAlias()); + $this->assertSame('displayRoute', $process->getDisplayRoute()); + $this->assertSame('forwardRoute', $process->getForwardRoute()); + $this->assertSame('http://somepage', $process->getRedirect()); + $this->assertSame('Awesome validator', $validator()); + } + + /** + * @test + * @covers Sylius\Bundle\FlowBundle\Process\Process::countSteps + * @dataProvider countStepsDataProvider + */ + public function shouldCountSteps($steps, $expectedCount) + { + $process = new Process(); + + $process->setSteps($steps); + + $this->assertEquals($process->countSteps(), $expectedCount); + } + + public function countStepsDataProvider() + { + return array( + array( + array(new TestStep(), new TestStep()), + 2 + ), + array( + array('abc' => new TestStep(), 'abc' => new TestStep()), + 1 + ), + array( + array('abc' => new TestStep()), + 1 + ), + array( + array('abc' => new TestStep(), 'zzz' => new TestStep(), 'yyy' => new TestStep()), + 3 + ), + ); + } } class TestStep extends Step diff --git a/src/Sylius/Bundle/FlowBundle/Tests/Process/Step/ContainerAwareStepTest.php b/src/Sylius/Bundle/FlowBundle/Tests/Process/Step/ContainerAwareStepTest.php new file mode 100644 index 0000000000..b12d0199cc --- /dev/null +++ b/src/Sylius/Bundle/FlowBundle/Tests/Process/Step/ContainerAwareStepTest.php @@ -0,0 +1,52 @@ + + */ +class ContainerAwareStepTest extends \PHPUnit_Framework_TestCase +{ + /** + * @test + * @covers Sylius\Bundle\FlowBundle\Process\Step\ContainerAwareStep::setContainer + */ + public function shouldInjectContainerBySetter() + { + $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); + $step = new TestContainerAwareStep(); + $step->setContainer($container); + + $this->assertSame($step->getContainer(), $container); + } +} + +class TestContainerAwareStep extends ContainerAwareStep +{ + /** + * Just for check if container setter works + */ + public function getContainer() + { + return $this->container; + } + + public function displayAction(ProcessContextInterface $context) + { + // pufff. + } +} diff --git a/src/Sylius/Bundle/FlowBundle/Tests/Process/Step/StepTest.php b/src/Sylius/Bundle/FlowBundle/Tests/Process/Step/StepTest.php new file mode 100644 index 0000000000..589370c219 --- /dev/null +++ b/src/Sylius/Bundle/FlowBundle/Tests/Process/Step/StepTest.php @@ -0,0 +1,63 @@ + + */ +class StepTest extends \PHPUnit_Framework_TestCase +{ + /** + * @test + * @covers Sylius\Bundle\FlowBundle\Process\Step\Step::isActive + */ + public function shouldByActiveByDefault() + { + $step = $this->getStep(); + + $this->assertTrue($step->isActive()); + } + + /** + * @test + * @covers Sylius\Bundle\FlowBundle\Process\Step\Step::forwardAction + */ + public function shouldCompleteProcessByDefault() + { + $processContext = $this->getMock('Sylius\Bundle\FlowBundle\Process\Context\ProcessContextInterface'); + $processContext->expects($this->once()) + ->method('complete'); + + $step = $this->getStep(); + $step->forwardAction($processContext); + } + + /** + * @test + * @covers Sylius\Bundle\FlowBundle\Process\Step\Step::setName + * @covers Sylius\Bundle\FlowBundle\Process\Step\Step::getName + */ + public function shouldSetName() + { + $step = $this->getStep(); + $step->setName('stepName'); + + $this->assertSame('stepName', $step->getName()); + } + + private function getStep() + { + return $this->getMockForAbstractClass('Sylius\Bundle\FlowBundle\Process\Step\Step'); + } +} diff --git a/src/Sylius/Bundle/FlowBundle/phpunit.xml.dist b/src/Sylius/Bundle/FlowBundle/phpunit.xml.dist index 07f432e641..e14271634c 100644 --- a/src/Sylius/Bundle/FlowBundle/phpunit.xml.dist +++ b/src/Sylius/Bundle/FlowBundle/phpunit.xml.dist @@ -12,6 +12,7 @@ ./Resources ./Tests + ./vendor