Skip to content

Commit

Permalink
Documentation reworked
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexandreDecan committed Mar 15, 2018
1 parent 74bb2cb commit 9bd35a4
Show file tree
Hide file tree
Showing 15 changed files with 151 additions and 115 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
Changelog
=========

0.26.3 (2018-03-15)
-------------------

- (Added) ``sismic.bdd`` exposes ``sismic.bdd.cli.execute_behave`` function to programmaticaly use ``sismic-bdd``.
- (Changed) ``execute_behave`` function has only two required parameters, and the remaining ones (that have default
values) can only be set by name, not by position.
- (Changed) ``action_alias`` and ``assertion_alias`` of module ``sismic.bdd.steps`` are renamed to ``map_action``
and ``map_assertion`` and are directly available from ``sismic.bdd``.


0.26.2 (2018-03-15)
-------------------

Expand Down
13 changes: 8 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@ Sismic for Python
Sismic Interactive Statechart Model Interpreter and Checker
-----------------------------------------------------------

Statecharts are a well-known visual language for modeling the executable behavior of complex reactive event-based systems.
The Sismic library for Python >= 3.4 provides a set of tools to define, validate, simulate, execute and debug statecharts.
More specifically, Sismic provides:
*Sismic* is a recursive acronym that stands for *Sismic Interactive Statechart Model Interpreter and Checker*.

Statecharts are a well-known visual modeling language for representing the executable behavior
of complex reactive event-based systems. Sismic library for Python (version 3.4 or higher) provides a set of
tools to define, validate, simulate, execute and test statecharts.
More specifically, Sismic provides:

- An easy way to define and to import statecharts, based on the human-friendly YAML markup language
- A statechart interpreter offering a discrete, step-by-step, and fully observable simulation engine
- Built-in support for expressing actions and guards using regular Python code, can be easily extended to other programming languages
- A design-by-contract approach for statecharts: contracts can be specified to express invariants, pre- and postconditions on states and transitions
- Runtime checking of behavioral properties expressed as statecharts.
- Predefined step definitions and utilities (including test coverage) to support behavior-driven development
- Runtime checking of behavioral properties expressed as statecharts
- Built-in support for behavior-driven development
- Synchronous and asynchronous simulation, in real time or simulated time
- Support for communication between statecharts and co-simulation
- Statechart visualization using `PlantUML <http://www.plantuml.com/plantuml>`__
Expand All @@ -43,6 +45,7 @@ The development occurs in the *devel* branch, the latest stable distributed vers

Sismic requires Python >=3.4


Documentation
-------------

Expand Down
5 changes: 1 addition & 4 deletions docs/api/bdd.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
Module *bdd*
============

Submodule *bdd.steps*
---------------------

.. automodule:: sismic.bdd.steps
.. automodule:: sismic.bdd
:members:
:member-order: bysource
:show-inheritance:
Expand Down
85 changes: 49 additions & 36 deletions docs/behavior.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
Behavior-Driven Development (BDD)
=================================
Behavior-Driven Development
===========================

About Behavior-Driven Development
---------------------------------

This introduction is inspired by the documentation of `Behave <http://behave.readthedocs.io/en/latest/philosophy.html>`__, a Python
library for Behavior-Driven Development (BDD).
Expand Down Expand Up @@ -82,14 +85,14 @@ We can then instruct ``sismic-bdd`` to run on this statechart the scenarios desc
sismic-bdd elevator.yaml --features elevator.feature
.. note:: ``sismic-bdd`` allows to specify the path to each file, so it is not mandatory to put all of them
in the same directory. It also accepts multiple files for the ``--features`` parameter, and supports
all the `command-line parameters of Behave <http://behave.readthedocs.io/en/latest/behave.html#command-line-arguments>`__.

Under the hood, ``sismic-bdd`` will create a temporary directory where all the files required to execute
Behave are put. It also makes available a list of predefined *given*, *when*, and *then* steps and sets up many
hooks that are required to integrate Sismic and Behave.

.. note:: Module ``sismic.bdd`` exposes a :py:func:`~sismic.bdd.execute_behave` function that is internally
used by ``sismic-bdd`` CLI, and that can be used if programmatic access to these features is required.


When ``sismic-bdd`` is executed, it will somehow translate the feature file into executable code, compute the outcomes
of the scenarios, check whether they match what is expected, and display as summary of all executed scenarios and
encountered errors:
Expand All @@ -103,8 +106,7 @@ encountered errors:
22 steps passed, 0 failed, 0 skipped, 0 undefined
Took 0m0.027s
The ``sismic-bdd`` command-line interface accepts several parameters. Here is the output of
``sismic-bdd -h``:
The ``sismic-bdd`` command-line interface accepts several other parameters:

.. code-block:: none
Expand Down Expand Up @@ -134,17 +136,27 @@ The ``sismic-bdd`` command-line interface accepts several parameters. Here is th
--debug-on-error Drop in a debugger in case of step failure (ipdb if
available)
Additionally, any extra parameter provided to ``sismic-bdd`` will be passed to Behave.
See `command-line parameters of Behave <http://behave.readthedocs.io/en/latest/behave.html#command-line-arguments>`__
for more information.



Predefined steps
----------------

Sismic comes with several predefined steps that can be used to manipulate the (interpreter of the) statechart and
to check that some conditions were met during execution.
In order to be able to execute scenarios, a Python developer needs to write code defining the mapping from the actions
and assertions expressed as natural language sentences in the scenarios (using specific
keywords such as *given*, *when* or *then*) to Python code that manipulates the statechart.
To facilitate the implementation of this mapping, Sismic provides a set of predefined
statechart-specific steps.

By convention, steps starting with *given* or *when* correspond to actions that must be applied by the statechart,
while steps starting with *then* correspond to assertions about what happened during the execution.
More precisely, any *given* or *when* step will trigger the ``execute()`` method of the underlying interpreter, *when*
steps will store the output of ``executed()`` and *then* steps will verify assertions on this output.
By convention, steps starting with *given* or *when* correspond to actions that must be applied on the statechart,
while steps starting with *then* correspond to assertions about the execution or the current state of the statechart.
More precisely, (1) all *given* or *when* steps implicitly call the :py:meth:`~sismic.interpreter.Interpreter.execute`
method of the underlying interpreter, (2) all *when* steps capture the output of these calls, and (3) we developed all
predefined *then* steps to assert things based on the captured output (implying that only the steps that start
with *when* will be monitored in practice).


"Given" and "when" steps
Expand Down Expand Up @@ -202,9 +214,6 @@ Given/when I repeat "{step}" {repeat:d} times
"Then" steps
~~~~~~~~~~~~

Remember that all these steps assert things about what happened during the execution the previous block of *when* steps.


Then state {name} is entered

Then state {name} is not entered
Expand Down Expand Up @@ -272,24 +281,22 @@ Then statechart is not in a final configuration
Implementing new steps
----------------------

While the steps that are already predefined should be sufficient to cover most of the cases, they are written in some
statechart specific language. It could be very convenient to use domain-specific steps to write scenarios.
For example, if the statechart being tested encodes the behavior of a microwave oven, it is far more intuitive to
have "*given I open the door*" instead of "*given I send event open door*".
While the steps that are already predefined should be sufficient to manipulate the statechart, it is more intuitive
to use domain-specific steps to write scenarios.
For example, if the statechart being tested encodes the behavior of a microwave oven, the domain-specific step
"Given I open the door" corresponds to the action of sending an event ``door_opened`` to the statechart, and is
more intuitive to use when writing scenarios.

Consider the following scenarios expressed using this somehow microwave-specific language:
Consider the following scenarios expressed using a domain-specific language:

.. literalinclude:: examples/microwave/heating_human.feature
:language: gherkin

A first option to implement "given I open the door" is to use Behave library to write a new step,
see `Python Step Implementations <http://behave.readthedocs.io/en/latest/tutorial.html#python-step-implementations>`__
for more information.

For convenience, the ``context`` object of Behave exposes three Sismic-related attributes, namely ``interpreter``,
``trace`` and ``monitored_trace``. The first one corresponds to the interpreter being executed, the second one is a
list of all executed macro steps, and the third one is list of executed macro steps restricted to the ones that were
performed during the execution of the previous block of *when* steps.
The mapping from domain-specific step "Given I open the door" to the action of sending a door opened event to the
statechart could be defined using plain Python code, by defining a new step following
`Python Step Implementations <http://behave.readthedocs.io/en/latest/tutorial.html#python-step-implementations>`__
of Behave.

.. code:: python
Expand All @@ -300,16 +307,22 @@ performed during the execution of the previous block of *when* steps.
def opening_door(context):
context.interpreter.queue('door_opened')
However, we believe that most of the time, the domain-specific steps are just aliases of predefined steps.
For convenience, :py:mod:`sismic.bdd.steps` provides two functions that can be easily used to define new aliases of
existing steps:
For convenience, the ``context`` parameter automatically provided by Behave at runtime exposes three Sismic-specific
attributes, namely ``interpreter``, ``trace`` and ``monitored_trace``.
The first one corresponds to the interpreter being executed, the second one is a list of all executed macro steps,
and the third one is list of executed macro steps restricted to the ones that were performed during the
execution of the previous block of *when* steps.

.. automodule:: sismic.bdd.steps
:members:
:noindex:

However, this domain-specific step can also be implemented more easily as an alias of predefined step "Given I send
event door_opened". As we believe that most of the domain-specific steps are just aliases or combinations of
predefined steps, Sismic provides two convenient helpers to map new steps to predefined ones:

.. automodule:: sismic.bdd
:members: map_action, map_assertion
:noindex:

Using these two functions, it is very easy to implement all steps used in the example above:
Using these helpers, one can easily implement the domain-specific steps of our example:

.. literalinclude:: examples/microwave/heating_steps.py
:language: python
Expand Down
3 changes: 3 additions & 0 deletions docs/code.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
Include code in statecharts
===========================

Python code evaluator
---------------------

A statechart can specify code that needs to be executed under some circumstances.
For example, the *preamble* of a statechart, the *guard* or *action* of a transition or the
*on entry* and *on exit* of a state may all contain code.
Expand Down
5 changes: 3 additions & 2 deletions docs/communication.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,9 @@ is sent both to ``interpreter_1`` and ``interpreter_2``.
Events for interpreter_2: Event('test')
Events for interpreter_3: InternalEvent('test')

Example
-------

Example of communicating statecharts
------------------------------------

Consider our running example, the elevator statechart.
This statechart expects to receive *floorSelected* events (with a *floor* parameter representing the selected floor).
Expand Down
26 changes: 13 additions & 13 deletions docs/examples/microwave/heating_steps.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
from sismic.bdd.steps import action_alias, assertion_alias
from sismic.bdd import map_action, map_assertion


action_alias('I open the door', 'I send event door_opened')
action_alias('I close the door', 'I send event door_closed')
action_alias('I place an item in the oven', 'I send event item_placed')
action_alias('I press increase timer button {time} times', 'I repeat "I send event timer_inc" {time} times')
action_alias('I press increase power button', 'I send event power_inc')
action_alias('I press start button', 'I send event cooking_start')
action_alias('{tick} seconds elapsed', 'I repeat "I send event timer_tick" {tick} times')
map_action('I open the door', 'I send event door_opened')
map_action('I close the door', 'I send event door_closed')
map_action('I place an item in the oven', 'I send event item_placed')
map_action('I press increase timer button {time} times', 'I repeat "I send event timer_inc" {time} times')
map_action('I press increase power button', 'I send event power_inc')
map_action('I press start button', 'I send event cooking_start')
map_action('{tick} seconds elapsed', 'I repeat "I send event timer_tick" {tick} times')

assertion_alias('Heating turns on', 'Event heating_on is fired')
assertion_alias('Heating does not turn on', 'Event heating_on is not fired')
assertion_alias('heating turns off', 'Event heating_off is fired')
assertion_alias('lamp turns on', 'Event lamp_switch_on is fired')
assertion_alias('lamp turns off', 'Event lamp_switch_off is fired')
map_assertion('Heating turns on', 'Event heating_on is fired')
map_assertion('Heating does not turn on', 'Event heating_on is not fired')
map_assertion('heating turns off', 'Event heating_off is fired')
map_assertion('lamp turns on', 'Event lamp_switch_on is fired')
map_assertion('lamp turns off', 'Event lamp_switch_off is fired')
27 changes: 12 additions & 15 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,12 @@ About

*Sismic* is a recursive acronym that stands for *Sismic Interactive Statechart Model Interpreter and Checker*.

The Sismic library for Python (version 3.4 or higher)
is mainly developed by Alexandre Decan at the `University of Mons <http://www.umons.ac.be>`_.

Sismic is released publicly under the `GNU Lesser General Public Licence version 3.0 (LGPLv3)
<http://www.gnu.org/licenses/lgpl-3.0.html>`_.

Sismic provides a set of tools to define, validate, simulate, execute and test statecharts.
Statecharts are a well-known visual modeling language for representing the executable behavior
of complex reactive event-based systems.
of complex reactive event-based systems. Sismic library for Python (version 3.4 or higher) provides a set of
tools to define, validate, simulate, execute and test statecharts.

Sismic is mainly developed by Alexandre Decan at the `University of Mons <http://www.umons.ac.be>`_ and released
publicly under the `GNU Lesser General Public Licence version 3.0 (LGPLv3) <http://www.gnu.org/licenses/lgpl-3.0.html>`_.


Features
Expand All @@ -42,8 +39,8 @@ Sismic provides the following features:
- A statechart interpreter offering a discrete, step-by-step, and fully observable simulation engine
- Built-in support for expressing actions and guards using regular Python code, can be easily extended to other programming languages
- A design-by-contract approach for statecharts: contracts can be specified to express invariants, pre- and postconditions on states and transitions
- Runtime checking of behavioral properties expressed as statecharts.
- Predefined step definitions and utilities (including test coverage) to support behavior-driven development
- Runtime checking of behavioral properties expressed as statecharts
- Built-in support for behavior-driven development
- Synchronous and asynchronous simulation, in real time or simulated time
- Support for communication between statecharts and co-simulation
- Statechart visualization using `PlantUML <http://www.plantuml.com/plantuml>`__
Expand All @@ -63,7 +60,7 @@ Sismic statecharts provides full support for the majority of the UML 2 statechar

.. toctree::
:caption: Overview
:maxdepth: 1
:maxdepth: 2

installation
format
Expand All @@ -72,18 +69,18 @@ Sismic statecharts provides full support for the majority of the UML 2 statechar

.. toctree::
:caption: Statechart testing
:maxdepth: 1
:maxdepth: 2

contract
properties
behavior

.. toctree::
:caption: Advanced topics
:maxdepth: 1
:maxdepth: 2

dealingtime
integrate_code
time
integration
communication
semantics

Expand Down
File renamed without changes.
30 changes: 19 additions & 11 deletions docs/properties.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
Monitoring properties
=====================


About runtime verification
--------------------------

Like any executable software artefacts, statecharts can and should be tested during their development.

One possible appproach is to test the execution of a statechart *by hand*, writing unit tests or BDD tests.
Expand All @@ -14,6 +18,10 @@ Another key feature of Sismic's interpreter is its support for monitoring proper
To avoid a statechart designer needing to learn a different language for expressing such properties,
these properties are expressed using the statechart notation. These properties are then called *property statecharts*


Using statecharts to express properties
---------------------------------------

Property statecharts can be used to express functional properties of the intended behaviour in terms of the events
that are consumed or sent, or in terms of the states that are entered or exited by a statechart.
When a statechart is executed by Sismic, specific meta-events are created based on the events that are sent or
Expand All @@ -30,10 +38,6 @@ While it is technically possible to use property statecharts to express liveline
(something desirable *eventually* happens), this would require additional code for their verification since
liveliness properties are not supported "as is" by Sismic.


Meta-events generated by the interpreter
----------------------------------------

During the execution of a statechart, several meta-events are created depending on what happens in the statechart
being executed. Those meta-events are automatically send to any previously bound property statechart.

Expand All @@ -46,20 +50,24 @@ When a property statechart is bound to an interpreter, its internal clock (the
:py:attr:`~sismic.interpreter.Interpreter.time` attribute) is automatically synchronised with the one of the
interpreter.

If a property statechart reaches a final state during its execution, then the property is considered as not
satisfied, and a :py:class:`~sismic.exceptions.PropertyStatechartError` is raised.
This exception provides access to the interpreter that executed the property, the active configuration of statechart
being executed, the latest executed :py:class:`~sismic.model.MacroStep` and the current context of the interpreter.


Meta-events generated by the interpreter
----------------------------------------

The complete list of :py:class:`~sismic.model.MetaEvent` that are created by the interpreter is described in the
documentation of the :py:meth:`~sismic.interpreter.Interpreter.bind_property_statechart` method:

.. automethod:: sismic.interpreter.Interpreter.bind_property_statechart
:noindex:

If a property statechart reaches a final state during its execution, then the property is considered as not
satisfied, and a :py:class:`~sismic.exceptions.PropertyStatechartError` is raised.
This exception provides access to the interpreter that executed the property, the active configuration of statechart
being executed, the latest executed :py:class:`~sismic.interpreter.MacroStep` and the current context of the interpreter.


Examples
--------
Examples of property statecharts
--------------------------------

7th floor is never reached
^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down

0 comments on commit 9bd35a4

Please sign in to comment.