From 29c729d510c7b7f97c721cf9a23f38fd56ba8bf9 Mon Sep 17 00:00:00 2001 From: Leander von Seelstrang Date: Tue, 5 Dec 2023 11:21:13 +0100 Subject: [PATCH 1/2] Added state not reached warning. --- .../clf/bonsai/engine/LoadingResults.java | 8 ++ .../clf/bonsai/engine/SCXMLValidator.java | 109 +++++++++++++++++- .../StateMachineConfiguratorResults.java | 25 ++++ .../engine/scxml/config/ValidationResult.java | 4 + 4 files changed, 145 insertions(+), 1 deletion(-) diff --git a/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/LoadingResults.java b/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/LoadingResults.java index d3b31f2c..e013e73a 100644 --- a/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/LoadingResults.java +++ b/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/LoadingResults.java @@ -1,6 +1,7 @@ package de.unibi.citec.clf.bonsai.engine; import de.unibi.citec.clf.bonsai.core.configuration.ConfigurationResults; +import de.unibi.citec.clf.bonsai.engine.model.StateID; import de.unibi.citec.clf.bonsai.engine.scxml.config.StateMachineConfiguratorResults; import de.unibi.citec.clf.bonsai.engine.scxml.config.ValidationResult; import de.unibi.citec.clf.bonsai.engine.scxml.exception.LoadingException; @@ -50,6 +51,13 @@ public String toString() { out += "\n" + l.getMessage(); } } + if (!validationResult.unreachedStates.isEmpty()) { + out += "#### Unreached States Warnings:\n"; + for (StateID state : validationResult.unreachedStates) { + out += state.toString() + "\n"; + // System.out.println(state.getFullSkill()); + } + } return out; } diff --git a/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/SCXMLValidator.java b/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/SCXMLValidator.java index 84e5ace6..b62e4c88 100644 --- a/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/SCXMLValidator.java +++ b/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/SCXMLValidator.java @@ -109,6 +109,9 @@ private ValidationResult validateAll(SCXML aSCXML, Map> boolean isValid = results.transitionNotFoundException.isEmpty(); + // Set unreachedStates = unreachedStates(aSCXML); + results.unreachedStates = unreachedStates(aSCXML); + for (String id : map.keySet()) { logger.debug("Found TransitionTarget: " + id); @@ -124,7 +127,7 @@ private ValidationResult validateAll(SCXML aSCXML, Map> continue; } StateID state = new StateID(prefix, id); - // if state does not exists, no need to check transitions + // if state does not exist, no need to check transitions try { if (vExistance) { isValid &= validateExistance(state); @@ -389,4 +392,108 @@ private List validateTransitions(StateID state, State currentSt return errors; } + + /** + * Finds and returns a set of unreached states in the given SCXML. + * + * @param aSCXML The SCXML to analyze. + * @return A set of unreached states. + */ + public Set unreachedStates(SCXML aSCXML) throws StateIDException { + Set allStates = getAllStates(aSCXML); + Set reachedStates = getReachedStates(aSCXML); + + Set unreachedStates = new HashSet<>(allStates); + unreachedStates.removeAll(reachedStates); + + logger.error("UNREACHED STATE IDs: " + unreachedStates); + + return unreachedStates; + } + + /** + * Retrieves a set of all states in the given SCXML. + * + * @param aSCXML The SCXML to analyze. + * @return A set of all states. + */ + private Set getAllStates(SCXML aSCXML) throws StateIDException { + Set allStates = new HashSet<>(); + + Map map = aSCXML.getTargets(); + for (String id : map.keySet()) { + if (map.get(id) instanceof State) { + State currentState = (State) map.get(id); + allStates.add(new StateID(prefix, id)); + } + } + return allStates; + } + + /** + * Retrieves a set of reached states in the given SCXML. + * + * @param aSCXML The SCXML to analyze. + * @return A set of reached states. + */ + private Set getReachedStates(SCXML aSCXML) { + Set reachedStates = new HashSet<>(); + + Map map = aSCXML.getTargets(); + for (String id : map.keySet()) { + TransitionTarget target = map.get(id); + + // Add post-states of transitions + target.getTransitionsList().forEach(t -> { + Transition transition = (Transition) t; + String postStateId = transition.getNext(); + if (postStateId != null) { + try { + // System.out.println("DELME postStateId: " + postStateId); + reachedStates.add(new StateID(prefix, postStateId)); + } catch (StateIDException e) { + throw new RuntimeException(e); + } + } + }); + + // Add post-states of onEntry actions + OnEntry onEntry = target.getOnEntry(); + if (onEntry != null) { + onEntry.getActions().forEach(action -> { + if (action instanceof TransitionTarget) { + String postStateId = ((TransitionTarget) action).getId(); + if (postStateId != null) { + try { + reachedStates.add(new StateID(prefix, postStateId)); + } catch (StateIDException e) { + throw new RuntimeException(e); + } + } + } + }); + } + + // Add post-states of onExit actions + OnExit onExit = target.getOnExit(); + if (onExit != null) { + onExit.getActions().forEach(action -> { + if (action instanceof TransitionTarget) { + String postStateId = ((TransitionTarget) action).getId(); + if (postStateId != null) { + try { + reachedStates.add(new StateID(prefix, postStateId)); + } catch (StateIDException e) { + throw new RuntimeException(e); + } + } + } + }); + } + } + + // System.out.println("Reached states: " + reachedStates); + return reachedStates; + } + } diff --git a/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/scxml/config/StateMachineConfiguratorResults.java b/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/scxml/config/StateMachineConfiguratorResults.java index bf7186a3..948c5869 100644 --- a/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/scxml/config/StateMachineConfiguratorResults.java +++ b/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/scxml/config/StateMachineConfiguratorResults.java @@ -1,6 +1,7 @@ package de.unibi.citec.clf.bonsai.engine.scxml.config; import de.unibi.citec.clf.bonsai.core.exception.StateIDException; +import de.unibi.citec.clf.bonsai.engine.model.StateID; import de.unibi.citec.clf.bonsai.engine.scxml.SkillConfigFaults; import java.util.HashSet; @@ -49,6 +50,30 @@ public boolean success(boolean warn) { return (warn) ? errors + warnings == 0 : errors == 0; } + + public String generateUnreachedWarning(Set unreachedStates, boolean warnings) { + StringBuilder output = new StringBuilder(); + boolean gen = false; + boolean warn = false; + for (SkillConfigFaults e : stateMachineConfigErrors) { + if (!e.getNoSlotDefinitions().isEmpty()) { + gen = true; + } + if (warnings && !e.getDefaultSlotWarnings().isEmpty()) { + warn = true; + } + } + if (gen || warn) { + if (!unreachedStates.isEmpty()) { + output.append("Unreached States:\n"); + for (StateID state : unreachedStates) { + output.append(state.getCanonicalSkill() + "\n"); + } + } + } + return output.toString(); + } + public String generateSlotHint(String prefixToRemove, boolean warnings) { StringBuilder output = new StringBuilder(); boolean gen = false; diff --git a/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/scxml/config/ValidationResult.java b/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/scxml/config/ValidationResult.java index 8346b6fd..a9074a17 100644 --- a/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/scxml/config/ValidationResult.java +++ b/bonsai_scxml_engine/src/main/java/de/unibi/citec/clf/bonsai/engine/scxml/config/ValidationResult.java @@ -1,6 +1,8 @@ package de.unibi.citec.clf.bonsai.engine.scxml.config; +import de.unibi.citec.clf.bonsai.engine.model.StateID; import de.unibi.citec.clf.bonsai.engine.scxml.exception.StateNotFoundException; +// import de.unibi.citec.clf.bonsai.engine.scxml.exception.StateNotReachedWarning; import java.util.ArrayList; import java.util.HashSet; @@ -15,6 +17,8 @@ public class ValidationResult { public Set stateNotFoundException = new HashSet<>(); public Set transitionNotFoundException = new HashSet<>(); + public Set unreachedStates = new HashSet<>(); + public boolean success() { boolean valid = stateNotFoundException.isEmpty(); for (TransitionError t : transitionNotFoundException) { From fcab134a944e1e79ac6aa8cec9c935dccec0eae2 Mon Sep 17 00:00:00 2001 From: Leander von Seelstrang Date: Wed, 17 Jan 2024 20:58:41 +0100 Subject: [PATCH 2/2] Added missing incoming transition test state machine + assertion --- .../bonsai/engine/scxml/StatemachineTest.java | 17 ++++++ .../missingIncomingTransition.xml | 52 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100755 bonsai_scxml_engine/src/test/resources/state_machines/missingIncomingTransition.xml diff --git a/bonsai_scxml_engine/src/test/java/de/unibi/citec/clf/bonsai/engine/scxml/StatemachineTest.java b/bonsai_scxml_engine/src/test/java/de/unibi/citec/clf/bonsai/engine/scxml/StatemachineTest.java index 47554f1a..bf273d46 100644 --- a/bonsai_scxml_engine/src/test/java/de/unibi/citec/clf/bonsai/engine/scxml/StatemachineTest.java +++ b/bonsai_scxml_engine/src/test/java/de/unibi/citec/clf/bonsai/engine/scxml/StatemachineTest.java @@ -122,6 +122,23 @@ public void testMissingTransition() throws TransformerException, TimeoutExceptio assertEquals(0,res.loadingExceptions.size()); } + @Test + public void testMissingIncomingTransition() throws TransformerException, TimeoutException { + final String sm = "missingIncomingTransition.xml"; + + LoadingResults res = TestTools.loadStatemachine(sm); + + assertFalse(res.success()); + + assertEquals(0,res.configurationResults.getConfigurationExceptions().size()); + assertEquals(0,res.configurationResults.otherExceptions.size()); + assertEquals(0,res.validationResult.transitionNotFoundException.size()); + assertEquals(1,res.validationResult.unreachedStates.size()); + assertEquals(0,res.stateMachineResults.numErrors()); + assertEquals(0,res.stateMachineResults.numWarnings()); + assertEquals(0,res.loadingExceptions.size()); + } + @Test public void testMissingParameter() throws TransformerException, TimeoutException { final String sm = "missingParameter.xml"; diff --git a/bonsai_scxml_engine/src/test/resources/state_machines/missingIncomingTransition.xml b/bonsai_scxml_engine/src/test/resources/state_machines/missingIncomingTransition.xml new file mode 100755 index 00000000..4d3b5473 --- /dev/null +++ b/bonsai_scxml_engine/src/test/resources/state_machines/missingIncomingTransition.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +