Skip to content

Commit

Permalink
raise exception when error appears in validate
Browse files Browse the repository at this point in the history
  • Loading branch information
mgonzs13 committed Oct 29, 2024
1 parent af4fd9f commit 4f90c89
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 33 deletions.
95 changes: 81 additions & 14 deletions yasmin/tests/python/test_state_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def test_add_state_with_wrong_outcome(self):
)
self.assertEqual(
str(context.exception),
"State 'FOO1' references unregistered outcomes: 'outcome9', available outcomes are: ['outcome1', 'outcome2']",
"State 'FOO1' references unregistered outcomes 'outcome9', available outcomes are ['outcome1', 'outcome2']",
)

def test_add_wrong_source_transition(self):
Expand Down Expand Up @@ -131,34 +131,101 @@ def test_add_wrong_target_transition(self):
str(context.exception), "Transitions with empty target in state 'FOO1'"
)

def test_validate_state_machine(self):
def test_validate_state_machine_outcome_from_fsm_not_used(self):

sm_1 = StateMachine(outcomes=["outcome4"])

sm_2 = StateMachine(outcomes=["outcome4", "outcome5"])
sm_1.add_state("FSM", sm_2)

sm_2.add_state(
"FOO",
FooState(),
transitions={
"outcome1": "outcome4",
"outcome2": "outcome4",
},
)
with self.assertRaises(Exception) as context:
sm_1.validate()
self.assertEqual(
str(context.exception),
"State 'FSM' outcome 'outcome5' not registered in transitions",
)

def test_validate_state_machine_outcome_from_state_not_used(self):

sm_1 = StateMachine(outcomes=["outcome4"])

sm_2 = StateMachine(outcomes=["outcome4"])
sm_1.add_state("FSM", sm_2)

sm_2.add_state(
"FOO",
FooState(),
transitions={
"outcome1": "outcome4",
},
)
with self.assertRaises(Exception) as context:
sm_1.validate()
self.assertEqual(
str(context.exception),
"State 'FOO' outcome 'outcome2' not registered in transitions",
)

def test_validate_state_machine_fsm_outcome_not_used(self):

sm_1 = StateMachine(outcomes=["outcome4"])

sm_2 = StateMachine(outcomes=["outcome4", "outcome5"])
sm_1.add_state(
"FSM",
sm_2,
transitions={
"outcome5": "outcome4",
},
)

sm_2.add_state(
"FOO",
FooState(),
transitions={
"outcome1": "outcome4",
"outcome2": "outcome4",
},
)
with self.assertRaises(Exception) as context:
sm_1.validate()
self.assertEqual(
str(context.exception),
"Target outcome 'outcome5' not registered in transitions",
)

def test_validate_state_machine_wrong_state(self):

sm_1 = StateMachine(outcomes=["outcome4"])

sm_2 = StateMachine(outcomes=["outcome4"])
sm_1.add_state(
"FSM",
sm_2,
transitions={
"outcome4": "outcome4",
},
)

sm_2.add_state(
"FOO",
FooState(),
transitions={
"outcome1": "BAR",
"outcome2": "outcome4",
},
)
with self.assertRaises(Exception) as context:
sm_1.validate()
self.assertEqual(
str(context.exception),
(
f"{'*' * 100}\nState machine failed validation check:"
"\n\tState 'FSM' outcome 'outcome5' not registered in transitions"
f"\n\tState machine 'FSM' failed validation check\n{'*' * 100}\n"
"State machine failed validation check:"
"\n\tState 'FOO' outcome 'outcome2' not registered in transitions"
"\n\tTarget outcome 'outcome4' not registered in transitions"
"\n\tTarget outcome 'outcome5' not registered in transitions"
"\n\tState machine outcome 'BAR' not registered as outcome neither state"
f"\n\n\tAvailable states: ['FOO']\n{'*' * 100}"
f"\n\n\tAvailable states: ['FSM']\n{'*' * 100}"
),
"State machine outcome 'BAR' not registered as outcome neither state",
)
33 changes: 14 additions & 19 deletions yasmin/yasmin/state_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def add_state(

if key not in state.get_outcomes():
raise Exception(
f"State '{name}' references unregistered outcomes: '{key}', available outcomes are: {state.get_outcomes()}"
f"State '{name}' references unregistered outcomes '{key}', available outcomes are {state.get_outcomes()}"
)

self._states[name] = {"state": state, "transitions": transitions}
Expand All @@ -74,14 +74,15 @@ def cancel_state(self) -> None:
if self.__current_state:
self._states[self.__current_state]["state"].cancel_state()

def validate(self, raise_exception: bool = True) -> str:
errors = ""
def validate(self) -> None:

# check initial state
if self._start_state is None:
errors += "\n\tNo initial state set."
raise Exception("No initial state set")
elif self._start_state not in self._states:
errors += f"\n\tInitial state label: '{self._start_state}' is not in the state machine."
raise Exception(
f"Initial state label: '{self._start_state}' is not in the state machine"
)

terminal_outcomes = []

Expand All @@ -96,17 +97,17 @@ def validate(self, raise_exception: bool = True) -> str:
# check if all state outcomes are in transitions
for o in outcomes:
if o not in set(list(transitions.keys()) + self.get_outcomes()):
errors += f"\n\tState '{state_name}' outcome '{o}' not registered in transitions"
raise Exception(
f"State '{state_name}' outcome '{o}' not registered in transitions"
)

# state outcomes that are in state machines out do not need transitions
elif o in self.get_outcomes():
terminal_outcomes.append(o)

# if sate is a state machine, validate it
if isinstance(state, StateMachine):
aux_errors = state.validate(False)
if aux_errors:
errors += f"\n\tState machine '{state_name}' failed validation check\n{aux_errors}"
state.validate()

# add terminal outcomes
terminal_outcomes.extend([transitions[key] for key in transitions])
Expand All @@ -117,20 +118,14 @@ def validate(self, raise_exception: bool = True) -> str:
# check if all state machine outcomes are in the terminal outcomes
for o in self.get_outcomes():
if o not in terminal_outcomes:
errors += f"\n\tTarget outcome '{o}' not registered in transitions"
raise Exception(f"Target outcome '{o}' not registered in transitions")

# check if all terminal outcomes are states or state machine outcomes
for o in terminal_outcomes:
if o not in set(list(self._states.keys()) + self.get_outcomes()):
errors += f"\n\tState machine outcome '{o}' not registered as outcome neither state"

if errors:
errors = f"{'*' * 100}\nState machine failed validation check:{errors}\n\n\tAvailable states: {list(self._states.keys())}\n{'*' * 100}"

if raise_exception:
raise Exception(errors)

return errors
raise Exception(
f"State machine outcome '{o}' not registered as outcome neither state"
)

def execute(self, blackboard: Blackboard) -> str:

Expand Down

0 comments on commit 4f90c89

Please sign in to comment.