From 000a7689ae74a0f9a9fec570a256aa97f5d62662 Mon Sep 17 00:00:00 2001 From: Yannick Voyer Date: Sat, 13 Dec 2025 22:18:15 -0500 Subject: [PATCH 1/3] Upgrade base support to php >=8.2 --- .github/workflows/php.yml | 5 +-- composer.json | 12 +++--- examples/ContextUsingBuilderTest.php | 5 --- examples/DoctrineMappedContextTest.php | 46 +++++++-------------- phpcs.xml.dist | 1 + src/Builder/StateBuilder.php | 29 +++++++++---- src/Callbacks/BufferStateChanges.php | 35 ++++++++++++++++ src/Event/StateEventStore.php | 16 ++++--- src/Event/TransitionWasRequested.php | 5 --- src/Event/TransitionWasSuccessful.php | 5 --- src/InvalidStateTransitionException.php | 5 --- src/NotFoundException.php | 5 --- src/Port/Symfony/EventDispatcherAdapter.php | 3 +- src/StateMachine.php | 5 --- src/StateTransition.php | 5 --- src/TransitionRegistry.php | 22 +++++----- src/Visitor/AttributeDumper.php | 14 +++---- tests/StateBuilderTest.php | 27 ++++++++++++ tests/StateMachineTest.php | 41 ++++++++++++++---- tests/TestContext.php | 5 --- tests/TransitionRegistryTest.php | 27 +++++++++--- tests/Visitor/AttributeDumperTest.php | 32 ++++++++++---- 22 files changed, 213 insertions(+), 137 deletions(-) create mode 100644 src/Callbacks/BufferStateChanges.php diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index f363898..5716288 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5'] + php-versions: ['8.2', '8.3', '8.4', '8.5'] steps: - uses: actions/checkout@v2 @@ -45,6 +45,3 @@ jobs: - name: Composer validate run: composer validate - - # - name: Infection -# run: bin/infection --formatter=progress diff --git a/composer.json b/composer.json index fda8381..82ecea5 100644 --- a/composer.json +++ b/composer.json @@ -20,20 +20,20 @@ } }, "require": { - "php": ">=7.4|^8.0", + "php": ">=8.2", "webmozart/assert": "^1.0", - "symfony/event-dispatcher": "^4.0|^5.0|^6.0|^7.0" + "symfony/event-dispatcher": ">=7.0" }, "require-dev": { "ext-pdo": "*", - "doctrine/annotations": "^1.13", - "doctrine/orm": "^2.5", + "doctrine/orm": ">=2.5", "infection/infection": "~0.13", "phpstan/phpstan": "^2.0", "phpstan/phpstan-phpunit": "^2.0", - "phpunit/phpunit": "^10.0|^11.0|^12.0", + "phpunit/phpunit": "^12.0", "squizlabs/php_codesniffer": "^3.2", - "symfony/cache": "^4.0|^5.0|^6.0" + "symfony/cache": ">=7.0", + "symfony/var-exporter": "^7.0" }, "config": { "bin-dir": "bin", diff --git a/examples/ContextUsingBuilderTest.php b/examples/ContextUsingBuilderTest.php index 848ebbc..1951dd7 100644 --- a/examples/ContextUsingBuilderTest.php +++ b/examples/ContextUsingBuilderTest.php @@ -1,9 +1,4 @@ markTestSkipped('Sqlite extension is needed'); } - $configuration = Setup::createAnnotationMetadataConfiguration([__DIR__], true); - $this->em = EntityManager::create( + $configuration = ORMSetup::createAttributeMetadataConfiguration([__DIR__], true); + $connection = DriverManager::getConnection( [ 'driver' => 'pdo_sqlite', 'in_memory' => true, ], - $configuration + $configuration, ); + $this->em = new EntityManager($connection, $configuration); $tool = new SchemaTool($this->em); $tool->createSchema([$this->em->getClassMetadata(MyEntity::class)]); } @@ -82,24 +79,16 @@ private function save(MyEntity $entity): MyEntity } } -/** - * @Entity() - */ +#[ORM\Entity] class MyEntity { - /** - * @var int - * @Id() - * @GeneratedValue(strategy="AUTO") - * @Column(name="id", type="integer") - */ + #[ORM\Id()] + #[ORM\GeneratedValue(strategy: "AUTO")] + #[ORM\Column(name: "id", type: "integer")] public int $id; - /** - * @var MyState|StateMetadata - * @Embedded(class="MyState", columnPrefix="my_") - */ - private $state; + #[ORM\Embedded(class: "MyState", columnPrefix: "my_")] + private MyState $state; public function __construct() { @@ -122,15 +111,10 @@ public function unlock(): void } } -/** - * @Embeddable() - */ +#[ORM\Embeddable] final class MyState extends StateMetadata { - /** - * @var string - * @Column(name="state", type="string") - */ + #[ORM\Column(name: "state", type: "string")] protected string $current; public function __construct() diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 63df743..6dc3d51 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -2,6 +2,7 @@ + src examples diff --git a/src/Builder/StateBuilder.php b/src/Builder/StateBuilder.php index 3033e4a..3c0cd46 100644 --- a/src/Builder/StateBuilder.php +++ b/src/Builder/StateBuilder.php @@ -5,10 +5,12 @@ use Star\Component\State\EventRegistry; use Star\Component\State\Port\Symfony\EventDispatcherAdapter; use Star\Component\State\StateMachine; +use Star\Component\State\StateRegistry; use Star\Component\State\StateTransition; use Star\Component\State\TransitionRegistry; use Star\Component\State\Transitions\ManyToOneTransition; use Star\Component\State\Transitions\OneToOneTransition; +use function is_array; /** * Tool to build the StateMachine. @@ -18,10 +20,19 @@ final class StateBuilder private TransitionRegistry $registry; private EventRegistry $listeners; - public function __construct() - { - $this->registry = new TransitionRegistry(); - $this->listeners = new EventDispatcherAdapter(); + public function __construct( + ?StateRegistry $registry = null, + ?EventRegistry $listeners = null, + ) { + if (!$registry) { + $registry = new TransitionRegistry(); + } + $this->registry = $registry; + + if (!$listeners) { + $listeners = new EventDispatcherAdapter(); + } + $this->listeners = $listeners; } /** @@ -33,7 +44,7 @@ public function __construct() */ public function allowTransition(string $name, $from, string $to): StateBuilder { - if (\is_array($from)) { + if (is_array($from)) { $transition = new ManyToOneTransition($name, $to, ...$from); } else { $transition = new OneToOneTransition($name, $from, $to); @@ -73,8 +84,10 @@ public function create(string $currentState): StateMachine return new StateMachine($currentState, $this->registry, $this->listeners); } - public static function build(): StateBuilder - { - return new static(); + public static function build( + ?StateRegistry $registry = null, + ?EventRegistry $listeners = null, + ): StateBuilder { + return new self($registry, $listeners); } } diff --git a/src/Callbacks/BufferStateChanges.php b/src/Callbacks/BufferStateChanges.php new file mode 100644 index 0000000..379ac0f --- /dev/null +++ b/src/Callbacks/BufferStateChanges.php @@ -0,0 +1,35 @@ +buffer[$context][] = __FUNCTION__; + } + + public function afterStateChange($context, StateMachine $machine): void + { + $this->buffer[$context][] = __FUNCTION__; + } + + public function onFailure(InvalidStateTransitionException $exception, $context, StateMachine $machine): string + { + throw new RuntimeException(__METHOD__ . ' is not implemented yet.'); + } + + public function flushBuffer(): array + { + return $this->buffer; + } +} diff --git a/src/Event/StateEventStore.php b/src/Event/StateEventStore.php index 197b5db..c9994e2 100644 --- a/src/Event/StateEventStore.php +++ b/src/Event/StateEventStore.php @@ -1,12 +1,9 @@ self::BEFORE_TRANSITION, + TransitionWasSuccessful::class => self::AFTER_TRANSITION, + TransitionWasFailed::class => self::FAILURE_TRANSITION, + }; + } } diff --git a/src/Event/TransitionWasRequested.php b/src/Event/TransitionWasRequested.php index 06c62f0..9b93983 100644 --- a/src/Event/TransitionWasRequested.php +++ b/src/Event/TransitionWasRequested.php @@ -1,9 +1,4 @@ dispatcher->dispatch($event); + $this->dispatcher->dispatch($event, StateEventStore::eventNameFromClass($event)); } public function addListener(string $event, callable $listener): void diff --git a/src/StateMachine.php b/src/StateMachine.php index 16748c3..c71784b 100644 --- a/src/StateMachine.php +++ b/src/StateMachine.php @@ -1,9 +1,4 @@ hasState($state)) { - $attributes = \array_merge($this->states[$state], $attributes); + $attributes = array_merge($this->states[$state], $attributes); } - $this->states[$state] = \array_unique($attributes); + $this->states[$state] = array_unique($attributes); } /** @@ -74,7 +74,7 @@ public function addAttribute(string $state, string $attribute): void */ private function addAttributes(string $state, array $attributes): void { - \array_map( + array_map( function ($attribute) use ($state) { $this->addAttribute($state, $attribute); }, @@ -89,7 +89,7 @@ public function transitionStartsFrom(string $transition, string $state): bool $from = $this->transitions[$transition]['from']; } - return \in_array($state, $from, true); // @phpstan-ignore-line + return in_array($state, $from, true); // @phpstan-ignore-line } public function hasAttribute(string $state, string $attribute): bool @@ -98,12 +98,12 @@ public function hasAttribute(string $state, string $attribute): bool return false; } - return \in_array($attribute, $this->states[$state]); + return in_array($attribute, $this->states[$state]); } public function hasState(string $name): bool { - return \array_key_exists($name, $this->states); + return array_key_exists($name, $this->states); } public function acceptTransitionVisitor(TransitionVisitor $visitor): void diff --git a/src/Visitor/AttributeDumper.php b/src/Visitor/AttributeDumper.php index 9d237dc..53f212b 100644 --- a/src/Visitor/AttributeDumper.php +++ b/src/Visitor/AttributeDumper.php @@ -8,16 +8,16 @@ final class AttributeDumper implements StateVisitor { /** * An array having the state name as key and the attributes of this state. - * @var string[][] + * @var array */ - private array $structure = []; + private array $attributesByStates = []; /** - * @return string[][] + * @return array */ public function getStructure(): array { - return $this->structure; + return $this->attributesByStates; } /** @@ -26,10 +26,6 @@ public function getStructure(): array */ public function visitState(string $name, array $attributes): void { - if (!isset($this->structure[$name])) { - $this->structure[$name] = []; - } - - $this->structure[$name] = array_unique(array_merge($this->structure[$name], $attributes)); + $this->attributesByStates[$name] = $attributes; } } diff --git a/tests/StateBuilderTest.php b/tests/StateBuilderTest.php index 5a9c854..e4ee0c4 100644 --- a/tests/StateBuilderTest.php +++ b/tests/StateBuilderTest.php @@ -4,6 +4,8 @@ use PHPUnit\Framework\TestCase; use Star\Component\State\Builder\StateBuilder; +use Star\Component\State\Event\StateEventStore; +use Star\Component\State\Port\Symfony\EventDispatcherAdapter; final class StateBuilderTest extends TestCase { @@ -34,4 +36,29 @@ public function test_it_should_return_whether_the_current_state_has_attribute_af self::assertTrue($machine->isInState('to')); self::assertFalse($machine->hasAttribute('attr')); } + + public function test_it_should_dispatch_event_on_transit(): void + { + $i = 0; + $addition = function () use (&$i): void { + $i ++; + }; + + $listeners = new EventDispatcherAdapter(); + $listeners->addListener( + StateEventStore::BEFORE_TRANSITION, + $addition + ); + $listeners->addListener( + StateEventStore::AFTER_TRANSITION, + $addition + ); + + $machine = StateBuilder::build(listeners: $listeners) + ->allowTransition('t', 'from', 'to') + ->create('from'); + + $machine->transit('t', 'c'); + self::assertSame(2, $i); + } } diff --git a/tests/StateMachineTest.php b/tests/StateMachineTest.php index 07d134e..203ecb4 100644 --- a/tests/StateMachineTest.php +++ b/tests/StateMachineTest.php @@ -1,13 +1,10 @@ createMock(StateRegistry::class); - $machine = new StateMachine('', $registry, $this->events); $visitor = $this->createStub(TransitionVisitor::class); - + $registry = $this->createMock(StateRegistry::class); $registry ->expects($this->once()) ->method('acceptTransitionVisitor') ->with($visitor); + + $machine = new StateMachine('', $registry, $this->events); + $machine->acceptTransitionVisitor($visitor); } @@ -136,4 +134,31 @@ public function test_it_should_dispatch_an_event_before_a_transition_has_failed( self::assertCount(1, $events); self::assertContainsOnlyInstancesOf(TransitionWasFailed::class, $events); } + + public function test_it_should_invoke_before_state_change_callback(): void + { + $this->registry->addTransition(new OneToOneTransition('t', 'current', 'to')); + $buffer = new BufferStateChanges(); + + self::assertSame( + [], + $buffer->flushBuffer(), + ); + + $this->machine->transit( + 't', + 'context', + $buffer, + ); + + self::assertSame( + [ + 'context' => [ + 'beforeStateChange', + 'afterStateChange', + ], + ], + $buffer->flushBuffer(), + ); + } } diff --git a/tests/TestContext.php b/tests/TestContext.php index 2543164..a6f33ef 100644 --- a/tests/TestContext.php +++ b/tests/TestContext.php @@ -1,9 +1,4 @@ attributes ); } + + public function test_it_should_add_unique_attributes(): void + { + $this->registry->addAttribute('a', '1'); + $this->registry->addAttribute('a', '2'); + $this->registry->addAttribute('a', '2'); + $this->registry->addAttribute('a', '3'); + $this->registry->addAttribute('a', '3'); + + $this->registry->acceptStateVisitor($visitor = new AttributeDumper()); + self::assertSame( + [ + 'a' => [ + '1', + '2', + '3', + ], + ], + $visitor->getStructure() + ); + } } diff --git a/tests/Visitor/AttributeDumperTest.php b/tests/Visitor/AttributeDumperTest.php index 10d041c..54476b5 100644 --- a/tests/Visitor/AttributeDumperTest.php +++ b/tests/Visitor/AttributeDumperTest.php @@ -4,25 +4,19 @@ use PHPUnit\Framework\TestCase; use Star\Component\State\Builder\StateBuilder; -use Star\Component\State\StateMachine; final class AttributeDumperTest extends TestCase { - private StateMachine $machine; - - public function setUp(): void + public function test_it_should_dump_the_attributes(): void { - $this->machine = StateBuilder::build() + $machine = StateBuilder::build() ->allowTransition('t1', 's1', 's2') ->allowTransition('t2', ['s2', 's3'], 's1') ->addAttribute('a1', 's1') ->addAttribute('a2', ['s1', 's2']) ->create('s1'); - } + $machine->acceptStateVisitor($dumper = new AttributeDumper()); - public function test_it_should_dump_the_attributes(): void - { - $this->machine->acceptStateVisitor($dumper = new AttributeDumper()); self::assertEquals( [ 's1' => ['a1', 'a2'], @@ -32,4 +26,24 @@ public function test_it_should_dump_the_attributes(): void $dumper->getStructure() ); } + + public function test_it_should_dump_unique_attributes_by_state(): void + { + $machine = StateBuilder::build() + ->allowTransition('t1', 's1', 's2') + ->addAttribute('a1', ['s1', 's2']) + ->addAttribute('a2', ['s1', 's2']) + ->addAttribute('a3', ['s1', 's2']) + ->addAttribute('a4', ['s1', 's2']) + ->create('s1'); + $machine->acceptStateVisitor($dumper = new AttributeDumper()); + + self::assertEquals( + [ + 's1' => ['a1', 'a2', 'a3', 'a4'], + 's2' => ['a1', 'a2', 'a3', 'a4'], + ], + $dumper->getStructure() + ); + } } From 77aba74881715d604f8fa562b31e24e1b3988a43 Mon Sep 17 00:00:00 2001 From: Yannick Voyer Date: Sat, 13 Dec 2025 22:29:32 -0500 Subject: [PATCH 2/3] * Bound deps to 7.0 and 8.0 --- .github/workflows/php.yml | 4 ++-- composer.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 5716288..fcc7247 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -43,5 +43,5 @@ jobs: - name: PHPStan run: bin/phpstan - - name: Composer validate - run: composer validate + - name: Infection + run: bin/infection --formatter=progress diff --git a/composer.json b/composer.json index 82ecea5..b92c637 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "require": { "php": ">=8.2", "webmozart/assert": "^1.0", - "symfony/event-dispatcher": ">=7.0" + "symfony/event-dispatcher": "^7.0||^8.0" }, "require-dev": { "ext-pdo": "*", From 833e10cd8524c9359a34d46016deeff4a486708a Mon Sep 17 00:00:00 2001 From: Yannick Voyer Date: Sat, 13 Dec 2025 23:07:37 -0500 Subject: [PATCH 3/3] * Add script for test --- composer.json | 3 + src/Builder/StateBuilder.php | 13 ++-- src/Callbacks/BufferStateChanges.php | 18 ++++- src/Event/StateEventStore.php | 9 +++ src/StateMachine.php | 1 + tests/Callbacks/BufferStateChangesTest.php | 84 ++++++++++++++++++++++ tests/Event/StateEventStoreTest.php | 16 +++++ 7 files changed, 137 insertions(+), 7 deletions(-) create mode 100644 tests/Callbacks/BufferStateChangesTest.php create mode 100644 tests/Event/StateEventStoreTest.php diff --git a/composer.json b/composer.json index b92c637..823bde7 100644 --- a/composer.json +++ b/composer.json @@ -35,6 +35,9 @@ "symfony/cache": ">=7.0", "symfony/var-exporter": "^7.0" }, + "scripts": { + "test": "bin/phpunit; bin/phpcs; bin/phpstan; bin/infection" + }, "config": { "bin-dir": "bin", "sort-packages": true, diff --git a/src/Builder/StateBuilder.php b/src/Builder/StateBuilder.php index 3c0cd46..dbc9ca1 100644 --- a/src/Builder/StateBuilder.php +++ b/src/Builder/StateBuilder.php @@ -5,7 +5,6 @@ use Star\Component\State\EventRegistry; use Star\Component\State\Port\Symfony\EventDispatcherAdapter; use Star\Component\State\StateMachine; -use Star\Component\State\StateRegistry; use Star\Component\State\StateTransition; use Star\Component\State\TransitionRegistry; use Star\Component\State\Transitions\ManyToOneTransition; @@ -18,12 +17,13 @@ final class StateBuilder { private TransitionRegistry $registry; - private EventRegistry $listeners; + private EventRegistry /* todo use StateRegistry */ $listeners; public function __construct( - ?StateRegistry $registry = null, + ?TransitionRegistry $registry = null, ?EventRegistry $listeners = null, ) { + /** @todo deprecated nullable construct, move to private */ if (!$registry) { $registry = new TransitionRegistry(); } @@ -42,7 +42,7 @@ public function __construct( * * @return StateBuilder */ - public function allowTransition(string $name, $from, string $to): StateBuilder + public function allowTransition(string $name, string|array $from, string $to): StateBuilder { if (is_array($from)) { $transition = new ManyToOneTransition($name, $to, ...$from); @@ -60,6 +60,7 @@ public function allowTransition(string $name, $from, string $to): StateBuilder */ public function allowCustomTransition(StateTransition $transition): void { + // todo add interface for registry, and inject interface instead $this->registry->addTransition($transition); } @@ -69,7 +70,7 @@ public function allowCustomTransition(StateTransition $transition): void * * @return StateBuilder */ - public function addAttribute(string $attribute, $states): StateBuilder + public function addAttribute(string $attribute, string|array $states): StateBuilder { $states = (array) $states; foreach ($states as $stateName) { @@ -85,7 +86,7 @@ public function create(string $currentState): StateMachine } public static function build( - ?StateRegistry $registry = null, + ?TransitionRegistry $registry = null, ?EventRegistry $listeners = null, ): StateBuilder { return new self($registry, $listeners); diff --git a/src/Callbacks/BufferStateChanges.php b/src/Callbacks/BufferStateChanges.php index 379ac0f..94e36a6 100644 --- a/src/Callbacks/BufferStateChanges.php +++ b/src/Callbacks/BufferStateChanges.php @@ -5,21 +5,34 @@ use RuntimeException; use Star\Component\State\InvalidStateTransitionException; use Star\Component\State\StateMachine; +use Webmozart\Assert\Assert; +use function get_class; +use function is_object; final class BufferStateChanges implements TransitionCallback { /** - * @var array + * @var array> */ private array $buffer = []; public function beforeStateChange($context, StateMachine $machine): void { + if (is_object($context)) { + $context = get_class($context); + } + Assert::string($context, 'Context is expected to be a string. Got: %s'); + $this->buffer[$context][] = __FUNCTION__; } public function afterStateChange($context, StateMachine $machine): void { + if (is_object($context)) { + $context = get_class($context); + } + Assert::string($context, 'Context is expected to be a string. Got: %s'); + $this->buffer[$context][] = __FUNCTION__; } @@ -28,6 +41,9 @@ public function onFailure(InvalidStateTransitionException $exception, $context, throw new RuntimeException(__METHOD__ . ' is not implemented yet.'); } + /** + * @return array> + */ public function flushBuffer(): array { return $this->buffer; diff --git a/src/Event/StateEventStore.php b/src/Event/StateEventStore.php index c9994e2..18929b3 100644 --- a/src/Event/StateEventStore.php +++ b/src/Event/StateEventStore.php @@ -2,7 +2,9 @@ namespace Star\Component\State\Event; +use InvalidArgumentException; use function get_class; +use function sprintf; final class StateEventStore { @@ -29,10 +31,17 @@ final class StateEventStore public static function eventNameFromClass(StateEvent $event): string { + // todo deprecate string event in favor of class name return match (get_class($event)) { TransitionWasRequested::class => self::BEFORE_TRANSITION, TransitionWasSuccessful::class => self::AFTER_TRANSITION, TransitionWasFailed::class => self::FAILURE_TRANSITION, + default => throw new InvalidArgumentException( + sprintf( + 'Event "%s" is not mapped to a name.', + get_class($event), + ) + ), }; } } diff --git a/src/StateMachine.php b/src/StateMachine.php index c71784b..19eeb38 100644 --- a/src/StateMachine.php +++ b/src/StateMachine.php @@ -40,6 +40,7 @@ public function transit( mixed $context, ?TransitionCallback $callback = null ): string { + // todo deprecate mixed to use StateContext if (!$callback) { $callback = new AlwaysThrowExceptionOnFailure(); } diff --git a/tests/Callbacks/BufferStateChangesTest.php b/tests/Callbacks/BufferStateChangesTest.php new file mode 100644 index 0000000..18ace69 --- /dev/null +++ b/tests/Callbacks/BufferStateChangesTest.php @@ -0,0 +1,84 @@ +create(''); + + $buffer->beforeStateChange( + (object) [], + $machine + ); + $buffer->afterStateChange( + (object) [], + $machine + ); + + self::assertSame( + [ + 'stdClass' => [ + 0 => 'beforeStateChange', + 1 => 'afterStateChange', + ], + ], + $buffer->flushBuffer(), + ); + } + + public function test_it_should_buffer_context_as_string(): void + { + $buffer = new BufferStateChanges(); + $machine = StateBuilder::build() + ->create(''); + + $buffer->beforeStateChange( + 'stdClass', + $machine + ); + $buffer->afterStateChange( + 'stdClass', + $machine + ); + + self::assertSame( + [ + 'stdClass' => [ + 0 => 'beforeStateChange', + 1 => 'afterStateChange', + ], + ], + $buffer->flushBuffer(), + ); + } + + public function test_it_should_not_allow_non_string_context_in_before(): void + { + $buffer = new BufferStateChanges(); + $machine = StateBuilder::build() + ->create(''); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Context is expected to be a string. Got: integer'); + $buffer->beforeStateChange(42, $machine); + } + + public function test_it_should_not_allow_non_string_context_in_after(): void + { + $buffer = new BufferStateChanges(); + $machine = StateBuilder::build() + ->create(''); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Context is expected to be a string. Got: integer'); + $buffer->afterStateChange(42, $machine); + } +} diff --git a/tests/Event/StateEventStoreTest.php b/tests/Event/StateEventStoreTest.php new file mode 100644 index 0000000..1d651b0 --- /dev/null +++ b/tests/Event/StateEventStoreTest.php @@ -0,0 +1,16 @@ +expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('is not mapped to a name.'); + StateEventStore::eventNameFromClass($this->createStub(StateEvent::class)); + } +}