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 b578751..07d1d25 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 @@ -169,7 +169,6 @@ public final class BooleanConstraintEvaluator { if (cleanValue.startsWith("\"") && cleanValue.endsWith("\"")) { cleanValue = cleanValue.substring(1, cleanValue.length() - 1); } - String suffix = cleanValue.contains(".") ? cleanValue.substring(cleanValue.lastIndexOf('.') + 1) : cleanValue; Pattern eqPattern = Pattern.compile( "(?i)" + Pattern.quote(varName) + "\\s*==\\s*([\\w.\"']+)"); @@ -177,10 +176,7 @@ public final class BooleanConstraintEvaluator { StringBuffer sb = new StringBuffer(); while (matcher.find()) { String rhs = matcher.group(1).replace("\"", "").replace("'", ""); - boolean matches = cleanValue.equals(rhs) - || cleanValue.endsWith("." + rhs) - || suffix.equalsIgnoreCase(rhs) - || cleanValue.equalsIgnoreCase(rhs); + boolean matches = constraintValuesMatch(cleanValue, rhs); matcher.appendReplacement(sb, matches ? "true" : "false"); } matcher.appendTail(sb); @@ -191,6 +187,72 @@ public final class BooleanConstraintEvaluator { return sb.toString(); } + private static boolean constraintValuesMatch(String boundValue, String rhs) { + if (boundValue == null || rhs == null) { + return false; + } + String bound = stripOuterQuotes(boundValue); + String rhsClean = stripOuterQuotes(rhs); + if (bound.equals(rhsClean) || bound.equalsIgnoreCase(rhsClean)) { + return true; + } + if (bound.endsWith("." + rhsClean) || rhsClean.endsWith("." + bound)) { + return true; + } + + String boundConstant = enumConstantName(bound); + String rhsConstant = enumConstantName(rhsClean); + if (!boundConstant.equalsIgnoreCase(rhsConstant)) { + return false; + } + + String boundType = enumTypePart(bound); + String rhsType = enumTypePart(rhsClean); + if (boundType == null || rhsType == null) { + return true; + } + if (boundType.equals(rhsType)) { + return true; + } + + String boundSimple = simpleTypeName(boundType); + String rhsSimple = simpleTypeName(rhsType); + if (!boundSimple.equals(rhsSimple)) { + return false; + } + boolean boundImportStyle = !boundType.contains("."); + boolean rhsImportStyle = !rhsType.contains("."); + return boundImportStyle || rhsImportStyle; + } + + private static String stripOuterQuotes(String value) { + if (value == null) { + return null; + } + if (value.length() >= 2 && value.startsWith("\"") && value.endsWith("\"")) { + return value.substring(1, value.length() - 1); + } + return value; + } + + private static String enumConstantName(String ref) { + int dot = ref.lastIndexOf('.'); + return dot >= 0 ? ref.substring(dot + 1) : ref; + } + + private static String enumTypePart(String ref) { + int dot = ref.lastIndexOf('.'); + if (dot <= 0) { + return null; + } + return ref.substring(0, dot); + } + + private static String simpleTypeName(String typePart) { + int dot = typePart.lastIndexOf('.'); + return dot >= 0 ? typePart.substring(dot + 1) : typePart; + } + /** * Returns {@code true}/{@code false} when both sides are compile-time string literals; otherwise {@code null}. */ diff --git a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluatorBindingsTest.java b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluatorBindingsTest.java index a094c59..96e3b84 100644 --- a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluatorBindingsTest.java +++ b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/resolver/BooleanConstraintEvaluatorBindingsTest.java @@ -29,6 +29,20 @@ class BooleanConstraintEvaluatorBindingsTest { Map.of("commandKey", "order.pay"))).isTrue(); } + @Test + void shouldRejectCrossPackageQualifiedEnumSwitchConstraint() { + assertThat(BooleanConstraintEvaluator.isCompatibleWithBindings( + "command == a.OrderEvent.PAY", + Map.of("command", "b.OrderEvent.PAY"))).isFalse(); + } + + @Test + void shouldAcceptPackageQualifiedRhsAgainstImportStyleBinding() { + assertThat(BooleanConstraintEvaluator.isCompatibleWithBindings( + "command == com.example.DomainCommand.ORDER_PAY", + Map.of("command", "DomainCommand.ORDER_PAY"))).isTrue(); + } + @Test void shouldRejectConstraintWhenBindingIsMissing() { assertThat(BooleanConstraintEvaluator.isCompatibleWithBindings(