def test_pass_state():
    """
    The Pass State (identified by "Type":"Pass") simply passes its input to its output, performing no work. 

    A Pass State MAY have a field named “Result”. 

    If present, its value is treated as the output of a virtual task, and placed as prescribed by the “ResultPath” field, 
    if any, to be passed on to the next state. 

    If “Result” is not provided, the output is the input. 

    Thus if neither “Result” nor “ResultPath” are provided, the Pass state copies its input through to its output.
    """

    machine = Machine()
    pass_ = Pass(2)
    machine.register(pass_)
    pass_run_result = machine.interpret()

    assert pass_run_result == 2

    pass_ = Pass(result=5)
    machine_2 = Machine()
    machine_2.register(pass_)
    pass_2_run_result = machine_2.interpret()

    assert pass_2_run_result == 5
def test_sugared_state_transition():

    first_state = Pass(name="state_one")
    second_state = Pass(name="state_two")

    machine = Machine()
    machine.register(first_state)
    machine.register(second_state)

    compiled = machine.compile()

    second_machine = first_state + second_state
    second_compiled = second_machine.compile()

    # This assert shows that a machine can be created by adding states
    # and that machine is equivalent to adding states with the OO interface
    assert compiled == second_compiled

    fourth_state = Pass(name="state_three")
    fifth_state = Pass(name="state_four")

    machine.register(fourth_state)
    machine.register(fifth_state)

    third_machine = Machine()
    third_machine.register(fourth_state)
    third_machine.register(fifth_state)

    fourth_machine = second_machine + third_machine

    # This assert shows that a machine can be created by adding two machines
    # and that machine is equivalent to one created with the OO interface
    assert machine.compile() == fourth_machine.compile()
def test_pass_state_transition():

    first_state = Pass(name="state_one")
    second_state = Pass(name="state_two")

    machine = Machine()
    machine.register(first_state)
    machine.register(second_state)

    assert machine.start_at() == "state_one"
    assert machine.end_at() == "state_two"
    assert machine.last().terminal()

    assert machine.interpret(52) == 52

    compiled = machine.compile()

    expected = {
        "StartAt": "state_one",
        "States": {
            "state_one": {
                "Type": "Pass",
                "Next": "state_two",
                "End": False
            },
            "state_two": {
                "Type": "Pass",
                "End": True
            }
        }
    }

    assert compiled == expected
def test_duplicate_statename_triggers_operationalerror():

    first_state = Pass(name="test_state")
    second_state = Pass(name="test_state")

    machine = Machine()
    machine.register(first_state)

    with pytest.raises(OperationalError):
        machine.register(second_state)
def test_compile_pass_state():

    pass_expected = {
        "No-op": {
            "Type": "Pass",
            "Result": {
                "x": 0.381018,
                "y": 622.2269926397355
            },
            "End": True,
            "ResultPath": "$.result"
        }
    }

    result = Result(x=0.381018, y=622.2269926397355)

    pass_ = Pass(result=result, name="No-op", end=True)

    assert pass_.compile() == pass_expected

    machine = Machine()
    machine.register(pass_)

    assert machine.interpret() == result

    compiled_machine_expected = {
        "StartAt": "No-op",
        "States": {
            "No-op": {
                "Type": "Pass",
                "Result": {
                    "x": 0.381018,
                    "y": 622.2269926397355
                },
                "End": True,
                "ResultPath": "$.result"
            }
        }
    }

    assert machine.compile() == compiled_machine_expected
def test_register_duplicate_statename_with_force():

    first_state = Pass(name="test_state")
    second_state = Pass(name="test_state")

    machine = Machine()
    machine.register(first_state)
    machine.register(second_state, force=True)

    compiled = machine.compile()

    expected = {
        "StartAt": "test_state",
        "States": {
            "test_state": {
                "Type": "Pass",
                "End": True
            }
        }
    }

    assert compiled == expected
def test_toplevel():
    """
    A State Machine MUST have an object field named “States”, whose fields represent the states.

    A State Machine MUST have a string field named “StartAt”, whose value MUST exactly match one of names of the “States” fields. 
    The interpreter starts running the the machine at the named state.
    """

    machine = Machine()
    machine.register(Pass())
    compiled = machine.compile()

    assert "States" in compiled
    assert "StartAt" in compiled
def test_interpret_single_task(registry):

    task = Task(name="test_task",
                resource="add_with_defaults",
                registry=registry)

    assert task.interpret() == 6

    machine = Machine()
    machine.register(task)

    assert machine.interpret() == 6

    new_machine = Machine()
    pass_ = Pass(name="a_pass")
    new_machine.register(pass_)
    new_machine.register(task)

    input_ = Input(x=3)
    assert new_machine.interpret(input=input_) == 8