Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b06fce1

Browse files
committed
[Workflow] Fix Marking when it must contains more than one tokens
1 parent 7dae80d commit b06fce1

File tree

4 files changed

+191
-22
lines changed

4 files changed

+191
-22
lines changed

src/Symfony/Component/Workflow/Marking.php

+29-6
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,46 @@ class Marking
2727
public function __construct(array $representation = [])
2828
{
2929
foreach ($representation as $place => $nbToken) {
30-
$this->mark($place);
30+
$this->mark($place, $nbToken);
3131
}
3232
}
3333

34-
public function mark(string $place)
34+
public function mark(string $place, int $nbToken = 1)
3535
{
36-
$this->places[$place] = 1;
36+
if ($nbToken < 1) {
37+
throw new \LogicException(sprintf('The number of tokens must be greater than 0, "%s" given.', $nbToken));
38+
}
39+
40+
if (!\array_key_exists($place, $this->places)) {
41+
$this->places[$place] = 0;
42+
}
43+
$this->places[$place] += $nbToken;
3744
}
3845

39-
public function unmark(string $place)
46+
public function unmark(string $place, int $nbToken = 1)
4047
{
41-
unset($this->places[$place]);
48+
if ($nbToken < 1) {
49+
throw new \LogicException(sprintf('The number of tokens must be greater than 0, "%s" given.', $nbToken));
50+
}
51+
52+
if (!$this->has($place)) {
53+
throw new \LogicException(sprintf('The place "%s" is not marked.', $place));
54+
}
55+
56+
$this->places[$place] -= $nbToken;
57+
58+
if (0 > $this->places[$place]) {
59+
throw new \LogicException(sprintf('The place "%s" could not contain a negative token number.', $place));
60+
}
61+
62+
if (0 === $this->places[$place]) {
63+
unset($this->places[$place]);
64+
}
4265
}
4366

4467
public function has(string $place)
4568
{
46-
return isset($this->places[$place]);
69+
return \array_key_exists($place, $this->places);
4770
}
4871

4972
public function getPlaces()

src/Symfony/Component/Workflow/Tests/MarkingTest.php

+50-4
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,70 @@ public function testMarking()
2222

2323
$this->assertTrue($marking->has('a'));
2424
$this->assertFalse($marking->has('b'));
25-
$this->assertSame(['a' => 1], $marking->getPlaces());
25+
$this->assertPlaces(['a' => 1], $marking);
2626

2727
$marking->mark('b');
2828

2929
$this->assertTrue($marking->has('a'));
3030
$this->assertTrue($marking->has('b'));
31-
$this->assertSame(['a' => 1, 'b' => 1], $marking->getPlaces());
31+
$this->assertPlaces(['a' => 1, 'b' => 1], $marking);
3232

3333
$marking->unmark('a');
3434

3535
$this->assertFalse($marking->has('a'));
3636
$this->assertTrue($marking->has('b'));
37-
$this->assertSame(['b' => 1], $marking->getPlaces());
37+
$this->assertPlaces(['b' => 1], $marking);
3838

3939
$marking->unmark('b');
4040

4141
$this->assertFalse($marking->has('a'));
4242
$this->assertFalse($marking->has('b'));
43-
$this->assertSame([], $marking->getPlaces());
43+
$this->assertPlaces([], $marking);
44+
45+
$marking->mark('a');
46+
$this->assertPlaces(['a' => 1], $marking);
47+
48+
$marking->mark('a');
49+
$this->assertPlaces(['a' => 2], $marking);
50+
51+
$marking->unmark('a');
52+
$this->assertPlaces(['a' => 1], $marking);
53+
54+
$marking->unmark('a');
55+
$this->assertPlaces([], $marking);
56+
}
57+
58+
public function testGuardNotMarked()
59+
{
60+
$marking = new Marking([]);
61+
62+
$this->expectException(\LogicException::class);
63+
$this->expectExceptionMessage('The place "a" is not marked.');
64+
$marking->unmark('a');
65+
}
66+
67+
public function testGuardNotNbTokenLowerThanZero()
68+
{
69+
$marking = new Marking(['a' => 1]);
70+
71+
$this->expectException(\LogicException::class);
72+
$this->expectExceptionMessage('The place "a" could not contain a negative token number.');
73+
$marking->unmark('a', 2);
74+
}
75+
76+
public function testGuardNotNbTokenEquals0()
77+
{
78+
$marking = new Marking(['a' => 1]);
79+
80+
$this->expectException(\LogicException::class);
81+
$this->expectExceptionMessage('The number of tokens must be greater than 0, "0" given.');
82+
$marking->unmark('a', 0);
83+
}
84+
85+
private function assertPlaces(array $expected, Marking $marking)
86+
{
87+
$places = $marking->getPlaces();
88+
ksort($places);
89+
$this->assertSame($expected, $places);
4490
}
4591
}

src/Symfony/Component/Workflow/Tests/WorkflowBuilderTrait.php

+39
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,43 @@ private static function createComplexStateMachineDefinition()
158158
// | d | -------------+
159159
// +-----+
160160
}
161+
162+
private static function createWorkflowWithSameNameBackTransition(): Definition
163+
{
164+
$places = range('a', 'c');
165+
166+
$transitions = [];
167+
$transitions[] = new Transition('a_to_bc', 'a', ['b', 'c']);
168+
$transitions[] = new Transition('back1', 'b', 'a');
169+
$transitions[] = new Transition('back1', 'c', 'b');
170+
$transitions[] = new Transition('back2', 'c', 'b');
171+
$transitions[] = new Transition('back2', 'b', 'a');
172+
$transitions[] = new Transition('c_to_cb', 'c', ['b', 'c']);
173+
174+
return new Definition($places, $transitions);
175+
176+
// The graph looks like:
177+
// +-----------------------------------------------------------------+
178+
// | |
179+
// | |
180+
// | +---------------------------------------------+ |
181+
// v | v |
182+
// +---+ +---------+ +-------+ +---------+ +---+ +-------+
183+
// | a | --> | a_to_bc | --> | | --> | back2 | --> | | --> | back2 |
184+
// +---+ +---------+ | | +---------+ | | +-------+
185+
// ^ | | | |
186+
// | | c | <-----+ | b |
187+
// | | | | | |
188+
// | | | +---------+ | | +-------+
189+
// | | | --> | c_to_cb | --> | | --> | back1 |
190+
// | +-------+ +---------+ +---+ +-------+
191+
// | | ^ |
192+
// | | | |
193+
// | v | |
194+
// | +-------+ | |
195+
// | | back1 | ----------------------+ |
196+
// | +-------+ |
197+
// | |
198+
// +-----------------------------------------------------------------+
199+
}
161200
}

src/Symfony/Component/Workflow/Tests/WorkflowTest.php

+73-12
Original file line numberDiff line numberDiff line change
@@ -330,28 +330,32 @@ public function testApplyWithSameNameTransition()
330330

331331
$marking = $workflow->apply($subject, 'a_to_bc');
332332

333-
$this->assertFalse($marking->has('a'));
334-
$this->assertTrue($marking->has('b'));
335-
$this->assertTrue($marking->has('c'));
333+
$this->assertPlaces([
334+
'b' => 1,
335+
'c' => 1,
336+
], $marking);
336337

337338
$marking = $workflow->apply($subject, 'to_a');
338339

339-
$this->assertTrue($marking->has('a'));
340-
$this->assertFalse($marking->has('b'));
341-
$this->assertFalse($marking->has('c'));
340+
// Two tokens in "a"
341+
$this->assertPlaces([
342+
'a' => 2,
343+
], $marking);
342344

343345
$workflow->apply($subject, 'a_to_bc');
344346
$marking = $workflow->apply($subject, 'b_to_c');
345347

346-
$this->assertFalse($marking->has('a'));
347-
$this->assertFalse($marking->has('b'));
348-
$this->assertTrue($marking->has('c'));
348+
$this->assertPlaces([
349+
'a' => 1,
350+
'c' => 2,
351+
], $marking);
349352

350353
$marking = $workflow->apply($subject, 'to_a');
351354

352-
$this->assertTrue($marking->has('a'));
353-
$this->assertFalse($marking->has('b'));
354-
$this->assertFalse($marking->has('c'));
355+
$this->assertPlaces([
356+
'a' => 2,
357+
'c' => 1,
358+
], $marking);
355359
}
356360

357361
public function testApplyWithSameNameTransition2()
@@ -785,6 +789,63 @@ public function testGetEnabledTransitionsWithSameNameTransition()
785789
$this->assertSame('to_a', $transitions[1]->getName());
786790
$this->assertSame('to_a', $transitions[2]->getName());
787791
}
792+
793+
/**
794+
* @@testWith ["back1"]
795+
* ["back2"]
796+
*/
797+
public function testApplyWithSameNameBackTransition(string $transition)
798+
{
799+
$definition = $this->createWorkflowWithSameNameBackTransition();
800+
$workflow = new Workflow($definition, new MethodMarkingStore());
801+
802+
$subject = new Subject();
803+
804+
$marking = $workflow->apply($subject, 'a_to_bc');
805+
$this->assertPlaces([
806+
'b' => 1,
807+
'c' => 1,
808+
], $marking);
809+
810+
$marking = $workflow->apply($subject, $transition);
811+
$this->assertPlaces([
812+
'a' => 1,
813+
'b' => 1,
814+
], $marking);
815+
816+
$marking = $workflow->apply($subject, $transition);
817+
$this->assertPlaces([
818+
'a' => 2,
819+
], $marking);
820+
821+
$marking = $workflow->apply($subject, 'a_to_bc');
822+
$this->assertPlaces([
823+
'a' => 1,
824+
'b' => 1,
825+
'c' => 1,
826+
], $marking);
827+
828+
$marking = $workflow->apply($subject, 'c_to_cb');
829+
$this->assertPlaces([
830+
'a' => 1,
831+
'b' => 2,
832+
'c' => 1,
833+
], $marking);
834+
835+
$marking = $workflow->apply($subject, 'c_to_cb');
836+
$this->assertPlaces([
837+
'a' => 1,
838+
'b' => 3,
839+
'c' => 1,
840+
], $marking);
841+
}
842+
843+
private function assertPlaces(array $expected, Marking $marking)
844+
{
845+
$places = $marking->getPlaces();
846+
ksort($places);
847+
$this->assertSame($expected, $places);
848+
}
788849
}
789850

790851
class EventDispatcherMock implements \Symfony\Contracts\EventDispatcher\EventDispatcherInterface

0 commit comments

Comments
 (0)