From 99c2167dd1fd890336b0d250324d353078ccf670 Mon Sep 17 00:00:00 2001 From: tienvx Date: Sun, 17 Apr 2022 22:54:48 +0700 Subject: [PATCH] Reuse start transition checking code --- src/Model/Model/Revision/Transition.php | 5 + .../Model/Revision/TransitionInterface.php | 2 + src/Service/Model/ModelHelper.php | 4 +- src/Service/Petrinet/PetrinetHelper.php | 9 +- tests/Model/Model/Revision/TransitionTest.php | 8 ++ tests/Service/Petrinet/PetrinetHelperTest.php | 108 +++++++++++++----- 6 files changed, 96 insertions(+), 40 deletions(-) diff --git a/src/Model/Model/Revision/Transition.php b/src/Model/Model/Revision/Transition.php index 4f94f15c..a0afe081 100644 --- a/src/Model/Model/Revision/Transition.php +++ b/src/Model/Model/Revision/Transition.php @@ -96,4 +96,9 @@ public function toArray(): array 'commands' => array_map(fn (CommandInterface $command) => $command->toArray(), $this->commands), ]; } + + public function isStart(): bool + { + return empty($this->fromPlaces); + } } diff --git a/src/Model/Model/Revision/TransitionInterface.php b/src/Model/Model/Revision/TransitionInterface.php index 0191cf25..6e1938e4 100644 --- a/src/Model/Model/Revision/TransitionInterface.php +++ b/src/Model/Model/Revision/TransitionInterface.php @@ -31,4 +31,6 @@ public function setToPlaces(array $toPlaces): void; public function addToPlace(int $toPlace): void; public function toArray(): array; + + public function isStart(): bool; } diff --git a/src/Service/Model/ModelHelper.php b/src/Service/Model/ModelHelper.php index 5328d6aa..7c3ca949 100644 --- a/src/Service/Model/ModelHelper.php +++ b/src/Service/Model/ModelHelper.php @@ -14,7 +14,7 @@ class ModelHelper implements ModelHelperInterface public function getStartTransitionId(RevisionInterface $revision): int { foreach ($revision->getTransitions() as $index => $transition) { - if ($transition instanceof TransitionInterface && 0 === count($transition->getFromPlaces())) { + if ($transition instanceof TransitionInterface && $transition->isStart()) { return $index; } } @@ -28,7 +28,7 @@ public function getStartTransitionId(RevisionInterface $revision): int public function getStartPlaceIds(RevisionInterface $revision): array { foreach ($revision->getTransitions() as $transition) { - if ($transition instanceof TransitionInterface && 0 === count($transition->getFromPlaces())) { + if ($transition instanceof TransitionInterface && $transition->isStart()) { return array_fill_keys($transition->getToPlaces(), 1); } } diff --git a/src/Service/Petrinet/PetrinetHelper.php b/src/Service/Petrinet/PetrinetHelper.php index a53ffe62..d84e8bd1 100644 --- a/src/Service/Petrinet/PetrinetHelper.php +++ b/src/Service/Petrinet/PetrinetHelper.php @@ -30,7 +30,7 @@ public function build(RevisionInterface $revision): PetrinetInterface $places = $this->getPlaces($revision, $builder); $transitions = $this->getTransitions($revision, $builder); foreach ($revision->getTransitions() as $index => $transition) { - if ($transition instanceof TransitionInterface && $this->isValidTransition($transition)) { + if ($transition instanceof TransitionInterface && !$transition->isStart()) { $this->connectPlacesToTransition( array_intersect_key($places, array_flip($transition->getFromPlaces())), $transitions[$index], @@ -60,7 +60,7 @@ protected function getTransitions(RevisionInterface $revision, SingleColorPetrin { $transitions = []; foreach ($revision->getTransitions() as $index => $transition) { - if ($transition instanceof TransitionInterface && $this->isValidTransition($transition)) { + if ($transition instanceof TransitionInterface && !$transition->isStart()) { $guardCallback = $transition->getGuard() ? fn (ColorInterface $color): bool => (bool) $this->expressionLanguage->evaluate( $transition->getGuard(), @@ -97,9 +97,4 @@ protected function connectTransitionToPlaces( $builder->connect($transition, $places[$toPlace], 1); } } - - protected function isValidTransition(TransitionInterface $transition): bool - { - return !empty($transition->getFromPlaces()); - } } diff --git a/tests/Model/Model/Revision/TransitionTest.php b/tests/Model/Model/Revision/TransitionTest.php index 3c6f4676..4c728355 100644 --- a/tests/Model/Model/Revision/TransitionTest.php +++ b/tests/Model/Model/Revision/TransitionTest.php @@ -49,6 +49,13 @@ protected function setUpCommands(): void $this->command2->setValue(null); } + public function testStartTransition(): void + { + $this->assertFalse($this->transition->isStart()); + $this->transition->setFromPlaces([]); + $this->assertTrue($this->transition->isStart()); + } + public function testSerialize(): void { $className = get_class($this->transition); @@ -70,6 +77,7 @@ public function testUnerialize(): void $this->assertSame(StoreCommandRunner::STORE, $transition->getCommands()[0]->getCommand()); $this->assertSame('55', $transition->getCommands()[0]->getTarget()); $this->assertSame('number', $transition->getCommands()[0]->getValue()); + $this->assertFalse($transition->isStart()); } protected function createTransition(): TransitionInterface diff --git a/tests/Service/Petrinet/PetrinetHelperTest.php b/tests/Service/Petrinet/PetrinetHelperTest.php index dcd5a934..3676c23a 100644 --- a/tests/Service/Petrinet/PetrinetHelperTest.php +++ b/tests/Service/Petrinet/PetrinetHelperTest.php @@ -2,11 +2,12 @@ namespace Tienvx\Bundle\MbtBundle\Tests\Service\Petrinet; -use Petrinet\Model\PlaceInterface; +use Petrinet\Model\ArcInterface; use PHPUnit\Framework\TestCase; use SingleColorPetrinet\Model\Color; use SingleColorPetrinet\Model\ColorfulFactory; -use SingleColorPetrinet\Model\GuardedTransitionInterface; +use SingleColorPetrinet\Model\GuardedTransition as PetrinetTransition; +use SingleColorPetrinet\Model\Place as PetrinetPlace; use Tienvx\Bundle\MbtBundle\Entity\Model\Revision; use Tienvx\Bundle\MbtBundle\Service\ExpressionLanguage; use Tienvx\Bundle\MbtBundle\Service\Petrinet\PetrinetHelper; @@ -28,45 +29,90 @@ public function testBuild(): void $factory = new ColorfulFactory(); $expressionLanguage = new ExpressionLanguage(); $helper = new PetrinetHelper($factory, $expressionLanguage); - $places = [ + + // Model revision + $revision = new Revision(); + $revision->setPlaces([ + $place0 = new Place(), $place1 = new Place(), $place2 = new Place(), - $place3 = new Place(), - ]; - $revision = new Revision(); - $revision->setPlaces($places); - $transitions = [ + ]); + $revision->setTransitions([ + $transition0 = new Transition(), $transition1 = new Transition(), $transition2 = new Transition(), - ]; + $transition3 = new Transition(), + ]); + $transition0->setFromPlaces([]); + $transition0->setToPlaces([0]); $transition1->setGuard('count > 0'); - $transition1->setFromPlaces([0, 1]); - $transition1->setToPlaces([2]); + $transition1->setFromPlaces([0]); + $transition1->setToPlaces([1, 2]); $transition2->setFromPlaces([2]); $transition2->setToPlaces([1]); - $revision->setTransitions($transitions); + $transition3->setFromPlaces([1]); + $transition3->setToPlaces([0, 2]); + + // Petrinet $petrinet = $helper->build($revision); $this->assertCount(3, $petrinet->getPlaces()); - foreach ($petrinet->getPlaces() as $place) { - $this->assertInstanceOf(PlaceInterface::class, $place); + $places = [ + 0 => [ + 'input' => [3], + 'output' => [1], + ], + 1 => [ + 'input' => [1, 2], + 'output' => [3], + ], + 2 => [ + 'input' => [1, 3], + 'output' => [2], + ], + ]; + foreach ($petrinet->getPlaces() as $index => $place) { + $this->assertInstanceOf(PetrinetPlace::class, $place); + $this->assertSame( + $places[$index]['input'], + array_map(fn (ArcInterface $arc) => $arc->getTransition()->getId(), $place->getInputArcs()->toArray()), + ); + $this->assertSame( + $places[$index]['output'], + array_map(fn (ArcInterface $arc) => $arc->getTransition()->getId(), $place->getOutputArcs()->toArray()), + ); } - $this->assertCount(0, $petrinet->getPlaces()[0]->getInputArcs()); - $this->assertCount(1, $petrinet->getPlaces()[0]->getOutputArcs()); - $this->assertCount(1, $petrinet->getPlaces()[1]->getInputArcs()); - $this->assertCount(1, $petrinet->getPlaces()[1]->getOutputArcs()); - $this->assertCount(1, $petrinet->getPlaces()[2]->getInputArcs()); - $this->assertCount(1, $petrinet->getPlaces()[2]->getOutputArcs()); - $this->assertCount(2, $petrinet->getTransitions()); - foreach ($petrinet->getTransitions() as $place) { - $this->assertInstanceOf(GuardedTransitionInterface::class, $place); + $this->assertCount(3, $petrinet->getTransitions()); + $transitions = [ + 0 => [ + 'input' => [0], + 'output' => [1, 2], + ], + 1 => [ + 'input' => [2], + 'output' => [1], + ], + 2 => [ + 'input' => [1], + 'output' => [0, 2], + ], + ]; + foreach ($petrinet->getTransitions() as $index => $transition) { + $this->assertInstanceOf(PetrinetTransition::class, $transition); + $this->assertSame( + $transitions[$index]['input'], + array_map(fn (ArcInterface $arc) => $arc->getPlace()->getId(), $transition->getInputArcs()->toArray()), + ); + $this->assertSame( + $transitions[$index]['output'], + array_map(fn (ArcInterface $arc) => $arc->getPlace()->getId(), $transition->getOutputArcs()->toArray()), + ); + if (0 === $index) { + $this->assertIsCallable($guardCallback = $transition->getGuard()); + $this->assertTrue($guardCallback(new Color(['count' => 1]))); + $this->assertFalse($guardCallback(new Color(['count' => 0]))); + } else { + $this->assertNull($transition->getGuard()); + } } - $this->assertIsCallable($guardCallback = $petrinet->getTransitions()[0]->getGuard()); - $this->assertTrue($guardCallback(new Color(['count' => 1]))); - $this->assertFalse($guardCallback(new Color(['count' => 0]))); - $this->assertNull($petrinet->getTransitions()[1]->getGuard()); - $this->assertCount(2, $petrinet->getTransitions()[0]->getInputArcs()); - $this->assertCount(1, $petrinet->getTransitions()[0]->getOutputArcs()); - $this->assertCount(1, $petrinet->getTransitions()[1]->getInputArcs()); - $this->assertCount(1, $petrinet->getTransitions()[1]->getOutputArcs()); } }