X-Git-Url: http://www.aleph1.co.uk/gitweb/?a=blobdiff_plain;f=web%2Fcore%2Fmodules%2Fworkflows%2Ftests%2Fsrc%2FUnit%2FWorkflowTest.php;fp=web%2Fcore%2Fmodules%2Fworkflows%2Ftests%2Fsrc%2FUnit%2FWorkflowTest.php;h=e2f2db7be3178c56d0a5d052a7e29556f69e6f2c;hb=a2bd1bf0c2c1f1a17d188f4dc0726a45494cefae;hp=0000000000000000000000000000000000000000;hpb=57c063afa3f66b07c4bbddc2d6129a96d90f0aad;p=yaffs-website diff --git a/web/core/modules/workflows/tests/src/Unit/WorkflowTest.php b/web/core/modules/workflows/tests/src/Unit/WorkflowTest.php new file mode 100644 index 000000000..e2f2db7be --- /dev/null +++ b/web/core/modules/workflows/tests/src/Unit/WorkflowTest.php @@ -0,0 +1,660 @@ +prophesize(WorkflowTypeInterface::class); + $workflow_type->decorateState(Argument::any())->willReturnArgument(0); + $workflow_type->decorateTransition(Argument::any())->willReturnArgument(0); + $workflow_manager = $this->prophesize(WorkflowTypeManager::class); + $workflow_manager->createInstance('test_type', Argument::any())->willReturn($workflow_type->reveal()); + $container->set('plugin.manager.workflows.type', $workflow_manager->reveal()); + \Drupal::setContainer($container); + } + + /** + * @covers ::addState + * @covers ::hasState + */ + public function testAddAndHasState() { + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $this->assertFalse($workflow->hasState('draft')); + + // By default states are ordered in the order added. + $workflow->addState('draft', 'Draft'); + $this->assertTrue($workflow->hasState('draft')); + $this->assertFalse($workflow->hasState('published')); + $this->assertEquals(0, $workflow->getState('draft')->weight()); + // Adding a state does not set up a transition to itself. + $this->assertFalse($workflow->hasTransitionFromStateToState('draft', 'draft')); + + // New states are added with a new weight 1 more than the current highest + // weight. + $workflow->addState('published', 'Published'); + $this->assertEquals(1, $workflow->getState('published')->weight()); + } + + /** + * @covers ::addState + */ + public function testAddStateException() { + $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' already exists in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->addState('draft', 'Draft'); + $workflow->addState('draft', 'Draft'); + } + + /** + * @covers ::addState + */ + public function testAddStateInvalidIdException() { + $this->setExpectedException(\InvalidArgumentException::class, "The state ID 'draft-draft' must contain only lowercase letters, numbers, and underscores"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->addState('draft-draft', 'Draft'); + } + + /** + * @covers ::getStates + */ + public function testGetStates() { + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + + // Getting states works when there are none. + $this->assertArrayEquals([], array_keys($workflow->getStates())); + $this->assertArrayEquals([], array_keys($workflow->getStates([]))); + + $workflow + ->addState('draft', 'Draft') + ->addState('published', 'Published') + ->addState('archived', 'Archived'); + + // States are stored in alphabetical key order. + $this->assertArrayEquals([ + 'archived', + 'draft', + 'published', + ], array_keys($workflow->get('states'))); + + // Ensure we're returning state objects. + $this->assertInstanceOf(State::class, $workflow->getStates()['draft']); + + // Passing in no IDs returns all states. + $this->assertArrayEquals(['draft', 'published', 'archived'], array_keys($workflow->getStates())); + + // The order of states is by weight. + $workflow->setStateWeight('published', -1); + $this->assertArrayEquals(['published', 'draft', 'archived'], array_keys($workflow->getStates())); + + // The label is also used for sorting if weights are equal. + $workflow->setStateWeight('archived', 0); + $this->assertArrayEquals(['published', 'archived', 'draft'], array_keys($workflow->getStates())); + + // You can limit the states returned by passing in states IDs. + $this->assertArrayEquals(['archived', 'draft'], array_keys($workflow->getStates(['draft', 'archived']))); + + // An empty array does not load all states. + $this->assertArrayEquals([], array_keys($workflow->getStates([]))); + } + + /** + * @covers ::getStates + */ + public function testGetStatesException() { + $this->setExpectedException(\InvalidArgumentException::class, "The state 'state_that_does_not_exist' does not exist in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->getStates(['state_that_does_not_exist']); + } + + /** + * @covers ::getState + */ + public function testGetState() { + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + // By default states are ordered in the order added. + $workflow + ->addState('draft', 'Draft') + ->addState('published', 'Published') + ->addState('archived', 'Archived') + ->addTransition('create_new_draft', 'Create new draft', ['draft'], 'draft') + ->addTransition('publish', 'Publish', ['draft'], 'published'); + + // Ensure we're returning state objects and they are set up correctly + $this->assertInstanceOf(State::class, $workflow->getState('draft')); + $this->assertEquals('archived', $workflow->getState('archived')->id()); + $this->assertEquals('Archived', $workflow->getState('archived')->label()); + + $draft = $workflow->getState('draft'); + $this->assertTrue($draft->canTransitionTo('draft')); + $this->assertTrue($draft->canTransitionTo('published')); + $this->assertFalse($draft->canTransitionTo('archived')); + $this->assertEquals('Publish', $draft->getTransitionTo('published')->label()); + $this->assertEquals(0, $draft->weight()); + $this->assertEquals(1, $workflow->getState('published')->weight()); + $this->assertEquals(2, $workflow->getState('archived')->weight()); + } + + /** + * @covers ::getState + */ + public function testGetStateException() { + $this->setExpectedException(\InvalidArgumentException::class, "The state 'state_that_does_not_exist' does not exist in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->getState('state_that_does_not_exist'); + } + + /** + * @covers ::setStateLabel + */ + public function testSetStateLabel() { + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->addState('draft', 'Draft'); + $this->assertEquals('Draft', $workflow->getState('draft')->label()); + $workflow->setStateLabel('draft', 'Unpublished'); + $this->assertEquals('Unpublished', $workflow->getState('draft')->label()); + } + + /** + * @covers ::setStateLabel + */ + public function testSetStateLabelException() { + $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' does not exist in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->setStateLabel('draft', 'Draft'); + } + + /** + * @covers ::setStateWeight + */ + public function testSetStateWeight() { + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->addState('draft', 'Draft'); + $this->assertEquals(0, $workflow->getState('draft')->weight()); + $workflow->setStateWeight('draft', -10); + $this->assertEquals(-10, $workflow->getState('draft')->weight()); + } + + /** + * @covers ::setStateWeight + */ + public function testSetStateWeightException() { + $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' does not exist in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->setStateWeight('draft', 10); + } + + /** + * @covers ::deleteState + */ + public function testDeleteState() { + // Create a container so that the plugin manager and workflow type can be + // mocked and test that + // \Drupal\workflows\WorkflowTypeInterface::deleteState() is called + // correctly. + $container = new ContainerBuilder(); + $workflow_type = $this->prophesize(WorkflowTypeInterface::class); + $workflow_type->decorateState(Argument::any())->willReturnArgument(0); + $workflow_type->decorateTransition(Argument::any())->willReturnArgument(0); + $workflow_type->deleteState('draft')->shouldBeCalled(); + $workflow_type->deleteTransition('create_new_draft')->shouldBeCalled(); + $workflow_manager = $this->prophesize(WorkflowTypeManager::class); + $workflow_manager->createInstance('test_type', Argument::any())->willReturn($workflow_type->reveal()); + $container->set('plugin.manager.workflows.type', $workflow_manager->reveal()); + \Drupal::setContainer($container); + + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow + ->addState('draft', 'Draft') + ->addState('published', 'Published') + ->addTransition('publish', 'Publish', ['draft', 'published'], 'published') + ->addTransition('create_new_draft', 'Create new draft', ['draft', 'published'], 'draft'); + $this->assertCount(2, $workflow->getStates()); + $this->assertCount(2, $workflow->getState('published')->getTransitions()); + $workflow->deleteState('draft'); + $this->assertFalse($workflow->hasState('draft')); + $this->assertCount(1, $workflow->getStates()); + $this->assertCount(1, $workflow->getState('published')->getTransitions()); + } + + /** + * @covers ::deleteState + */ + public function testDeleteStateException() { + $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' does not exist in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->deleteState('draft'); + } + + /** + * @covers ::deleteState + */ + public function testDeleteOnlyStateException() { + $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' can not be deleted from workflow 'test' as it is the only state"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->addState('draft', 'Draft'); + $workflow->deleteState('draft'); + } + + /** + * @covers ::addTransition + * @covers ::hasTransition + */ + public function testAddTransition() { + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + + // By default states are ordered in the order added. + $workflow + ->addState('draft', 'Draft') + ->addState('published', 'Published'); + + $this->assertFalse($workflow->getState('draft')->canTransitionTo('published')); + $workflow->addTransition('publish', 'Publish', ['draft'], 'published'); + $this->assertTrue($workflow->getState('draft')->canTransitionTo('published')); + $this->assertEquals(0, $workflow->getTransition('publish')->weight()); + $this->assertTrue($workflow->hasTransition('publish')); + $this->assertFalse($workflow->hasTransition('draft')); + + $workflow->addTransition('save_publish', 'Save', ['published'], 'published'); + $this->assertEquals(1, $workflow->getTransition('save_publish')->weight()); + } + + /** + * @covers ::addTransition + */ + public function testAddTransitionDuplicateException() { + $this->setExpectedException(\InvalidArgumentException::class, "The transition 'publish' already exists in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->addState('published', 'Published'); + $workflow->addTransition('publish', 'Publish', ['published'], 'published'); + $workflow->addTransition('publish', 'Publish', ['published'], 'published'); + } + + /** + * @covers ::addTransition + */ + public function testAddTransitionInvalidIdException() { + $this->setExpectedException(\InvalidArgumentException::class, "The transition ID 'publish-publish' must contain only lowercase letters, numbers, and underscores"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->addState('published', 'Published'); + $workflow->addTransition('publish-publish', 'Publish', ['published'], 'published'); + } + + /** + * @covers ::addTransition + */ + public function testAddTransitionMissingFromException() { + $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' does not exist in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->addState('published', 'Published'); + $workflow->addTransition('publish', 'Publish', ['draft'], 'published'); + } + + /** + * @covers ::addTransition + */ + public function testAddTransitionDuplicateTransitionStatesException() { + $this->setExpectedException(\InvalidArgumentException::class, "The 'publish' transition already allows 'draft' to 'published' transitions in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow + ->addState('draft', 'Draft') + ->addState('published', 'Published'); + $workflow->addTransition('publish', 'Publish', ['draft', 'published'], 'published'); + $workflow->addTransition('draft_to_published', 'Publish a draft', ['draft'], 'published'); + } + + /** + * @covers ::addTransition + */ + public function testAddTransitionConsistentAfterFromCatch() { + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->addState('published', 'Published'); + try { + $workflow->addTransition('publish', 'Publish', ['draft'], 'published'); + } + catch (\InvalidArgumentException $e) { + } + // Ensure that the workflow is not left in an inconsistent state after an + // exception is thrown from Workflow::setTransitionFromStates() whilst + // calling Workflow::addTransition(). + $this->assertFalse($workflow->hasTransition('publish')); + } + + /** + * @covers ::addTransition + */ + public function testAddTransitionMissingToException() { + $this->setExpectedException(\InvalidArgumentException::class, "The state 'published' does not exist in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->addState('draft', 'Draft'); + $workflow->addTransition('publish', 'Publish', ['draft'], 'published'); + } + + /** + * @covers ::getTransitions + * @covers ::setTransitionWeight + */ + public function testGetTransitions() { + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + + // Getting transitions works when there are none. + $this->assertArrayEquals([], array_keys($workflow->getTransitions())); + $this->assertArrayEquals([], array_keys($workflow->getTransitions([]))); + + // By default states are ordered in the order added. + $workflow + ->addState('a', 'A') + ->addState('b', 'B') + ->addTransition('a_b', 'A to B', ['a'], 'b') + ->addTransition('a_a', 'A to A', ['a'], 'a'); + + // Transitions are stored in alphabetical key order in configuration. + $this->assertArrayEquals(['a_a', 'a_b'], array_keys($workflow->get('transitions'))); + + // Ensure we're returning transition objects. + $this->assertInstanceOf(Transition::class, $workflow->getTransitions()['a_a']); + + // Passing in no IDs returns all transitions. + $this->assertArrayEquals(['a_b', 'a_a'], array_keys($workflow->getTransitions())); + + // The order of states is by weight. + $workflow->setTransitionWeight('a_a', -1); + $this->assertArrayEquals(['a_a', 'a_b'], array_keys($workflow->getTransitions())); + + // If all weights are equal it will fallback to labels. + $workflow->setTransitionWeight('a_a', 0); + $this->assertArrayEquals(['a_a', 'a_b'], array_keys($workflow->getTransitions())); + $workflow->setTransitionLabel('a_b', 'A B'); + $this->assertArrayEquals(['a_b', 'a_a'], array_keys($workflow->getTransitions())); + + // You can limit the states returned by passing in states IDs. + $this->assertArrayEquals(['a_a'], array_keys($workflow->getTransitions(['a_a']))); + + // An empty array does not load all states. + $this->assertArrayEquals([], array_keys($workflow->getTransitions([]))); + } + + + /** + * @covers ::getTransition + */ + public function testGetTransition() { + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + // By default states are ordered in the order added. + $workflow + ->addState('draft', 'Draft') + ->addState('published', 'Published') + ->addState('archived', 'Archived') + ->addTransition('create_new_draft', 'Create new draft', ['draft'], 'draft') + ->addTransition('publish', 'Publish', ['draft'], 'published'); + + // Ensure we're returning state objects and they are set up correctly + $this->assertInstanceOf(Transition::class, $workflow->getTransition('create_new_draft')); + $this->assertEquals('publish', $workflow->getTransition('publish')->id()); + $this->assertEquals('Publish', $workflow->getTransition('publish')->label()); + + $transition = $workflow->getTransition('publish'); + $this->assertEquals($workflow->getState('draft'), $transition->from()['draft']); + $this->assertEquals($workflow->getState('published'), $transition->to()); + } + + /** + * @covers ::getTransition + */ + public function testGetTransitionException() { + $this->setExpectedException(\InvalidArgumentException::class, "The transition 'transition_that_does_not_exist' does not exist in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->getTransition('transition_that_does_not_exist'); + } + + /** + * @covers ::getTransitionsForState + */ + public function testGetTransitionsForState() { + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + // By default states are ordered in the order added. + $workflow + ->addState('draft', 'Draft') + ->addState('published', 'Published') + ->addState('archived', 'Archived') + ->addTransition('create_new_draft', 'Create new draft', ['archived', 'draft'], 'draft') + ->addTransition('publish', 'Publish', ['draft', 'published'], 'published') + ->addTransition('archive', 'Archive', ['published'], 'archived'); + + $this->assertEquals(['create_new_draft', 'publish'], array_keys($workflow->getTransitionsForState('draft'))); + $this->assertEquals(['create_new_draft'], array_keys($workflow->getTransitionsForState('draft', 'to'))); + $this->assertEquals(['publish', 'archive'], array_keys($workflow->getTransitionsForState('published'))); + $this->assertEquals(['publish'], array_keys($workflow->getTransitionsForState('published', 'to'))); + $this->assertEquals(['create_new_draft'], array_keys($workflow->getTransitionsForState('archived', 'from'))); + $this->assertEquals(['archive'], array_keys($workflow->getTransitionsForState('archived', 'to'))); + } + + + /** + * @covers ::getTransitionFromStateToState + * @covers ::hasTransitionFromStateToState + */ + public function testGetTransitionFromStateToState() { + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + // By default states are ordered in the order added. + $workflow + ->addState('draft', 'Draft') + ->addState('published', 'Published') + ->addState('archived', 'Archived') + ->addTransition('create_new_draft', 'Create new draft', ['archived', 'draft'], 'draft') + ->addTransition('publish', 'Publish', ['draft', 'published'], 'published') + ->addTransition('archive', 'Archive', ['published'], 'archived'); + + $this->assertTrue($workflow->hasTransitionFromStateToState('draft', 'published')); + $this->assertFalse($workflow->hasTransitionFromStateToState('archived', 'archived')); + $transition = $workflow->getTransitionFromStateToState('published', 'archived'); + $this->assertEquals('Archive', $transition->label()); + } + + /** + * @covers ::getTransitionFromStateToState + */ + public function testGetTransitionFromStateToStateException() { + $this->setExpectedException(\InvalidArgumentException::class, "The transition from 'archived' to 'archived' does not exist in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + // By default states are ordered in the order added. + $workflow + ->addState('draft', 'Draft') + ->addState('published', 'Published') + ->addState('archived', 'Archived') + ->addTransition('create_new_draft', 'Create new draft', ['archived', 'draft'], 'draft') + ->addTransition('publish', 'Publish', ['draft', 'published'], 'published') + ->addTransition('archive', 'Archive', ['published'], 'archived'); + + $workflow->getTransitionFromStateToState('archived', 'archived'); + } + + /** + * @covers ::setTransitionLabel + */ + public function testSetTransitionLabel() { + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow + ->addState('draft', 'Draft') + ->addState('published', 'Published') + ->addTransition('publish', 'Publish', ['draft'], 'published'); + $this->assertEquals('Publish', $workflow->getTransition('publish')->label()); + $workflow->setTransitionLabel('publish', 'Publish!'); + $this->assertEquals('Publish!', $workflow->getTransition('publish')->label()); + } + + /** + * @covers ::setTransitionLabel + */ + public function testSetTransitionLabelException() { + $this->setExpectedException(\InvalidArgumentException::class, "The transition 'draft-published' does not exist in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->addState('published', 'Published'); + $workflow->setTransitionLabel('draft-published', 'Publish'); + } + + /** + * @covers ::setTransitionWeight + */ + public function testSetTransitionWeight() { + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow + ->addState('draft', 'Draft') + ->addState('published', 'Published') + ->addTransition('publish', 'Publish', ['draft'], 'published'); + $this->assertEquals(0, $workflow->getTransition('publish')->weight()); + $workflow->setTransitionWeight('publish', 10); + $this->assertEquals(10, $workflow->getTransition('publish')->weight()); + } + + /** + * @covers ::setTransitionWeight + */ + public function testSetTransitionWeightException() { + $this->setExpectedException(\InvalidArgumentException::class, "The transition 'draft-published' does not exist in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->addState('published', 'Published'); + $workflow->setTransitionWeight('draft-published', 10); + } + + /** + * @covers ::setTransitionFromStates + */ + public function testSetTransitionFromStates() { + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow + ->addState('draft', 'Draft') + ->addState('published', 'Published') + ->addState('archived', 'Archived') + ->addTransition('test', 'Test', ['draft'], 'draft'); + + $this->assertTrue($workflow->hasTransitionFromStateToState('draft', 'draft')); + $this->assertFalse($workflow->hasTransitionFromStateToState('published', 'draft')); + $this->assertFalse($workflow->hasTransitionFromStateToState('archived', 'draft')); + $workflow->setTransitionFromStates('test', ['draft', 'published', 'archived']); + $this->assertTrue($workflow->hasTransitionFromStateToState('draft', 'draft')); + $this->assertTrue($workflow->hasTransitionFromStateToState('published', 'draft')); + $this->assertTrue($workflow->hasTransitionFromStateToState('archived', 'draft')); + $workflow->setTransitionFromStates('test', ['published', 'archived']); + $this->assertFalse($workflow->hasTransitionFromStateToState('draft', 'draft')); + $this->assertTrue($workflow->hasTransitionFromStateToState('published', 'draft')); + $this->assertTrue($workflow->hasTransitionFromStateToState('archived', 'draft')); + } + + /** + * @covers ::setTransitionFromStates + */ + public function testSetTransitionFromStatesMissingTransition() { + $this->setExpectedException(\InvalidArgumentException::class, "The transition 'test' does not exist in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow + ->addState('draft', 'Draft') + ->addState('published', 'Published') + ->addState('archived', 'Archived') + ->addTransition('create_new_draft', 'Create new draft', ['draft'], 'draft'); + + $workflow->setTransitionFromStates('test', ['draft', 'published', 'archived']); + } + + /** + * @covers ::setTransitionFromStates + */ + public function testSetTransitionFromStatesMissingState() { + $this->setExpectedException(\InvalidArgumentException::class, "The state 'published' does not exist in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow + ->addState('draft', 'Draft') + ->addState('archived', 'Archived') + ->addTransition('create_new_draft', 'Create new draft', ['draft'], 'draft'); + + $workflow->setTransitionFromStates('create_new_draft', ['draft', 'published', 'archived']); + } + + /** + * @covers ::setTransitionFromStates + */ + public function testSetTransitionFromStatesAlreadyExists() { + $this->setExpectedException(\InvalidArgumentException::class, "The 'create_new_draft' transition already allows 'draft' to 'draft' transitions in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow + ->addState('draft', 'Draft') + ->addState('archived', 'Archived') + ->addState('needs_review', 'Needs Review') + ->addTransition('create_new_draft', 'Create new draft', ['draft'], 'draft') + ->addTransition('needs_review', 'Needs review', ['needs_review'], 'draft'); + + $workflow->setTransitionFromStates('needs_review', ['draft']); + } + + /** + * @covers ::deleteTransition + */ + public function testDeleteTransition() { + // Create a container so that the plugin manager and workflow type can be + // mocked and test that + // \Drupal\workflows\WorkflowTypeInterface::deleteState() is called + // correctly. + $container = new ContainerBuilder(); + $workflow_type = $this->prophesize(WorkflowTypeInterface::class); + $workflow_type->decorateState(Argument::any())->willReturnArgument(0); + $workflow_type->decorateTransition(Argument::any())->willReturnArgument(0); + $workflow_type->deleteTransition('publish')->shouldBeCalled(); + $workflow_manager = $this->prophesize(WorkflowTypeManager::class); + $workflow_manager->createInstance('test_type', Argument::any())->willReturn($workflow_type->reveal()); + $container->set('plugin.manager.workflows.type', $workflow_manager->reveal()); + \Drupal::setContainer($container); + + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow + ->addState('draft', 'Draft') + ->addState('published', 'Published') + ->addTransition('create_new_draft', 'Create new draft', ['draft'], 'draft') + ->addTransition('publish', 'Publish', ['draft'], 'published'); + $this->assertTrue($workflow->getState('draft')->canTransitionTo('published')); + $workflow->deleteTransition('publish'); + $this->assertFalse($workflow->getState('draft')->canTransitionTo('published')); + $this->assertTrue($workflow->getState('draft')->canTransitionTo('draft')); + } + + /** + * @covers ::deleteTransition + */ + public function testDeleteTransitionException() { + $this->setExpectedException(\InvalidArgumentException::class, "The transition 'draft-published' does not exist in workflow 'test'"); + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $workflow->addState('published', 'Published'); + $workflow->deleteTransition('draft-published'); + } + + /** + * @covers ::status + */ + public function testStatus() { + $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow'); + $this->assertFalse($workflow->status()); + $workflow->addState('published', 'Published'); + $this->assertTrue($workflow->status()); + } + +}