From ed74a44c292d0eca70dee9cfef5ea80d9ffd3345 Mon Sep 17 00:00:00 2001 From: Kamil Patryk Kozakowski Date: Fri, 17 Jul 2026 07:58:42 +0200 Subject: [PATCH] B --- .../enricher/CallChainLinkPolicy.java | 3 +- .../enricher/CallChainPolyNarrower.java | 3 +- .../enricher/TransitionLinkerEnricher.java | 3 +- .../HeuristicEventMatchingEngine.java | 8 +- .../resolver/BooleanConstraintEvaluator.java | 12 +- .../analysis/resolver/ConstraintClauses.java | 126 ++++++++++++++++++ .../service/AbstractCallGraphEngine.java | 3 +- .../service/CarrierConstraintSupport.java | 97 +------------- .../service/ExternalTriggerPolicy.java | 9 +- .../AnalysisCanonicalFormValidator.java | 3 +- .../resolver/ConstraintClausesTest.java | 49 +++++++ .../service/CarrierConstraintSupportTest.java | 17 +-- 12 files changed, 201 insertions(+), 132 deletions(-) create mode 100644 state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/ConstraintClauses.java create mode 100644 state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/ConstraintClausesTest.java diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/CallChainLinkPolicy.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/CallChainLinkPolicy.java index 5418a88..3153745 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/CallChainLinkPolicy.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/CallChainLinkPolicy.java @@ -5,6 +5,7 @@ import click.kamil.springstatemachineexporter.analysis.model.EntryPoint; import click.kamil.springstatemachineexporter.analysis.model.LinkResolution; import click.kamil.springstatemachineexporter.analysis.model.MatchedTransition; import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint; +import click.kamil.springstatemachineexporter.analysis.resolver.DynamicTriggerExpressions; import click.kamil.springstatemachineexporter.analysis.resolver.MachineEnumCanonicalizer; import click.kamil.springstatemachineexporter.analysis.resolver.StateMachineTypeResolver; import click.kamil.springstatemachineexporter.analysis.service.ExternalTriggerPolicy; @@ -141,7 +142,7 @@ public final class CallChainLinkPolicy { if (event != null && event.startsWith("ENUM_SET:")) { return true; } - return MachineEnumCanonicalizer.isDynamicTriggerExpression(event); + return DynamicTriggerExpressions.isDynamic(event); } /** diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/CallChainPolyNarrower.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/CallChainPolyNarrower.java index f8be14d..293ce4e 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/CallChainPolyNarrower.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/CallChainPolyNarrower.java @@ -4,6 +4,7 @@ import click.kamil.springstatemachineexporter.analysis.enricher.path.SymbolicPat import click.kamil.springstatemachineexporter.analysis.model.CallChain; import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint; import click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver; +import click.kamil.springstatemachineexporter.analysis.resolver.DynamicTriggerExpressions; import click.kamil.springstatemachineexporter.analysis.resolver.MachineEnumCanonicalizer; import click.kamil.springstatemachineexporter.analysis.resolver.StateMachineTypeResolver; import click.kamil.springstatemachineexporter.analysis.service.EventCarrierPolicy; @@ -140,7 +141,7 @@ public final class CallChainPolyNarrower { if (event == null || event.isBlank()) { return; } - if (MachineEnumCanonicalizer.isDynamicTriggerExpression(event)) { + if (DynamicTriggerExpressions.isDynamic(event)) { return; } addEnumReference(event, configuredConstants, votes, STRONG); diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/TransitionLinkerEnricher.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/TransitionLinkerEnricher.java index 5921ca2..3ef60e6 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/TransitionLinkerEnricher.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/TransitionLinkerEnricher.java @@ -30,6 +30,7 @@ import click.kamil.springstatemachineexporter.analysis.enricher.routing.BeanReso import click.kamil.springstatemachineexporter.analysis.enricher.routing.HeuristicBeanResolutionEngine; import click.kamil.springstatemachineexporter.analysis.enricher.routing.SharedServiceRoutingPolicy; import click.kamil.springstatemachineexporter.analysis.resolver.BooleanConstraintEvaluator; +import click.kamil.springstatemachineexporter.analysis.resolver.DynamicTriggerExpressions; import click.kamil.springstatemachineexporter.analysis.resolver.MachineEnumCanonicalizer; import click.kamil.springstatemachineexporter.analysis.resolver.StateMachineTypeResolver; @@ -359,7 +360,7 @@ public class TransitionLinkerEnricher implements AnalysisEnricher { if (!messaging) { return false; } - if (!MachineEnumCanonicalizer.isDynamicTriggerExpression(trigger.getEvent())) { + if (!DynamicTriggerExpressions.isDynamic(trigger.getEvent())) { return false; } // Expander variants carry concrete payload bindings (same channel as REST pathBindings). diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/matching/HeuristicEventMatchingEngine.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/matching/HeuristicEventMatchingEngine.java index a411012..134ad90 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/matching/HeuristicEventMatchingEngine.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/matching/HeuristicEventMatchingEngine.java @@ -1,6 +1,7 @@ package click.kamil.springstatemachineexporter.analysis.enricher.matching; import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint; +import click.kamil.springstatemachineexporter.analysis.resolver.DynamicTriggerExpressions; import click.kamil.springstatemachineexporter.model.Event; import java.util.List; @@ -27,7 +28,7 @@ public class HeuristicEventMatchingEngine implements EventMatchingEngine { String smEventRaw = stateMachineEvent.fullIdentifier() != null ? stateMachineEvent.fullIdentifier() : stateMachineEvent.rawName(); String smEvent = simplify(smEventRaw); - boolean isWildcard = isWildcardVariable(rawTriggerEvent); + boolean isWildcard = DynamicTriggerExpressions.isDynamic(rawTriggerEvent); List polyEvents = triggerPoint.getPolymorphicEvents() != null ? triggerPoint.getPolymorphicEvents() : java.util.Collections.emptyList(); @@ -156,11 +157,6 @@ public class HeuristicEventMatchingEngine implements EventMatchingEngine { return smNormalized.matches(".*" + pattern2 + ".*") || triggerNormalized.matches(".*" + pattern1 + ".*"); } - private boolean isWildcardVariable(String eventStr) { - return click.kamil.springstatemachineexporter.analysis.resolver.DynamicTriggerExpressions - .isDynamic(eventStr); - } - private String simplify(String name) { if (name == null) return null; if (simplifyCache.containsKey(name)) return simplifyCache.get(name); diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluator.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluator.java index b5205fa..83fa1a1 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluator.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluator.java @@ -116,7 +116,7 @@ public final class BooleanConstraintEvaluator { if (bindings == null || bindings.isEmpty()) { return true; } - Set equalityVars = extractEqualityVariables(constraint); + Set equalityVars = ConstraintClauses.equalityVariables(constraint); for (String varName : equalityVars) { if (!bindings.containsKey(varName)) { if (ignoreUnboundEqualityVars) { @@ -354,16 +354,6 @@ public final class BooleanConstraintEvaluator { return -1; } - private static Set extractEqualityVariables(String constraint) { - Set vars = new HashSet<>(); - Pattern pattern = Pattern.compile("([a-zA-Z][\\w]*)\\s*=="); - Matcher matcher = pattern.matcher(constraint); - while (matcher.find()) { - vars.add(matcher.group(1)); - } - return vars; - } - private static String substituteVariableBindings(String expr, String varName, String boundValue) { if (boundValue == null || boundValue.isBlank()) { return expr; diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/ConstraintClauses.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/ConstraintClauses.java new file mode 100644 index 0000000..18dd601 --- /dev/null +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/resolver/ConstraintClauses.java @@ -0,0 +1,126 @@ +package click.kamil.springstatemachineexporter.analysis.resolver; + +import click.kamil.springstatemachineexporter.analysis.service.EventCarrierPolicy; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Shared AND-clause splitting and primary-identifier extraction for constraint strings + * emitted by the analysis pipeline (carrier strip, binding compatibility). + */ +public final class ConstraintClauses { + + private static final Pattern EQUALS_CALL = Pattern.compile( + "(?i)(?:\"[^\"]+\"|'[^']+')\\s*\\.\\s*(?:equalsIgnoreCase|equals)\\s*\\(\\s*([A-Za-z_][A-Za-z0-9_]*)\\s*\\)" + + "|" + + "(?i)([A-Za-z_][A-Za-z0-9_]*)\\s*\\.\\s*(?:equalsIgnoreCase|equals)\\s*\\(\\s*(?:\"[^\"]+\"|'[^']+')\\s*\\)"); + + private static final Pattern EQ_COMPARE = Pattern.compile( + "(?i)([A-Za-z_][A-Za-z0-9_]*)\\s*(?:==|!=)\\s*(?:\"[^\"]+\"|'[^']+'|[A-Za-z_][A-Za-z0-9_.]*)" + + "|" + + "(?i)(?:\"[^\"]+\"|'[^']+'|[A-Za-z_][A-Za-z0-9_.]*)\\s*(?:==|!=)\\s*([A-Za-z_][A-Za-z0-9_]*)"); + + private ConstraintClauses() { + } + + /** + * Splits a constraint on top-level {@code &&} (paren-aware). + */ + public static List splitAndClauses(String constraint) { + List clauses = new ArrayList<>(); + if (constraint == null || constraint.isBlank()) { + return clauses; + } + StringBuilder current = new StringBuilder(); + int depth = 0; + for (int i = 0; i < constraint.length(); i++) { + char c = constraint.charAt(i); + if (c == '(') { + depth++; + current.append(c); + continue; + } + if (c == ')') { + depth = Math.max(0, depth - 1); + current.append(c); + continue; + } + if (depth == 0 + && c == '&' + && i + 1 < constraint.length() + && constraint.charAt(i + 1) == '&') { + String piece = current.toString().trim(); + if (!piece.isEmpty()) { + clauses.add(piece); + } + current.setLength(0); + i++; + continue; + } + current.append(c); + } + String tail = current.toString().trim(); + if (!tail.isEmpty()) { + clauses.add(tail); + } + if (clauses.isEmpty() && !constraint.isBlank()) { + clauses.add(constraint.trim()); + } + return clauses; + } + + /** + * Primary parameter/local identifier in a comparison or equals clause. + */ + public static String primaryIdent(String clause) { + if (clause == null || clause.isBlank()) { + return null; + } + String trimmed = clause.trim(); + Matcher equals = EQUALS_CALL.matcher(trimmed); + if (equals.find()) { + String a = equals.group(1); + String b = equals.group(2); + return a != null ? a : b; + } + Matcher eq = EQ_COMPARE.matcher(trimmed); + if (eq.find()) { + String a = eq.group(1); + String b = eq.group(2); + String left = a != null ? a : b; + if (left != null && looksLikeSimpleIdent(left)) { + return left; + } + } + return null; + } + + /** + * Union of primary identifiers across AND clauses (for binding overlap checks). + */ + public static Set equalityVariables(String constraint) { + Set vars = new LinkedHashSet<>(); + for (String clause : splitAndClauses(constraint)) { + String ident = primaryIdent(clause); + if (ident != null) { + vars.add(ident); + } + } + return vars; + } + + private static boolean looksLikeSimpleIdent(String value) { + if (value == null || value.isBlank() || value.contains(".")) { + return false; + } + char first = value.charAt(0); + return Character.isJavaIdentifierStart(first) + && value.chars().allMatch(Character::isJavaIdentifierPart) + && (Character.isLowerCase(first) || EventCarrierPolicy.isCarrierParamName(value)); + } +} diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/AbstractCallGraphEngine.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/AbstractCallGraphEngine.java index 38e99ab..6823588 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/AbstractCallGraphEngine.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/AbstractCallGraphEngine.java @@ -13,6 +13,7 @@ import click.kamil.springstatemachineexporter.analysis.model.EntryPoint; import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint; import click.kamil.springstatemachineexporter.ast.common.CodebaseContext; import click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver; +import click.kamil.springstatemachineexporter.analysis.resolver.DynamicTriggerExpressions; import click.kamil.springstatemachineexporter.analysis.resolver.MachineEnumCanonicalizer; import lombok.extern.slf4j.Slf4j; import org.eclipse.jdt.core.dom.*; @@ -1237,7 +1238,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine { .anyMatch(pe -> pe != null && !pe.startsWith(" pe != null && pe.startsWith(" kept = new ArrayList<>(); - for (String clause : splitAndClauses(constraint)) { - String ident = primaryIdent(clause); + for (String clause : ConstraintClauses.splitAndClauses(constraint)) { + String ident = ConstraintClauses.primaryIdent(clause); if (ident != null && EventCarrierPolicy.isCarrierParamName(ident)) { kept.add("true"); continue; @@ -82,8 +71,8 @@ public final class CarrierConstraintSupport { private static Set carrierPrimaryIdents(String constraint) { Set idents = new LinkedHashSet<>(); - for (String clause : splitAndClauses(constraint)) { - String ident = primaryIdent(clause); + for (String clause : ConstraintClauses.splitAndClauses(constraint)) { + String ident = ConstraintClauses.primaryIdent(clause); if (ident != null && EventCarrierPolicy.isCarrierParamName(ident)) { idents.add(ident); } @@ -100,82 +89,6 @@ public final class CarrierConstraintSupport { return false; } - static List splitAndClauses(String constraint) { - List clauses = new ArrayList<>(); - StringBuilder current = new StringBuilder(); - int depth = 0; - for (int i = 0; i < constraint.length(); i++) { - char c = constraint.charAt(i); - if (c == '(') { - depth++; - current.append(c); - continue; - } - if (c == ')') { - depth = Math.max(0, depth - 1); - current.append(c); - continue; - } - if (depth == 0 - && c == '&' - && i + 1 < constraint.length() - && constraint.charAt(i + 1) == '&') { - String piece = current.toString().trim(); - if (!piece.isEmpty()) { - clauses.add(piece); - } - current.setLength(0); - i++; - continue; - } - current.append(c); - } - String tail = current.toString().trim(); - if (!tail.isEmpty()) { - clauses.add(tail); - } - if (clauses.isEmpty() && constraint != null && !constraint.isBlank()) { - clauses.add(constraint.trim()); - } - return clauses; - } - - /** - * Primary parameter/local identifier in a comparison or equals clause. - */ - static String primaryIdent(String clause) { - if (clause == null || clause.isBlank()) { - return null; - } - String trimmed = clause.trim(); - Matcher equals = EQUALS_CALL.matcher(trimmed); - if (equals.find()) { - String a = equals.group(1); - String b = equals.group(2); - return a != null ? a : b; - } - Matcher eq = EQ_COMPARE.matcher(trimmed); - if (eq.find()) { - String a = eq.group(1); - String b = eq.group(2); - String left = a != null ? a : b; - if (left != null && looksLikeSimpleIdent(left)) { - return left; - } - } - return null; - } - - private static boolean looksLikeSimpleIdent(String value) { - if (value == null || value.isBlank() || value.contains(".")) { - return false; - } - char first = value.charAt(0); - return Character.isJavaIdentifierStart(first) - && value.chars().allMatch(Character::isJavaIdentifierPart) - && (Character.isLowerCase(first) || EventCarrierPolicy.isCarrierParamName(value)); - } - private static String joinAndTidy(List clauses) { if (clauses.isEmpty()) { return ""; diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ExternalTriggerPolicy.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ExternalTriggerPolicy.java index 86a085d..c54bddb 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ExternalTriggerPolicy.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ExternalTriggerPolicy.java @@ -2,6 +2,7 @@ package click.kamil.springstatemachineexporter.analysis.service; import click.kamil.springstatemachineexporter.analysis.model.EntryPoint; import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint; +import click.kamil.springstatemachineexporter.analysis.resolver.DynamicTriggerExpressions; import click.kamil.springstatemachineexporter.analysis.resolver.MachineEnumCanonicalizer; import click.kamil.springstatemachineexporter.ast.common.CodebaseContext; import org.eclipse.jdt.core.dom.*; @@ -27,7 +28,7 @@ public final class ExternalTriggerPolicy { return false; } if (entryPoint != null && entryPointHasUnboundPlaceholders(entryPoint) - && MachineEnumCanonicalizer.isDynamicTriggerExpression(trigger.getEvent())) { + && DynamicTriggerExpressions.isDynamic(trigger.getEvent())) { String paramName = resolveRestEventParameterName(entryPoint, resolvedEventParamName); if (paramName != null) { RestParamBinding binding = findRestParameterBinding(entryPoint, paramName, context); @@ -70,7 +71,7 @@ public final class ExternalTriggerPolicy { } } if (entryPoint.getName() != null && entryPointHasUnboundPlaceholders(entryPoint) - && MachineEnumCanonicalizer.isDynamicTriggerExpression(trigger.getEvent())) { + && DynamicTriggerExpressions.isDynamic(trigger.getEvent())) { if (paramName != null) { RestParamBinding pathBinding = findRestParameterBinding(entryPoint, paramName, context); if (pathBinding != null && pathBinding.pathVariable() && pathBinding.enumType()) { @@ -95,7 +96,7 @@ public final class ExternalTriggerPolicy { return false; } } - if (MachineEnumCanonicalizer.isDynamicTriggerExpression(trigger.getEvent()) + if (DynamicTriggerExpressions.isDynamic(trigger.getEvent()) && !hasConcreteSinglePoly(trigger)) { // Unbound messaging payload feeding valueOf/switch — treat like unbound REST event param. return true; @@ -119,7 +120,7 @@ public final class ExternalTriggerPolicy { } if (entryPoint != null && entryPoint.getType() == EntryPoint.Type.REST && !entryPointHasUnboundPlaceholders(entryPoint) - && MachineEnumCanonicalizer.isDynamicTriggerExpression(trigger.getEvent())) { + && DynamicTriggerExpressions.isDynamic(trigger.getEvent())) { return false; } return trigger.isExternal(); diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/validation/AnalysisCanonicalFormValidator.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/validation/AnalysisCanonicalFormValidator.java index 8562728..1094192 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/validation/AnalysisCanonicalFormValidator.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/validation/AnalysisCanonicalFormValidator.java @@ -5,6 +5,7 @@ import click.kamil.springstatemachineexporter.analysis.model.CallChain; import click.kamil.springstatemachineexporter.analysis.model.LifecycleTriggerMarkers; import click.kamil.springstatemachineexporter.analysis.model.MatchedTransition; import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint; +import click.kamil.springstatemachineexporter.analysis.resolver.DynamicTriggerExpressions; import click.kamil.springstatemachineexporter.analysis.resolver.MachineEnumCanonicalizer; import click.kamil.springstatemachineexporter.analysis.resolver.StateMachineTypeResolver; import click.kamil.springstatemachineexporter.ast.common.CodebaseContext; @@ -483,7 +484,7 @@ public final class AnalysisCanonicalFormValidator { } if (trigger.isExternal() && trigger.isAmbiguous() - && MachineEnumCanonicalizer.isDynamicTriggerExpression(event) + && DynamicTriggerExpressions.isDynamic(event) && (trigger.getPolymorphicEvents() == null || trigger.getPolymorphicEvents().isEmpty())) { return true; } diff --git a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/ConstraintClausesTest.java b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/ConstraintClausesTest.java new file mode 100644 index 0000000..7e569b7 --- /dev/null +++ b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/ConstraintClausesTest.java @@ -0,0 +1,49 @@ +package click.kamil.springstatemachineexporter.analysis.resolver; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ConstraintClausesTest { + + @Test + void splitAndClausesSplitsTopLevelAnd() { + assertThat(ConstraintClauses.splitAndClauses( + "\"PAY\".equalsIgnoreCase(message) && message == \"PAY\"")) + .containsExactly( + "\"PAY\".equalsIgnoreCase(message)", + "message == \"PAY\""); + } + + @Test + void splitAndClausesKeepsNestedAndInsideParens() { + assertThat(ConstraintClauses.splitAndClauses( + "(a == 1 && b == 2) && c == 3")) + .containsExactly("(a == 1 && b == 2)", "c == 3"); + } + + @Test + void primaryIdentExtractsEqualsIgnoreCaseArgument() { + assertThat(ConstraintClauses.primaryIdent("\"PAY\".equalsIgnoreCase(message)")) + .isEqualTo("message"); + } + + @Test + void primaryIdentExtractsEqLeftOperand() { + assertThat(ConstraintClauses.primaryIdent("message == \"PAY\"")) + .isEqualTo("message"); + } + + @Test + void primaryIdentExtractsReceiverOfEqualsCall() { + assertThat(ConstraintClauses.primaryIdent("machineType.equals(\"ORDER\")")) + .isEqualTo("machineType"); + } + + @Test + void equalityVariablesUnionsPrimaryIdentsAcrossClauses() { + assertThat(ConstraintClauses.equalityVariables( + "\"ORDER\".equalsIgnoreCase(machineType) && message == \"PAY\"")) + .containsExactly("machineType", "message"); + } +} diff --git a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/CarrierConstraintSupportTest.java b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/CarrierConstraintSupportTest.java index e830848..fe66e69 100644 --- a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/CarrierConstraintSupportTest.java +++ b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/CarrierConstraintSupportTest.java @@ -1,5 +1,6 @@ package click.kamil.springstatemachineexporter.analysis.service; +import click.kamil.springstatemachineexporter.analysis.resolver.ConstraintClauses; import org.junit.jupiter.api.Test; import java.util.Map; @@ -28,8 +29,8 @@ class CarrierConstraintSupportTest { void stripMixedLeavesOnlyDomainClauseMeaningfully() { String stripped = CarrierConstraintSupport.stripNonMachineClauses( "\"ORDER\".equalsIgnoreCase(machineType) && message == \"PAY\""); - assertThat(CarrierConstraintSupport.primaryIdent( - CarrierConstraintSupport.splitAndClauses(stripped).get(0))) + assertThat(ConstraintClauses.primaryIdent( + ConstraintClauses.splitAndClauses(stripped).get(0))) .isEqualTo("machineType"); } @@ -53,16 +54,4 @@ class CarrierConstraintSupportTest { "command == ORDER_PAY", Map.of("commandKey", "order.pay"))).isFalse(); } - - @Test - void primaryIdentExtractsEqualsIgnoreCaseArgument() { - assertThat(CarrierConstraintSupport.primaryIdent("\"PAY\".equalsIgnoreCase(message)")) - .isEqualTo("message"); - } - - @Test - void primaryIdentExtractsEqLeftOperand() { - assertThat(CarrierConstraintSupport.primaryIdent("message == \"PAY\"")) - .isEqualTo("message"); - } }