def test_comments(): input = ''' // comment 0 /some_name // comment 1 off @BUTTON_PRESS -> on // comment 2 @TIMEOUT -> off // comment 3 not_really_off // comment 4 @SOME_EVENT -> ../off @THIRD_EVENT -> not_really_off/what // comment 5 what really_off @OTHER_EVENT -> ../on/what on @TIMEOUT ["i==3"] -> on/what [else] -> off/not_really_off/what what @OTHER -> ../off/really_off // comment 6 // comment 7 ''' parse(input)
def test_internal_transition_without_action(): input = ''' /some_name off #init "doSomething()" @TIMEOUT ["count == 3"] -> on @OTHER ["count == 6"] -- "set(6)" ["count == 4"] -> off [else] -- "set(7)" yes #init "start()" "stop()" #exit "stop()" "start()" @TO_OTHER -> other @OTHER -- "restart()" other on #exit "doSomethingElse()" @SOME -- @TIMEOUT -> off ''' with pytest.raises(ParsingError): parse(input)
def test_composite_state_names_not_unique(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off not_really_off @SOME_EVENT -> ../off @EVENT -> really_off @THIRD_EVENT -> not_really_off/what what really_off @OTHER_EVENT -> ../on/what not_really_off @OTHER -> ../on on @TIMEOUT ["i==3"] -> off/really_off [else] -> off/not_really_off/what what @OTHER -> ../on ''' with pytest.raises(DefinitionError) as exc: parse(input) assert 'state name not unique in state "off"' in str(exc.value)
def test_invalid_event_name(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off on @_TIMEOUT -> off ''' with pytest.raises(ParsingError): parse(input)
def test_wrong_indentation(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off on @TIMEOUT -> off ''' with pytest.raises(ParsingError): parse(input)
def test_only_else_guard(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT [else] -> on on @TIMEOUT -> off ''' with pytest.raises(ParsingError): parse(input)
def test_invalid_target_name(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off on @TIMEOUT -> offf ''' with pytest.raises(DefinitionError) as exc: parse(input) assert 'invalid transition target "offf" in state "on"' in str(exc.value)
def test_unreachable_state(): input = ''' /some_name off @BUTTON_PRESS -> off @TIMEOUT -> off on @TIMEOUT -> off ''' with pytest.raises(DefinitionError) as exc: parse(input) assert 'state "on" is unreachable' in str(exc.value)
def test_event_handlers_not_unique(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off @BUTTON_PRESS -> off on @TIMEOUT -> off ''' with pytest.raises(DefinitionError) as exc: parse(input) assert 'event handler not unique in state "off"' in str(exc.value)
def test_else_guard_not_unique(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT ["count == 3"] -> off [else] -> on [else] -> off on @TIMEOUT -> off ''' with pytest.raises(ParsingError): parse(input)
def test_states_to_ancestor(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off not_really_off @SOME_EVENT -> really_off what really_off @OTHER_EVENT -> not_really_off what @EVENT->final final on @TIMEOUT -> off ''' sc = parse(input) assert sc.states[0].states[0].states_to_ancestor(sc) == [sc.states[0]] assert sc.states[0].states[0].states[0].states_to_ancestor(sc) == [ sc.states[0].states[0], sc.states[0] ] assert sc.states[0].states[1].states[1].states_to_ancestor(sc) == [ sc.states[0].states[1], sc.states[0] ] assert sc.states[0].states[1].states[0].states_to_ancestor(sc) == [ sc.states[0].states[1], sc.states[0] ] assert sc.states[0].states[0].states_to_ancestor(sc.states[0]) == [] assert sc.states[0].states[0].states_to_ancestor( sc.states[0].states[0]) == []
def test_composite(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off not_really_off @SOME_EVENT -> really_off really_off @OTHER_EVENT -> not_really_off on @TIMEOUT -> off ''' sc = parse(input) assert sc.is_root assert sc.states[0].states[0].name == 'not_really_off' assert sc.states[0].states[1].name == 'really_off' assert not sc.states[0].is_root assert not sc.states[0].states[1].is_root assert sc.states[0].is_initial assert not sc.states[1].is_initial assert sc.states[1].is_atomic assert not sc.states[0].is_atomic assert sc.states[0].states[0].is_initial assert sc.states[0].states[0].is_atomic
def test_guard_not_unique(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT ["count == 3"] -> off ["count == 3"] -> on [else] -> off on @TIMEOUT -> off ''' with pytest.raises(DefinitionError) as exc: parse(input) assert 'guard not unique for event "TIMEOUT"' in str(exc.value)
def test_state_names_not_unique(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off on @TIMEOUT -> off off @TIMEOUT -> on ''' with pytest.raises(DefinitionError) as exc: parse(input) assert 'state name not unique in state "some_name"' in str(exc.value)
def test_transient_state_with_guard_not_unique(): input = ''' /some_name <>off ["count == 3"] -> on ["count == 4"] -> on ["count == 4"] -> on [else] -> on on @TIMEOUT -> off ''' with pytest.raises(DefinitionError) as exc: parse(input) assert 'guard not unique for event "None"' in str(exc.value)
def test_composite_reachable_state(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off not_really_off @SOME_EVENT -> ../off @THIRD_EVENT -> not_really_off/what what really_off @OTHER_EVENT -> ../on/what on @TIMEOUT ["i==3"] -> on/what [else] -> off/not_really_off/what what @OTHER -> ../off/really_off ''' parse(input)
def test_composite_unreachable_state(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off not_really_off @SOME_EVENT -> ../off @THIRD_EVENT -> not_really_off/what what really_off @OTHER_EVENT -> ../on/what on @TIMEOUT ["i==3"] -> on/what [else] -> off/not_really_off/what what @OTHER -> ../off ''' with pytest.raises(DefinitionError) as exc: parse(input) assert 'state "really_off" is unreachable' in str(exc.value)
def test_guard(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT ["count == 3"] -> off on @TIMEOUT -> off ''' sc = parse(input) assert sc.states[0].event_handlers[1].transitions[0].guard == 'count == 3'
def test_transient_state(): input = ''' /some_name <>off ["true"] -> on [else] -> off on @TIMEOUT -> off ''' sc = parse(input) assert sc.initial.is_transient assert not sc.is_transient assert not sc.states[1].is_transient
def test_simplest(): input = ''' /simplest off @BUTTON_PRESS -> on @TIMEOUT -> off on @TIMEOUT -> off ''' sc = parse(input) assert sc.name == 'simplest' assert len(sc.states) == 2 assert sc.states[0].name == 'off' assert sc.states[1].event_handlers[0].event == 'TIMEOUT'
def test_multiple_guards(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT ["count == 3"] -> off ["count == 4"] -> on [else] -> on on @TIMEOUT -> off ''' sc = parse(input) assert sc.states[0].event_handlers[1].transitions[0].guard == 'count == 3' assert sc.states[0].event_handlers[1].transitions[1].guard == 'count == 4' assert not sc.states[0].event_handlers[1].transitions[1].is_else_guard assert sc.states[0].event_handlers[1].transitions[2].is_else_guard
def test_path(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off not_really_off @SOME_EVENT -> really_off what really_off @OTHER_EVENT -> not_really_off on @TIMEOUT -> off ''' sc = parse(input) assert sc.states[0].path == 'some_name/off' assert sc.states[0].states[1].path == 'some_name/off/really_off' assert sc.states[0].states[0].states[ 0].path == 'some_name/off/not_really_off/what'
def test_all_states(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off not_really_off @SOME_EVENT -> really_off what really_off @OTHER_EVENT -> not_really_off on @TIMEOUT -> off ''' sc = parse(input) assert sc.all_states == [ sc, sc.states[0], sc.states[0].states[0], sc.states[0].states[0].states[0], sc.states[0].states[1], sc.states[1] ]
def test_internal_external_transition(): input = ''' /some_name off #init "doSomething()" @TIMEOUT ["count == 3"] -> on @OTHER ["count == 6"] -- "set(6)" ["count == 4"] -> off [else] -- "set(7)" yes #init "start()" "stop()" #exit "stop()" "start()" @TO_OTHER -> other @WHAT -- "restart()" other on #exit "doSomethingElse()" @SOME -- "wait()" @TIMEOUT -> off ''' sc = parse(input) assert sc.states[0].transitions[1].is_internal assert sc.states[0].transitions[1].actions == ['set(6)'] assert not sc.states[0].transitions[2].is_internal assert sc.states[0].transitions[3].is_internal assert sc.states[0].states[0].transitions[1].is_internal assert sc.states[0].states[0].transitions[1].actions == ['restart()'] assert sc.states[1].transitions[0].is_internal
def test_actions(): input = ''' /some_name #init "bonjour()" #exit "auRevoir()" off #init "doSomething()" @TIMEOUT ["count == 3"] -> on <>half_off ["count == 6"] -> other "set(6)" [else] -> yes "set(7)" yes #init "start()" "stop()" #exit "stop()" "start()" other on #exit "doSomethingElse()" @TIMEOUT -> off ''' sc = parse(input) assert sc.init_actions == ['bonjour()'] assert sc.exit_actions == ['auRevoir()'] assert sc.states[0].init_actions == ['doSomething()'] assert sc.states[0].states[0].transitions[0].actions == ['set(6)'] assert sc.states[0].states[0].transitions[1].actions == ['set(7)'] assert sc.states[1].exit_actions == ['doSomethingElse()'] assert sc.states[0].states[1].init_actions == ['start()', 'stop()'] assert sc.states[0].states[1].exit_actions == ['stop()', 'start()']
def test_common_ancestor(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off not_really_off @SOME_EVENT -> really_off what really_off @OTHER_EVENT -> not_really_off on @TIMEOUT -> off ''' sc = parse(input) assert sc.common_ancestor(sc) is sc assert sc.states[0].states[0].common_ancestor( sc.states[0].states[0]) is sc.states[0].states[0] assert sc.states[0].states[0].common_ancestor( sc.states[0].states[1]) is sc.states[0] assert sc.states[0].states[1].common_ancestor( sc.states[0].states[0].states[0]) is sc.states[0]
def test_state_paths(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off not_really_off @SOME_EVENT -> really_off what really_off @OTHER_EVENT -> not_really_off on @TIMEOUT -> off ''' sc = parse(input) assert list(sc.state_paths.values()) == list(sc.all_states) assert list(sc.state_paths.keys()) == [ 'some_name', 'some_name/off', 'some_name/off/not_really_off', 'some_name/off/not_really_off/what', 'some_name/off/really_off', 'some_name/on' ] assert sc.state_paths is sc.states[0].state_paths
def test_path_elements(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off not_really_off @SOME_EVENT -> really_off what really_off @OTHER_EVENT -> not_really_off on @TIMEOUT -> off ''' sc = parse(input) assert sc.states[0].path_elements == ['some_name', 'off'] assert sc.states[0].states[1].path_elements == [ 'some_name', 'off', 'really_off' ] assert sc.states[0].states[0].states[0].path_elements == [ 'some_name', 'off', 'not_really_off', 'what' ]
def test_composite_valid_target_path(): input = ''' /some_name off @BUTTON_PRESS -> on @TIMEOUT -> off not_really_off @SOME_EVENT -> ../off @EVENT -> really_off @THIRD_EVENT -> not_really_off/what what really_off @OTHER_EVENT -> ../on/what on @TIMEOUT ["i==3"] -> off/really_off [else] -> off/not_really_off/what what @OTHER -> ../on ''' sc = parse(input) assert sc.states[0].states[0].transitions[ 2].target.path == 'some_name/off/not_really_off/what'
def test_event_names(input, events): sc = parse(input) assert sc.event_names == set(events)