{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# import piplite\n# await piplite.install('python-statemachine[diagrams]')\n# import patch_repr_svg"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# All actions machine\n\nA StateMachine that exercices all possible `Actions` and `Guards`.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import mock\n\nfrom statemachine import State\nfrom statemachine import StateMachine\n\n\nclass AllActionsMachine(StateMachine):\n\n    initial = State(\"Initial\", initial=True)\n    final = State(\"Final\", final=True)\n\n    go = initial.to(\n        final,\n        validators=[\"validation_1\", \"validation_2\"],\n        cond=[\"condition_1\", \"condition_2\"],\n        unless=[\"unless_1\", \"unless_2\"],\n        on=[\"on_inline_1\", \"on_inline_2\"],\n        before=[\"before_go_inline_1\", \"before_go_inline_2\"],\n        after=[\"after_go_inline_1\", \"after_go_inline_2\"],\n    )\n\n    def __init__(self, *args, **kwargs):\n        self.spy = mock.Mock(side_effect=lambda x: x)\n        super(AllActionsMachine, self).__init__(*args, **kwargs)\n\n    # validators and guards\n\n    def validation_1(self):\n        # this method may raise an exception\n        return self.spy(\"validation_1\")\n\n    def validation_2(self):\n        # this method may raise an exception\n        return self.spy(\"validation_2\")\n\n    def condition_1(self):\n        self.spy(\"condition_1\")\n        return True\n\n    def condition_2(self):\n        self.spy(\"condition_2\")\n        return True\n\n    def unless_1(self):\n        self.spy(\"unless_1\")\n        return False\n\n    def unless_2(self):\n        self.spy(\"unless_2\")\n        return False\n\n    # generics state\n\n    def on_enter_state(self):\n        return self.spy(\"on_enter_state\")\n\n    def on_exit_state(self):\n        return self.spy(\"on_exit_state\")\n\n    # generics transition\n\n    def before_transition(self):\n        return self.spy(\"before_transition\")\n\n    def on_transition(self):\n        return self.spy(\"on_transition\")\n\n    def after_transition(self):\n        return self.spy(\"after_transition\")\n\n    # before / after specific\n\n    @go.before\n    def before_go_decor(self):\n        return self.spy(\"before_go_decor\")\n\n    def before_go_inline_1(self):\n        return self.spy(\"before_go_inline_1\")\n\n    def before_go_inline_2(self):\n        return self.spy(\"before_go_inline_2\")\n\n    def before_go(self):\n        return self.spy(\"before_go\")\n\n    @go.on\n    def go_on_decor(self):\n        return self.spy(\"go_on_decor\")\n\n    def on_inline_1(self):\n        return self.spy(\"on_inline_1\")\n\n    def on_inline_2(self):\n        return self.spy(\"on_inline_2\")\n\n    def on_go(self):\n        return self.spy(\"on_go\")\n\n    @go.after\n    def after_go_decor(self):\n        return self.spy(\"after_go_decor\")\n\n    def after_go_inline_1(self):\n        return self.spy(\"after_go_inline_1\")\n\n    def after_go_inline_2(self):\n        return self.spy(\"after_go_inline_2\")\n\n    def after_go(self):\n        return self.spy(\"after_go\")\n\n    # enter / exit specific\n\n    @initial.enter\n    def enter_initial_decor(self):\n        return self.spy(\"enter_initial_decor\")\n\n    def on_enter_initial(self):\n        return self.spy(\"on_enter_initial\")\n\n    @initial.exit\n    def exit_initial_decor(self):\n        return self.spy(\"exit_initial_decor\")\n\n    def on_exit_initial(self):\n        return self.spy(\"on_exit_initial\")\n\n    def on_enter_final(self):\n        return self.spy(\"on_enter_final\")\n\n    def on_exit_final(self):\n        \"hopefully this will not be called\"\n        return self.spy(\"on_exit_final\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Testing\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "machine = AllActionsMachine()\nspy = machine.spy"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Only before/on actions have their result collected.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "result = machine.go()\nassert result == [\n    \"before_transition\",\n    \"before_go_inline_1\",\n    \"before_go_inline_2\",\n    \"before_go_decor\",\n    \"before_go\",\n    \"on_transition\",\n    \"on_inline_1\",\n    \"on_inline_2\",\n    \"go_on_decor\",\n    \"on_go\",\n]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Checking the method resolution order\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "assert spy.call_args_list == [\n    mock.call(\"on_enter_state\"),\n    mock.call(\"enter_initial_decor\"),\n    mock.call(\"on_enter_initial\"),\n    mock.call(\"validation_1\"),\n    mock.call(\"validation_2\"),\n    mock.call(\"condition_1\"),\n    mock.call(\"condition_2\"),\n    mock.call(\"unless_1\"),\n    mock.call(\"unless_2\"),\n    mock.call(\"before_transition\"),\n    mock.call(\"before_go_inline_1\"),\n    mock.call(\"before_go_inline_2\"),\n    mock.call(\"before_go_decor\"),\n    mock.call(\"before_go\"),\n    mock.call(\"on_exit_state\"),\n    mock.call(\"exit_initial_decor\"),\n    mock.call(\"on_exit_initial\"),\n    mock.call(\"on_transition\"),\n    mock.call(\"on_inline_1\"),\n    mock.call(\"on_inline_2\"),\n    mock.call(\"go_on_decor\"),\n    mock.call(\"on_go\"),\n    mock.call(\"on_enter_state\"),\n    mock.call(\"on_enter_final\"),\n    mock.call(\"after_go_inline_1\"),\n    mock.call(\"after_go_inline_2\"),\n    mock.call(\"after_go_decor\"),\n    mock.call(\"after_go\"),\n    mock.call(\"after_transition\"),\n]"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.8.1"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}