{"id":21289001,"url":"https://github.com/hollodotme/state-machine-generator","last_synced_at":"2025-03-15T15:44:28.506Z","repository":{"id":78841634,"uuid":"82061489","full_name":"hollodotme/state-machine-generator","owner":"hollodotme","description":"PHP code generator for OOP state machines","archived":false,"fork":false,"pushed_at":"2020-03-25T03:29:10.000Z","size":56,"stargazers_count":2,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-22T05:42:45.449Z","etag":null,"topics":["code-generator","oop","php","state-machine"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hollodotme.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-15T13:04:48.000Z","updated_at":"2020-04-01T13:31:58.000Z","dependencies_parsed_at":"2023-04-16T01:52:16.180Z","dependency_job_id":null,"html_url":"https://github.com/hollodotme/state-machine-generator","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hollodotme%2Fstate-machine-generator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hollodotme%2Fstate-machine-generator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hollodotme%2Fstate-machine-generator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hollodotme%2Fstate-machine-generator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hollodotme","download_url":"https://codeload.github.com/hollodotme/state-machine-generator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243754008,"owners_count":20342537,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-generator","oop","php","state-machine"],"created_at":"2024-11-21T12:33:08.360Z","updated_at":"2025-03-15T15:44:28.485Z","avatar_url":"https://github.com/hollodotme.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/hollodotme/state-machine-generator.svg?branch=master)](https://travis-ci.org/hollodotme/state-machine-generator)\n[![Coverage Status](https://coveralls.io/repos/github/hollodotme/state-machine-generator/badge.svg?branch=master)](https://coveralls.io/github/hollodotme/state-machine-generator?branch=master)\n\n# State machine generator\n\nA PHP code generator for OOP state machines.\n\nThis package is based on the work of [Sebastian Bergmann and his state repository](https://github.com/sebastianbergmann/state).\n\n## Requirements\n\n* PHP \u003e= 7.1\n* PHPUnit \u003e= 6.0 (for running the generated tests)\n\n## Features\n\n* Command based CLI API\n* Support for namespaces\n* States can be represented as and reconstituted from strings\n* Configurable output paths\n* Configurable meta data\n* Template specification file creation\n* Generator available as a PHAR file\n\n## Installation\n\nDownload the current stable PHAR file from the [releases section](https://github.com/hollodotme/state-machine-generator/releases/).\n\n\twget https://github.com/hollodotme/state-machine-generator/releases/download/vX.X.X/state-machine-generator.phar\n\t\nIf you like verify it with its GPG signature:\n\n\twget https://github.com/hollodotme/state-machine-generator/releases/download/vX.X.X/state-machine-generator.phar.asc\n\n## Usage\n\n### Create a sample specification file\n\n```bash\n$ php state-machine-generator.phar create:specfile /path/to/specification-file.xml\n```\n\n### Generate state machine classes incl. exceptions and unit tests\n\n```bash\n$ php state-machine-generator.phar generate:machine /path/to/specification-file.xml\n```\n\n## Example\n\n### Specification file\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cspecification\u003e\n\t\u003cmeta\u003e\n\t\t\u003c!-- NOTE: You can add multiple author nodes. --\u003e\n\t\t\u003cauthor name=\"Your Name\" email=\"you@example.com\"/\u003e\n\t\u003c/meta\u003e\n\t\u003coutput\u003e\n\t\t\u003c!-- NOTE: Paths must be relative to the directory of this file. --\u003e\n\t\t\u003cpath for=\"mainClass\" dir=\"src\"/\u003e\n\t\t\u003cpath for=\"stateInterface\" dir=\"src/States/Interfaces\"/\u003e\n\t\t\u003cpath for=\"stateClasses\" dir=\"src/States\"/\u003e\n\t\t\u003cpath for=\"testClasses\" dir=\"tests/Unit\"/\u003e\n\t\t\u003cpath for=\"exceptions\" dir=\"src/States/Exceptions\"/\u003e\n\t\u003c/output\u003e\n\t\u003cconfiguration\u003e\n\t\t\u003c!-- NOTE: The value in \"fqcn\" attribute must be the full qualified class/interface name. --\u003e\n\t\t\u003cconfig for=\"mainClass\" fqcn=\"YourVendor\\YourProject\\Door\"/\u003e\n\t\t\u003cconfig for=\"stateInterface\" fqcn=\"YourVendor\\YourProject\\States\\Interfaces\\DoorState\"/\u003e\n\t\t\u003cconfig for=\"abstractStateClass\" fqcn=\"YourVendor\\YourProject\\States\\AbstractDoorState\"/\u003e\n\t\t\u003cconfig for=\"illegalTransitionException\" fqcn=\"YourVendor\\YourProject\\States\\Exceptions\\IllegalStateTransition\"/\u003e\n\t\t\u003cconfig for=\"invalidStateStringException\" fqcn=\"YourVendor\\YourProject\\States\\Exceptions\\InvalidStateString\"/\u003e\n\t\t\u003c!-- NOTE: Leave the \"*\" as the last namespace component --\u003e\n\t\t\u003cconfig for=\"testClasses\" fqcn=\"YourVendor\\YourProject\\Tests\\Unit\\*\"/\u003e\n\t\u003c/configuration\u003e\n\t\u003cstates\u003e\n\t\t\u003cstate name=\"OpenDoorState\" query=\"isOpen\" stringRepresentation=\"open\"/\u003e\n\t\t\u003cstate name=\"ClosedDoorState\" query=\"isClosed\" stringRepresentation=\"closed\"/\u003e\n\t\t\u003cstate name=\"LockedDoorState\" query=\"isLocked\" stringRepresentation=\"locked\"/\u003e\n\t\u003c/states\u003e\n\t\u003ctransitions\u003e\n\t\t\u003ctransition from=\"ClosedDoorState\" to=\"OpenDoorState\" operation=\"open\"/\u003e\n\t\t\u003ctransition from=\"OpenDoorState\" to=\"ClosedDoorState\" operation=\"close\"/\u003e\n\t\t\u003ctransition from=\"ClosedDoorState\" to=\"LockedDoorState\" operation=\"lock\"/\u003e\n\t\t\u003ctransition from=\"LockedDoorState\" to=\"ClosedDoorState\" operation=\"unlock\"/\u003e\n\t\u003c/transitions\u003e\n\t\u003coperations\u003e\n\t\t\u003coperation name=\"open\" allowed=\"canBeOpened\" disallowed=\"cannotBeOpened\"/\u003e\n\t\t\u003coperation name=\"close\" allowed=\"canBeClosed\" disallowed=\"cannotBeClosed\"/\u003e\n\t\t\u003coperation name=\"lock\" allowed=\"canBeLocked\" disallowed=\"cannotBeLocked\"/\u003e\n\t\t\u003coperation name=\"unlock\" allowed=\"canBeUnlocked\" disallowed=\"cannotBeUnlocked\"/\u003e\n\t\u003c/operations\u003e\n\u003c/specification\u003e\n\n```\n\n### Generated files\n\n```\n- /src\n   |- /States\n   |   |- /Exceptions\n   |   |   |- IllegalStateTransition\n   |   |   `- InvalidStateString\n   |   |- /Interfaces\n   |   |   `- DoorState.php\n   |   |- AbstractDoorState.php\n   |   |- ClosedDoorState.php\n   |   |- LockedDoorState.php\n   |   `- OpenDoorState.php\n   `- Door.php\n- /tests\n   |- ClosedDoorStateTest.php\n   |- LockedDoorStateTest.php\n   `- OpenDoorStateTest.php\n```\n\n#### Interface `DoorState`\n\n```php\n\u003c?php declare(strict_types=1);\n/**\n * @author Your Name \u003cyou@example.com\u003e\n */\n\nnamespace YourVendor\\YourProject\\States\\Interfaces;\n\n/**\n * Interface DoorState\n * @package YourVendor\\YourProject\\States\\Interfaces\n */\ninterface DoorState\n{\n\tpublic function open() : DoorState;\n\n\tpublic function close() : DoorState;\n\n\tpublic function lock() : DoorState;\n\n\tpublic function unlock() : DoorState;\n\n\tpublic function toString() : string;\n\n\tpublic function __toString() : string;\n}\n```\n\n### Class `AbstractDoorState`\n\n```php\n\u003c?php declare(strict_types=1);\n/**\n * @author Your Name \u003cyou@example.com\u003e\n */\n\nnamespace YourVendor\\YourProject\\States;\n\nuse YourVendor\\YourProject\\States\\Interfaces\\DoorState;\nuse YourVendor\\YourProject\\States\\Exceptions\\IllegalStateTransition;\nuse YourVendor\\YourProject\\States\\Exceptions\\InvalidStateString;\n\n/**\n * Class AbstractDoorState\n * @package YourVendor\\YourProject\\States\n */\nabstract class AbstractDoorState implements DoorState\n{\n\tprotected const OPEN = 'open';\n\n\tprotected const CLOSED = 'closed';\n\n\tprotected const LOCKED = 'locked';\n\n\tpublic function open() : DoorState\n\t{\n\t\tthrow (new IllegalStateTransition())-\u003ewithDesiredState(self::OPEN);\n\t}\n\n\tpublic function close() : DoorState\n\t{\n\t\tthrow (new IllegalStateTransition())-\u003ewithDesiredState(self::CLOSED);\n\t}\n\n\tpublic function lock() : DoorState\n\t{\n\t\tthrow (new IllegalStateTransition())-\u003ewithDesiredState(self::LOCKED);\n\t}\n\n\tpublic function unlock() : DoorState\n\t{\n\t\tthrow (new IllegalStateTransition())-\u003ewithDesiredState(self::CLOSED);\n\t}\n\n\tpublic function __toString() : string\n\t{\n\t\treturn $this-\u003etoString();\n\t}\n\n\t/**\n\t * @param string $stateString\n\t * @throws InvalidStateString\n\t * @return DoorState\n\t */\n\tpublic static function fromString(string $stateString) : DoorState\n\t{\n\t\tswitch($stateString)\n\t\t{\n\t\t\tcase self::OPEN:\n\t\t\t\treturn new OpenDoorState();\n\n\t\t\tcase self::CLOSED:\n\t\t\t\treturn new ClosedDoorState();\n\n\t\t\tcase self::LOCKED:\n\t\t\t\treturn new LockedDoorState();\n\n\t\t\tdefault:\n\t\t\t\tthrow (new InvalidStateString())-\u003ewithStateString($stateString);\n\t\t}\n\t}\n}\n```\n\n#### Class `ClosedDoorState`\n\n```php\n\u003c?php declare(strict_types=1);\n/**\n * @author Your Name \u003cyou@example.com\u003e\n */\n\nnamespace YourVendor\\YourProject\\States;\n\nuse YourVendor\\YourProject\\States\\Interfaces\\DoorState;\n\n/**\n * Class ClosedDoorState\n * @package YourVendor\\YourProject\\States\n */\nfinal class ClosedDoorState extends AbstractDoorState\n{\n\tpublic function open() : DoorState\n\t{\n\t\treturn new OpenDoorState();\n\t}\n\n\tpublic function lock() : DoorState\n\t{\n\t\treturn new LockedDoorState();\n\t}\n\n\tpublic function toString() : string\n\t{\n\t\treturn self::CLOSED;\n\t}\n}\n```\n\n#### Class `LockedDoorState`\n\n```php\n\u003c?php declare(strict_types=1);\n/**\n * @author Your Name \u003cyou@example.com\u003e\n */\n\nnamespace YourVendor\\YourProject\\States;\n\nuse YourVendor\\YourProject\\States\\Interfaces\\DoorState;\n\n/**\n * Class LockedDoorState\n * @package YourVendor\\YourProject\\States\n */\nfinal class LockedDoorState extends AbstractDoorState\n{\n\tpublic function unlock() : DoorState\n\t{\n\t\treturn new ClosedDoorState();\n\t}\n\n\tpublic function toString() : string\n\t{\n\t\treturn self::LOCKED;\n\t}\n}\n```\n\n#### Class `OpenDoorState`\n\n```php\n\u003c?php declare(strict_types=1);\n/**\n * @author Your Name \u003cyou@example.com\u003e\n */\n\nnamespace YourVendor\\YourProject\\States;\n\nuse YourVendor\\YourProject\\States\\Interfaces\\DoorState;\n\n/**\n * Class OpenDoorState\n * @package YourVendor\\YourProject\\States\n */\nfinal class OpenDoorState extends AbstractDoorState\n{\n\tpublic function close() : DoorState\n\t{\n\t\treturn new ClosedDoorState();\n\t}\n\n\tpublic function toString() : string\n\t{\n\t\treturn self::OPEN;\n\t}\n}\n```\n\n#### Class `Door`\n\n```php\n\u003c?php declare(strict_types=1);\n/**\n * @author Your Name \u003cyou@example.com\u003e\n */\n\nnamespace YourVendor\\YourProject;\n\nuse YourVendor\\YourProject\\States\\Interfaces\\DoorState;\nuse YourVendor\\YourProject\\States\\Exceptions\\IllegalStateTransition;\nuse YourVendor\\YourProject\\States\\OpenDoorState;\nuse YourVendor\\YourProject\\States\\ClosedDoorState;\nuse YourVendor\\YourProject\\States\\LockedDoorState;\n\n/**\n * Class Door\n * @package YourVendor\\YourProject\n */\nclass Door\n{\n\t/** @var DoorState */\n\tprivate $state;\n\n\tpublic function __construct(DoorState $state)\n\t{\n\t\t$this-\u003esetState($state);\n\t}\n\n\tprivate function setState(DoorState $state)\n\t{\n\t\t$this-\u003estate = $state;\n\t}\n\n\t/**\n\t * @throws IllegalStateTransition\n\t */\n\tpublic function open()\n\t{\n\t\t$this-\u003esetState($this-\u003estate-\u003eopen());\n\t}\n\n\t/**\n\t * @throws IllegalStateTransition\n\t */\n\tpublic function close()\n\t{\n\t\t$this-\u003esetState($this-\u003estate-\u003eclose());\n\t}\n\n\t/**\n\t * @throws IllegalStateTransition\n\t */\n\tpublic function lock()\n\t{\n\t\t$this-\u003esetState($this-\u003estate-\u003elock());\n\t}\n\n\t/**\n\t * @throws IllegalStateTransition\n\t */\n\tpublic function unlock()\n\t{\n\t\t$this-\u003esetState($this-\u003estate-\u003eunlock());\n\t}\n\n\tpublic function isOpen() : bool\n\t{\n\t\treturn ($this-\u003estate instanceof OpenDoorState);\n\t}\n\n\tpublic function isClosed() : bool\n\t{\n\t\treturn ($this-\u003estate instanceof ClosedDoorState);\n\t}\n\n\tpublic function isLocked() : bool\n\t{\n\t\treturn ($this-\u003estate instanceof LockedDoorState);\n\t}\n}\n```\n\n#### Test class `ClosedDoorStateTest`\n\n```php\n\u003c?php declare(strict_types=1);\n/**\n * @author Your Name \u003cyou@example.com\u003e\n */\n\nnamespace YourVendor\\YourProject\\Tests\\Unit;\n\nuse YourVendor\\YourProject\\Door;\nuse YourVendor\\YourProject\\States\\AbstractDoorState;\nuse YourVendor\\YourProject\\States\\Exceptions\\InvalidStateString;\nuse YourVendor\\YourProject\\States\\Exceptions\\IllegalStateTransition;\nuse YourVendor\\YourProject\\States\\ClosedDoorState;\n\n/**\n * Class ClosedDoorStateTest\n * @package YourVendor\\YourProject\\Tests\\Unit\n */\nfinal class ClosedDoorStateTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /** @var Door */\n    private $door;\n\n    protected function setUp()\n    {\n        $this-\u003edoor = new Door(new ClosedDoorState());\n\t}\n\n\tpublic function testIsNotOpen()\n\t{\n\t\t$this-\u003eassertFalse($this-\u003edoor-\u003eisOpen());\n\t}\n\n\tpublic function testIsClosed()\n\t{\n\t\t$this-\u003eassertTrue($this-\u003edoor-\u003eisClosed());\n\t}\n\n\tpublic function testIsNotLocked()\n\t{\n\t\t$this-\u003eassertFalse($this-\u003edoor-\u003eisLocked());\n\t}\n\n\tpublic function testCanBeOpened()\n\t{\n\t\t$this-\u003edoor-\u003eopen();\n\n\t\t$this-\u003eassertTrue($this-\u003edoor-\u003eisOpen());\n\t}\n\n\t/**\n\t * @expectedException \\YourVendor\\YourProject\\States\\Exceptions\\IllegalStateTransition\n\t */\n\tpublic function testCannotBeClosed()\n\t{\n\t\ttry\n\t\t{\n\t\t\t$this-\u003edoor-\u003eclose();\n\t\t}\n\t\tcatch(IllegalStateTransition $e)\n\t\t{\n\t\t\t$this-\u003eassertEquals('closed', $e-\u003egetDesiredState());\n\n\t\t\tthrow $e;\n\t\t}\n\t}\n\n\tpublic function testCanBeLocked()\n\t{\n\t\t$this-\u003edoor-\u003elock();\n\n\t\t$this-\u003eassertTrue($this-\u003edoor-\u003eisLocked());\n\t}\n\n\t/**\n\t * @expectedException \\YourVendor\\YourProject\\States\\Exceptions\\IllegalStateTransition\n\t */\n\tpublic function testCannotBeUnlocked()\n\t{\n\t\ttry\n\t\t{\n\t\t\t$this-\u003edoor-\u003eunlock();\n\t\t}\n\t\tcatch(IllegalStateTransition $e)\n\t\t{\n\t\t\t$this-\u003eassertEquals('closed', $e-\u003egetDesiredState());\n\n\t\t\tthrow $e;\n\t\t}\n\t}\n\n\tpublic function testStateCanBeRepresentedAsString()\n\t{\n\t\t$state = new ClosedDoorState();\n\n\t\t$this-\u003eassertEquals('closed', (string)$state);\n\t\t$this-\u003eassertEquals('closed', $state-\u003etoString());\n\t}\n\n\tpublic function testCanBuildStateFromStringRepresentation()\n\t{\n\t\t$state = AbstractDoorState::fromString('closed');\n\n\t\t$this-\u003eassertInstanceOf(ClosedDoorState::class, $state);\n\t}\n\n\t/**\n\t * @expectedException \\YourVendor\\YourProject\\States\\Exceptions\\InvalidStateString\n\t */\n\tpublic function testInvalidStateStringThrowsException()\n\t{\n\t\ttry\n\t\t{\n\t\t\tAbstractDoorState::fromString('closed.invalid');\n\t\t}\n\t\tcatch (InvalidStateString $e)\n\t\t{\n\t\t\t$this-\u003eassertEquals('closed.invalid', $e-\u003egetStateString());\n\n\t\t\tthrow $e;\n\t\t}\n\t}\n}\n```\n\n#### Test class `LockedDoorStateTest`\n\n```php\n\u003c?php declare(strict_types=1);\n/**\n * @author Your Name \u003cyou@example.com\u003e\n */\n\nnamespace YourVendor\\YourProject\\Tests\\Unit;\n\nuse YourVendor\\YourProject\\Door;\nuse YourVendor\\YourProject\\States\\AbstractDoorState;\nuse YourVendor\\YourProject\\States\\Exceptions\\InvalidStateString;\nuse YourVendor\\YourProject\\States\\Exceptions\\IllegalStateTransition;\nuse YourVendor\\YourProject\\States\\LockedDoorState;\n\n/**\n * Class LockedDoorStateTest\n * @package YourVendor\\YourProject\\Tests\\Unit\n */\nfinal class LockedDoorStateTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /** @var Door */\n    private $door;\n\n    protected function setUp()\n    {\n        $this-\u003edoor = new Door(new LockedDoorState());\n\t}\n\n\tpublic function testIsNotOpen()\n\t{\n\t\t$this-\u003eassertFalse($this-\u003edoor-\u003eisOpen());\n\t}\n\n\tpublic function testIsNotClosed()\n\t{\n\t\t$this-\u003eassertFalse($this-\u003edoor-\u003eisClosed());\n\t}\n\n\tpublic function testIsLocked()\n\t{\n\t\t$this-\u003eassertTrue($this-\u003edoor-\u003eisLocked());\n\t}\n\n\t/**\n\t * @expectedException \\YourVendor\\YourProject\\States\\Exceptions\\IllegalStateTransition\n\t */\n\tpublic function testCannotBeOpened()\n\t{\n\t\ttry\n\t\t{\n\t\t\t$this-\u003edoor-\u003eopen();\n\t\t}\n\t\tcatch(IllegalStateTransition $e)\n\t\t{\n\t\t\t$this-\u003eassertEquals('open', $e-\u003egetDesiredState());\n\n\t\t\tthrow $e;\n\t\t}\n\t}\n\n\t/**\n\t * @expectedException \\YourVendor\\YourProject\\States\\Exceptions\\IllegalStateTransition\n\t */\n\tpublic function testCannotBeClosed()\n\t{\n\t\ttry\n\t\t{\n\t\t\t$this-\u003edoor-\u003eclose();\n\t\t}\n\t\tcatch(IllegalStateTransition $e)\n\t\t{\n\t\t\t$this-\u003eassertEquals('closed', $e-\u003egetDesiredState());\n\n\t\t\tthrow $e;\n\t\t}\n\t}\n\n\t/**\n\t * @expectedException \\YourVendor\\YourProject\\States\\Exceptions\\IllegalStateTransition\n\t */\n\tpublic function testCannotBeLocked()\n\t{\n\t\ttry\n\t\t{\n\t\t\t$this-\u003edoor-\u003elock();\n\t\t}\n\t\tcatch(IllegalStateTransition $e)\n\t\t{\n\t\t\t$this-\u003eassertEquals('locked', $e-\u003egetDesiredState());\n\n\t\t\tthrow $e;\n\t\t}\n\t}\n\n\tpublic function testCanBeUnlocked()\n\t{\n\t\t$this-\u003edoor-\u003eunlock();\n\n\t\t$this-\u003eassertTrue($this-\u003edoor-\u003eisClosed());\n\t}\n\n\tpublic function testStateCanBeRepresentedAsString()\n\t{\n\t\t$state = new LockedDoorState();\n\n\t\t$this-\u003eassertEquals('locked', (string)$state);\n\t\t$this-\u003eassertEquals('locked', $state-\u003etoString());\n\t}\n\n\tpublic function testCanBuildStateFromStringRepresentation()\n\t{\n\t\t$state = AbstractDoorState::fromString('locked');\n\n\t\t$this-\u003eassertInstanceOf(LockedDoorState::class, $state);\n\t}\n\n\t/**\n\t * @expectedException \\YourVendor\\YourProject\\States\\Exceptions\\InvalidStateString\n\t */\n\tpublic function testInvalidStateStringThrowsException()\n\t{\n\t\ttry\n\t\t{\n\t\t\tAbstractDoorState::fromString('locked.invalid');\n\t\t}\n\t\tcatch (InvalidStateString $e)\n\t\t{\n\t\t\t$this-\u003eassertEquals('locked.invalid', $e-\u003egetStateString());\n\n\t\t\tthrow $e;\n\t\t}\n\t}\n}\n```\n\n#### Test class `OpenDoorStateTest`\n\n```php\n\u003c?php declare(strict_types=1);\n/**\n * @author Your Name \u003cyou@example.com\u003e\n */\n\nnamespace YourVendor\\YourProject\\Tests\\Unit;\n\nuse YourVendor\\YourProject\\Door;\nuse YourVendor\\YourProject\\States\\AbstractDoorState;\nuse YourVendor\\YourProject\\States\\Exceptions\\InvalidStateString;\nuse YourVendor\\YourProject\\States\\Exceptions\\IllegalStateTransition;\nuse YourVendor\\YourProject\\States\\OpenDoorState;\n\n/**\n * Class OpenDoorStateTest\n * @package YourVendor\\YourProject\\Tests\\Unit\n */\nfinal class OpenDoorStateTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /** @var Door */\n    private $door;\n\n    protected function setUp()\n    {\n        $this-\u003edoor = new Door(new OpenDoorState());\n\t}\n\n\tpublic function testIsOpen()\n\t{\n\t\t$this-\u003eassertTrue($this-\u003edoor-\u003eisOpen());\n\t}\n\n\tpublic function testIsNotClosed()\n\t{\n\t\t$this-\u003eassertFalse($this-\u003edoor-\u003eisClosed());\n\t}\n\n\tpublic function testIsNotLocked()\n\t{\n\t\t$this-\u003eassertFalse($this-\u003edoor-\u003eisLocked());\n\t}\n\n\t/**\n\t * @expectedException \\YourVendor\\YourProject\\States\\Exceptions\\IllegalStateTransition\n\t */\n\tpublic function testCannotBeOpened()\n\t{\n\t\ttry\n\t\t{\n\t\t\t$this-\u003edoor-\u003eopen();\n\t\t}\n\t\tcatch(IllegalStateTransition $e)\n\t\t{\n\t\t\t$this-\u003eassertEquals('open', $e-\u003egetDesiredState());\n\n\t\t\tthrow $e;\n\t\t}\n\t}\n\n\tpublic function testCanBeClosed()\n\t{\n\t\t$this-\u003edoor-\u003eclose();\n\n\t\t$this-\u003eassertTrue($this-\u003edoor-\u003eisClosed());\n\t}\n\n\t/**\n\t * @expectedException \\YourVendor\\YourProject\\States\\Exceptions\\IllegalStateTransition\n\t */\n\tpublic function testCannotBeLocked()\n\t{\n\t\ttry\n\t\t{\n\t\t\t$this-\u003edoor-\u003elock();\n\t\t}\n\t\tcatch(IllegalStateTransition $e)\n\t\t{\n\t\t\t$this-\u003eassertEquals('locked', $e-\u003egetDesiredState());\n\n\t\t\tthrow $e;\n\t\t}\n\t}\n\n\t/**\n\t * @expectedException \\YourVendor\\YourProject\\States\\Exceptions\\IllegalStateTransition\n\t */\n\tpublic function testCannotBeUnlocked()\n\t{\n\t\ttry\n\t\t{\n\t\t\t$this-\u003edoor-\u003eunlock();\n\t\t}\n\t\tcatch(IllegalStateTransition $e)\n\t\t{\n\t\t\t$this-\u003eassertEquals('closed', $e-\u003egetDesiredState());\n\n\t\t\tthrow $e;\n\t\t}\n\t}\n\n\tpublic function testStateCanBeRepresentedAsString()\n\t{\n\t\t$state = new OpenDoorState();\n\n\t\t$this-\u003eassertEquals('open', (string)$state);\n\t\t$this-\u003eassertEquals('open', $state-\u003etoString());\n\t}\n\n\tpublic function testCanBuildStateFromStringRepresentation()\n\t{\n\t\t$state = AbstractDoorState::fromString('open');\n\n\t\t$this-\u003eassertInstanceOf(OpenDoorState::class, $state);\n\t}\n\n\t/**\n\t * @expectedException \\YourVendor\\YourProject\\States\\Exceptions\\InvalidStateString\n\t */\n\tpublic function testInvalidStateStringThrowsException()\n\t{\n\t\ttry\n\t\t{\n\t\t\tAbstractDoorState::fromString('open.invalid');\n\t\t}\n\t\tcatch (InvalidStateString $e)\n\t\t{\n\t\t\t$this-\u003eassertEquals('open.invalid', $e-\u003egetStateString());\n\n\t\t\tthrow $e;\n\t\t}\n\t}\n}\n```\n\n### Test execution result with TestDox and text coverage summary\n\n```\nPHPUnit 6.0.6 by Sebastian Bergmann and contributors.\n\nRuntime:       PHP 7.1.1 with Xdebug 2.5.0\nConfiguration: /Users/hollodotme/Sites/StateMachineGenerator/build/phpunit.xml\n\nYourVendor\\YourProject\\Tests\\Unit\\ClosedDoorState\n [x] Is not open\n [x] Is closed\n [x] Is not locked\n [x] Can be opened\n [x] Cannot be closed\n [x] Can be locked\n [x] Cannot be unlocked\n [x] State can be represented as string\n [x] Can build state from string representation\n [x] Invalid state string throws exception\n\nYourVendor\\YourProject\\Tests\\Unit\\LockedDoorState\n [x] Is not open\n [x] Is not closed\n [x] Is locked\n [x] Cannot be opened\n [x] Cannot be closed\n [x] Cannot be locked\n [x] Can be unlocked\n [x] State can be represented as string\n [x] Can build state from string representation\n [x] Invalid state string throws exception\n\nYourVendor\\YourProject\\Tests\\Unit\\OpenDoorState\n [x] Is open\n [x] Is not closed\n [x] Is not locked\n [x] Cannot be opened\n [x] Can be closed\n [x] Cannot be locked\n [x] Cannot be unlocked\n [x] State can be represented as string\n [x] Can build state from string representation\n [x] Invalid state string throws exception\n\nCode Coverage Report Summary:\n  Classes: 100.00% (7/7)\n  Methods: 100.00% (26/26)\n  Lines:   100.00% (42/42)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhollodotme%2Fstate-machine-generator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhollodotme%2Fstate-machine-generator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhollodotme%2Fstate-machine-generator/lists"}