B
This commit is contained in:
@@ -8,6 +8,7 @@ import click.kamil.springstatemachineexporter.analysis.model.LifecycleTriggerMar
|
|||||||
import click.kamil.springstatemachineexporter.analysis.model.LinkResolution;
|
import click.kamil.springstatemachineexporter.analysis.model.LinkResolution;
|
||||||
import click.kamil.springstatemachineexporter.analysis.model.MatchedTransition;
|
import click.kamil.springstatemachineexporter.analysis.model.MatchedTransition;
|
||||||
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
||||||
|
import click.kamil.springstatemachineexporter.analysis.service.CarrierConstraintSupport;
|
||||||
import click.kamil.springstatemachineexporter.analysis.service.CodebaseIntelligenceProvider;
|
import click.kamil.springstatemachineexporter.analysis.service.CodebaseIntelligenceProvider;
|
||||||
import click.kamil.springstatemachineexporter.analysis.service.EventCarrierPolicy;
|
import click.kamil.springstatemachineexporter.analysis.service.EventCarrierPolicy;
|
||||||
import click.kamil.springstatemachineexporter.analysis.service.JsonExportContextFactory;
|
import click.kamil.springstatemachineexporter.analysis.service.JsonExportContextFactory;
|
||||||
@@ -279,49 +280,11 @@ public class TransitionLinkerEnricher implements AnalysisEnricher {
|
|||||||
if (constraint == null || machineName == null) {
|
if (constraint == null || machineName == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
String machineConstraint = stripEventBindingClauses(constraint);
|
String machineConstraint = CarrierConstraintSupport.stripNonMachineClauses(constraint);
|
||||||
return BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
|
return BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
|
||||||
machineConstraint, MachineDomainKeys.extractMachineDomainKey(machineName));
|
machineConstraint, MachineDomainKeys.extractMachineDomainKey(machineName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String stripEventBindingClauses(String constraint) {
|
|
||||||
if (constraint == null || constraint.isBlank()) {
|
|
||||||
return constraint;
|
|
||||||
}
|
|
||||||
// Event/payload binding clauses prove which event was selected — not which machine.
|
|
||||||
// Keep machineType/domain comparisons for isCompatibleWithMachineDomain.
|
|
||||||
String eventLike = "(?i)(" + EventCarrierPolicy.carrierNameAlternation() + ")";
|
|
||||||
String stripped = constraint.replaceAll(
|
|
||||||
"\"[^\"]+\"\\s*\\.\\s*equalsIgnoreCase\\s*\\(\\s*" + eventLike + "\\s*\\)",
|
|
||||||
"true");
|
|
||||||
stripped = stripped.replaceAll(
|
|
||||||
eventLike + "\\s*\\.\\s*equalsIgnoreCase\\s*\\(\\s*\"[^\"]+\"\\s*\\)",
|
|
||||||
"true");
|
|
||||||
stripped = stripped.replaceAll(
|
|
||||||
"\"[^\"]+\"\\s*\\.\\s*equals\\s*\\(\\s*" + eventLike + "\\s*\\)",
|
|
||||||
"true");
|
|
||||||
stripped = stripped.replaceAll(
|
|
||||||
eventLike + "\\s*\\.\\s*equals\\s*\\(\\s*\"[^\"]+\"\\s*\\)",
|
|
||||||
"true");
|
|
||||||
// Switch-case / arrow constraints often use == on the payload param.
|
|
||||||
stripped = stripped.replaceAll(
|
|
||||||
eventLike + "\\s*==\\s*\"[^\"]+\"",
|
|
||||||
"true");
|
|
||||||
stripped = stripped.replaceAll(
|
|
||||||
"\"[^\"]+\"\\s*==\\s*" + eventLike,
|
|
||||||
"true");
|
|
||||||
stripped = stripped.replaceAll(
|
|
||||||
eventLike + "\\s*!=\\s*\"[^\"]+\"",
|
|
||||||
"true");
|
|
||||||
stripped = stripped.replaceAll(
|
|
||||||
"\"[^\"]+\"\\s*!=\\s*" + eventLike,
|
|
||||||
"true");
|
|
||||||
stripped = stripped.replaceAll("&&\\s*&&+", "&&");
|
|
||||||
stripped = stripped.replaceAll("^\\s*&&\\s*", "");
|
|
||||||
stripped = stripped.replaceAll("\\s*&&\\s*$", "");
|
|
||||||
return stripped.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String extractStateEnumType(String stateIdentifier) {
|
private String extractStateEnumType(String stateIdentifier) {
|
||||||
if (stateIdentifier == null || stateIdentifier.isBlank()) {
|
if (stateIdentifier == null || stateIdentifier.isBlank()) {
|
||||||
return stateIdentifier;
|
return stateIdentifier;
|
||||||
@@ -452,14 +415,8 @@ public class TransitionLinkerEnricher implements AnalysisEnricher {
|
|||||||
if (colon > 0) {
|
if (colon > 0) {
|
||||||
lower = lower.substring(0, colon);
|
lower = lower.substring(0, colon);
|
||||||
}
|
}
|
||||||
return lower.equals("event")
|
return EventCarrierPolicy.isCarrierParamName(lower)
|
||||||
|| lower.equals("e")
|
|| EventCarrierPolicy.isMachineDiscriminatorName(lower);
|
||||||
|| lower.endsWith("event")
|
|
||||||
|| lower.equals("command")
|
|
||||||
|| lower.equals("commandkey")
|
|
||||||
|| lower.equals("transition")
|
|
||||||
|| lower.equals("action")
|
|
||||||
|| lower.equals("machinetype");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean hasConcreteEventEvidence(TriggerPoint trigger) {
|
private static boolean hasConcreteEventEvidence(TriggerPoint trigger) {
|
||||||
|
|||||||
@@ -159,9 +159,8 @@ public class HeuristicEventMatchingEngine implements EventMatchingEngine {
|
|||||||
private boolean isWildcardVariable(String eventStr) {
|
private boolean isWildcardVariable(String eventStr) {
|
||||||
if (eventStr == null) return false;
|
if (eventStr == null) return false;
|
||||||
|
|
||||||
if (eventStr.equals("event") || eventStr.equals("e") ||
|
if (click.kamil.springstatemachineexporter.analysis.service.EventCarrierPolicy
|
||||||
eventStr.equals("msg") || eventStr.equals("message") ||
|
.isDynamicEventToken(eventStr)) {
|
||||||
eventStr.equals("payload")) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -681,9 +681,8 @@ public final class MachineEnumCanonicalizer {
|
|||||||
if (eventStr.contains("${")) {
|
if (eventStr.contains("${")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (eventStr.equals("event") || eventStr.equals("e")
|
if (click.kamil.springstatemachineexporter.analysis.service.EventCarrierPolicy
|
||||||
|| eventStr.equals("msg") || eventStr.equals("message")
|
.isDynamicEventToken(eventStr)) {
|
||||||
|| eventStr.equals("payload")) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (eventStr.contains(".valueOf(") || eventStr.contains("valueOf (")) {
|
if (eventStr.contains(".valueOf(") || eventStr.contains("valueOf (")) {
|
||||||
@@ -1199,11 +1198,8 @@ public final class MachineEnumCanonicalizer {
|
|||||||
.matcher(constraint);
|
.matcher(constraint);
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
String param = matcher.group(2);
|
String param = matcher.group(2);
|
||||||
if ("event".equals(param)
|
if (click.kamil.springstatemachineexporter.analysis.service.EventCarrierPolicy
|
||||||
|| "eventString".equals(param)
|
.isCarrierParamName(param)) {
|
||||||
|| "actionKey".equals(param)
|
|
||||||
|| "action".equals(param)
|
|
||||||
|| "commandKey".equals(param)) {
|
|
||||||
literals.add(matcher.group(1));
|
literals.add(matcher.group(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import click.kamil.springstatemachineexporter.analysis.model.CallEdge;
|
|||||||
import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
|
import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
|
||||||
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
||||||
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
|
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
|
||||||
import click.kamil.springstatemachineexporter.analysis.resolver.BooleanConstraintEvaluator;
|
|
||||||
import click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver;
|
import click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver;
|
||||||
import click.kamil.springstatemachineexporter.analysis.resolver.MachineEnumCanonicalizer;
|
import click.kamil.springstatemachineexporter.analysis.resolver.MachineEnumCanonicalizer;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -144,7 +143,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
|||||||
&& resolvedTp.getConstraint() != null
|
&& resolvedTp.getConstraint() != null
|
||||||
&& constraintBindings != null
|
&& constraintBindings != null
|
||||||
&& !constraintBindings.isEmpty()
|
&& !constraintBindings.isEmpty()
|
||||||
&& !BooleanConstraintEvaluator.isCompatibleWithKnownBindings(
|
&& CarrierConstraintSupport.contradictsCarrierBindings(
|
||||||
resolvedTp.getConstraint(), constraintBindings)) {
|
resolvedTp.getConstraint(), constraintBindings)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package click.kamil.springstatemachineexporter.analysis.service;
|
||||||
|
|
||||||
|
import click.kamil.springstatemachineexporter.analysis.resolver.BooleanConstraintEvaluator;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Carrier-aware constraint helpers shared by call-graph filtering and transition linking.
|
||||||
|
* Payload/event binding clauses are not machine-domain evidence.
|
||||||
|
*/
|
||||||
|
public final class CarrierConstraintSupport {
|
||||||
|
|
||||||
|
private CarrierConstraintSupport() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes equals / {@code ==} / {@code !=} clauses whose parameter is an event/payload carrier,
|
||||||
|
* leaving machine-domain discriminators for {@link BooleanConstraintEvaluator#isCompatibleWithMachineDomain}.
|
||||||
|
*/
|
||||||
|
public static String stripNonMachineClauses(String constraint) {
|
||||||
|
if (constraint == null || constraint.isBlank()) {
|
||||||
|
return constraint;
|
||||||
|
}
|
||||||
|
String eventLike = "(?i)(" + EventCarrierPolicy.carrierNameAlternation() + ")";
|
||||||
|
String stripped = constraint.replaceAll(
|
||||||
|
"\"[^\"]+\"\\s*\\.\\s*equalsIgnoreCase\\s*\\(\\s*" + eventLike + "\\s*\\)",
|
||||||
|
"true");
|
||||||
|
stripped = stripped.replaceAll(
|
||||||
|
eventLike + "\\s*\\.\\s*equalsIgnoreCase\\s*\\(\\s*\"[^\"]+\"\\s*\\)",
|
||||||
|
"true");
|
||||||
|
stripped = stripped.replaceAll(
|
||||||
|
"\"[^\"]+\"\\s*\\.\\s*equals\\s*\\(\\s*" + eventLike + "\\s*\\)",
|
||||||
|
"true");
|
||||||
|
stripped = stripped.replaceAll(
|
||||||
|
eventLike + "\\s*\\.\\s*equals\\s*\\(\\s*\"[^\"]+\"\\s*\\)",
|
||||||
|
"true");
|
||||||
|
stripped = stripped.replaceAll(
|
||||||
|
eventLike + "\\s*==\\s*\"[^\"]+\"",
|
||||||
|
"true");
|
||||||
|
stripped = stripped.replaceAll(
|
||||||
|
"\"[^\"]+\"\\s*==\\s*" + eventLike,
|
||||||
|
"true");
|
||||||
|
stripped = stripped.replaceAll(
|
||||||
|
eventLike + "\\s*!=\\s*\"[^\"]+\"",
|
||||||
|
"true");
|
||||||
|
stripped = stripped.replaceAll(
|
||||||
|
"\"[^\"]+\"\\s*!=\\s*" + eventLike,
|
||||||
|
"true");
|
||||||
|
stripped = stripped.replaceAll("&&\\s*&&+", "&&");
|
||||||
|
stripped = stripped.replaceAll("^\\s*&&\\s*", "");
|
||||||
|
stripped = stripped.replaceAll("\\s*&&\\s*$", "");
|
||||||
|
return stripped.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True when the constraint contradicts entry/path bindings on overlapping carrier keys.
|
||||||
|
* Unrelated locals (e.g. {@code command} vs binding {@code commandKey}) are ignored.
|
||||||
|
*/
|
||||||
|
public static boolean contradictsCarrierBindings(String constraint, Map<String, String> bindings) {
|
||||||
|
if (constraint == null || constraint.isBlank() || bindings == null || bindings.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Map<String, String> carrierBindings = new LinkedHashMap<>();
|
||||||
|
for (Map.Entry<String, String> entry : bindings.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
if (key == null || !EventCarrierPolicy.isCarrierParamName(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!constraintMentionsIdent(constraint, key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
carrierBindings.put(key, entry.getValue());
|
||||||
|
}
|
||||||
|
if (carrierBindings.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !BooleanConstraintEvaluator.isCompatibleWithKnownBindings(constraint, carrierBindings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean constraintMentionsIdent(String constraint, String ident) {
|
||||||
|
if (constraint == null || ident == null || ident.isBlank()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Pattern word = Pattern.compile("(?i)\\b" + Pattern.quote(ident) + "\\b");
|
||||||
|
return word.matcher(constraint).find();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,6 +43,14 @@ public final class EventCarrierPolicy {
|
|||||||
"sourcestate",
|
"sourcestate",
|
||||||
"fromstate");
|
"fromstate");
|
||||||
|
|
||||||
|
/** Bare unresolved trigger tokens (not FQNs / expressions). */
|
||||||
|
private static final Set<String> DYNAMIC_EVENT_TOKENS = Set.of(
|
||||||
|
"event",
|
||||||
|
"e",
|
||||||
|
"message",
|
||||||
|
"msg",
|
||||||
|
"payload");
|
||||||
|
|
||||||
private EventCarrierPolicy() {
|
private EventCarrierPolicy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +79,17 @@ public final class EventCarrierPolicy {
|
|||||||
return isCarrierParamName(name) || isMachineDiscriminatorName(name);
|
return isCarrierParamName(name) || isMachineDiscriminatorName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bare identifier used as an unresolved trigger event expression
|
||||||
|
* ({@code event}, {@code message}, {@code payload}, …).
|
||||||
|
*/
|
||||||
|
public static boolean isDynamicEventToken(String eventStr) {
|
||||||
|
if (eventStr == null || eventStr.isBlank()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return DYNAMIC_EVENT_TOKENS.contains(eventStr.toLowerCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
/** Clear state-variable / accessor names used for positive source-state inference. */
|
/** Clear state-variable / accessor names used for positive source-state inference. */
|
||||||
public static boolean isStateAccessorName(String name) {
|
public static boolean isStateAccessorName(String name) {
|
||||||
if (name == null || name.isBlank()) {
|
if (name == null || name.isBlank()) {
|
||||||
@@ -84,7 +103,7 @@ public final class EventCarrierPolicy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Messaging {@code @Payload} or unannotated String body that looks like an event carrier.
|
* Messaging {@code @Payload}, conventional carrier name, or the sole unannotated String body.
|
||||||
*/
|
*/
|
||||||
public static boolean isMessagingPayloadParameter(EntryPoint entryPoint, EntryPoint.Parameter parameter) {
|
public static boolean isMessagingPayloadParameter(EntryPoint entryPoint, EntryPoint.Parameter parameter) {
|
||||||
if (entryPoint == null || parameter == null || !isMessagingEntryPoint(entryPoint)) {
|
if (entryPoint == null || parameter == null || !isMessagingEntryPoint(entryPoint)) {
|
||||||
@@ -100,7 +119,41 @@ public final class EventCarrierPolicy {
|
|||||||
if (!isStringType(parameter.getType())) {
|
if (!isStringType(parameter.getType())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return isCarrierParamName(parameter.getName());
|
if (isCarrierParamName(parameter.getName())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return isSoleUnannotatedStringMessagingBody(entryPoint, parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unannotated {@code String} body that is the only such param on a messaging entry —
|
||||||
|
* treat as carrier even when named {@code cmd}.
|
||||||
|
*/
|
||||||
|
public static boolean isSoleUnannotatedStringMessagingBody(
|
||||||
|
EntryPoint entryPoint, EntryPoint.Parameter parameter) {
|
||||||
|
if (entryPoint == null || parameter == null || !isMessagingEntryPoint(entryPoint)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (parameter.getAnnotations() != null && !parameter.getAnnotations().isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!isStringType(parameter.getType())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (entryPoint.getParameters() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int unannotatedStringBodies = 0;
|
||||||
|
for (EntryPoint.Parameter candidate : entryPoint.getParameters()) {
|
||||||
|
if (candidate == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boolean unannotated = candidate.getAnnotations() == null || candidate.getAnnotations().isEmpty();
|
||||||
|
if (unannotated && isStringType(candidate.getType())) {
|
||||||
|
unannotatedStringBodies++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return unannotatedStringBodies == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -148,24 +201,16 @@ public final class EventCarrierPolicy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alternation for regex consumers (linker constraint stripping). Names are already lowercased
|
* Alternation for carrier-clause regex stripping ({@link CarrierConstraintSupport}).
|
||||||
* where case-insensitive flags are used by the caller.
|
* Includes camelCase aliases so source that uses {@code commandKey} matches under {@code (?i)}.
|
||||||
*/
|
*/
|
||||||
public static String carrierNameAlternation() {
|
static String carrierNameAlternation() {
|
||||||
return Stream.concat(
|
return Stream.concat(CARRIER_NAMES.stream(), Stream.of("commandKey", "eventString", "actionKey"))
|
||||||
CARRIER_NAMES.stream(),
|
|
||||||
Stream.of("commandKey"))
|
|
||||||
.distinct()
|
.distinct()
|
||||||
.sorted()
|
.sorted()
|
||||||
.collect(Collectors.joining("|"));
|
.collect(Collectors.joining("|"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String routingDiscriminantAlternation() {
|
|
||||||
return Stream.concat(CARRIER_NAMES.stream(), MACHINE_DISCRIMINATOR_NAMES.stream())
|
|
||||||
.sorted()
|
|
||||||
.collect(Collectors.joining("|"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasAnnotation(EntryPoint.Parameter parameter, String simpleName) {
|
private static boolean hasAnnotation(EntryPoint.Parameter parameter, String simpleName) {
|
||||||
if (parameter.getAnnotations() == null || simpleName == null) {
|
if (parameter.getAnnotations() == null || simpleName == null) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -800,11 +800,38 @@ public class GenericEventDetector {
|
|||||||
if (hasPayloadAnnotation(param)) {
|
if (hasPayloadAnnotation(param)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return EventCarrierPolicy.isCarrierParamName(param.getName().getIdentifier());
|
if (EventCarrierPolicy.isCarrierParamName(param.getName().getIdentifier())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Sole unannotated String param on the method — same rule as messaging body carrier.
|
||||||
|
return countUnannotatedStringParams(method) == 1;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int countUnannotatedStringParams(MethodDeclaration method) {
|
||||||
|
int count = 0;
|
||||||
|
for (Object paramObj : method.parameters()) {
|
||||||
|
if (!(paramObj instanceof SingleVariableDeclaration param)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (hasPayloadAnnotation(param)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boolean unannotated = true;
|
||||||
|
for (Object modifier : param.modifiers()) {
|
||||||
|
if (modifier instanceof Annotation) {
|
||||||
|
unannotated = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (unannotated && isStringType(param.getType())) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isStringType(org.eclipse.jdt.core.dom.Type type) {
|
private static boolean isStringType(org.eclipse.jdt.core.dom.Type type) {
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package click.kamil.springstatemachineexporter.analysis.service;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class CarrierConstraintSupportTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void stripNonMachineClausesRemovesPayloadEquals() {
|
||||||
|
String stripped = CarrierConstraintSupport.stripNonMachineClauses(
|
||||||
|
"\"PAY\".equalsIgnoreCase(message) && message == \"PAY\"");
|
||||||
|
assertThat(stripped).isEqualToIgnoringWhitespace("true && true");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void stripNonMachineClausesKeepsMachineDomainClauses() {
|
||||||
|
String stripped = CarrierConstraintSupport.stripNonMachineClauses(
|
||||||
|
"\"ORDER\".equalsIgnoreCase(machineType) && message == \"PAY\"");
|
||||||
|
assertThat(stripped).contains("machineType");
|
||||||
|
assertThat(stripped).doesNotContain("message == ");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void contradictsWhenCarrierBindingConflictsWithConstraint() {
|
||||||
|
assertThat(CarrierConstraintSupport.contradictsCarrierBindings(
|
||||||
|
"message == \"SHIP\"",
|
||||||
|
Map.of("message", "PAY"))).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void doesNotContradictWhenCarrierBindingMatchesConstraint() {
|
||||||
|
assertThat(CarrierConstraintSupport.contradictsCarrierBindings(
|
||||||
|
"\"PAY\".equalsIgnoreCase(message) && message == \"PAY\"",
|
||||||
|
Map.of("message", "PAY"))).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void doesNotContradictWhenConstraintLocalsDoNotOverlapCarrierBindings() {
|
||||||
|
assertThat(CarrierConstraintSupport.contradictsCarrierBindings(
|
||||||
|
"command == ORDER_PAY",
|
||||||
|
Map.of("commandKey", "order.pay"))).isFalse();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@@ -19,6 +20,15 @@ class EventCarrierPolicyTest {
|
|||||||
assertThat(EventCarrierPolicy.isCarrierParamName("cmd")).isFalse();
|
assertThat(EventCarrierPolicy.isCarrierParamName("cmd")).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void dynamicEventTokensMatchBareUnresolvedTriggers() {
|
||||||
|
assertThat(EventCarrierPolicy.isDynamicEventToken("event")).isTrue();
|
||||||
|
assertThat(EventCarrierPolicy.isDynamicEventToken("message")).isTrue();
|
||||||
|
assertThat(EventCarrierPolicy.isDynamicEventToken("payload")).isTrue();
|
||||||
|
assertThat(EventCarrierPolicy.isDynamicEventToken("OrderEvent.PAY")).isFalse();
|
||||||
|
assertThat(EventCarrierPolicy.isDynamicEventToken("cmd")).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void machineDiscriminatorsAreRoutingButNotCarriers() {
|
void machineDiscriminatorsAreRoutingButNotCarriers() {
|
||||||
assertThat(EventCarrierPolicy.isMachineDiscriminatorName("machineType")).isTrue();
|
assertThat(EventCarrierPolicy.isMachineDiscriminatorName("machineType")).isTrue();
|
||||||
@@ -55,6 +65,54 @@ class EventCarrierPolicyTest {
|
|||||||
entryPoint, entryPoint.getParameters().get(0))).isTrue();
|
entryPoint, entryPoint.getParameters().get(0))).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void soleUnannotatedStringMessagingBodyIsCarrierEvenWhenNamedCmd() {
|
||||||
|
EntryPoint entryPoint = EntryPoint.builder()
|
||||||
|
.type(EntryPoint.Type.JMS)
|
||||||
|
.name("JMS: q")
|
||||||
|
.className("com.example.L")
|
||||||
|
.methodName("onMessage")
|
||||||
|
.parameters(List.of(EntryPoint.Parameter.builder()
|
||||||
|
.name("cmd")
|
||||||
|
.type("String")
|
||||||
|
.annotations(List.of())
|
||||||
|
.build()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThat(EventCarrierPolicy.isSoleUnannotatedStringMessagingBody(
|
||||||
|
entryPoint, entryPoint.getParameters().get(0))).isTrue();
|
||||||
|
assertThat(EventCarrierPolicy.isMessagingPayloadParameter(
|
||||||
|
entryPoint, entryPoint.getParameters().get(0))).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void twoUnannotatedStringBodiesAreNotAutoCarriersBySoleBodyRule() {
|
||||||
|
EntryPoint entryPoint = EntryPoint.builder()
|
||||||
|
.type(EntryPoint.Type.JMS)
|
||||||
|
.name("JMS: q")
|
||||||
|
.className("com.example.L")
|
||||||
|
.methodName("onMessage")
|
||||||
|
.parameters(List.of(
|
||||||
|
EntryPoint.Parameter.builder()
|
||||||
|
.name("cmd")
|
||||||
|
.type("String")
|
||||||
|
.annotations(List.of())
|
||||||
|
.build(),
|
||||||
|
EntryPoint.Parameter.builder()
|
||||||
|
.name("extra")
|
||||||
|
.type("String")
|
||||||
|
.annotations(List.of())
|
||||||
|
.build()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThat(EventCarrierPolicy.isSoleUnannotatedStringMessagingBody(
|
||||||
|
entryPoint, entryPoint.getParameters().get(0))).isFalse();
|
||||||
|
assertThat(EventCarrierPolicy.isMessagingPayloadParameter(
|
||||||
|
entryPoint, entryPoint.getParameters().get(0))).isFalse();
|
||||||
|
assertThat(EventCarrierPolicy.isMessagingPayloadParameter(
|
||||||
|
entryPoint, entryPoint.getParameters().get(1))).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void unannotatedMessagingStringUsesCarrierNameConvention() {
|
void unannotatedMessagingStringUsesCarrierNameConvention() {
|
||||||
EntryPoint entryPoint = EntryPoint.builder()
|
EntryPoint entryPoint = EntryPoint.builder()
|
||||||
@@ -72,12 +130,4 @@ class EventCarrierPolicyTest {
|
|||||||
assertThat(EventCarrierPolicy.isMessagingPayloadParameter(
|
assertThat(EventCarrierPolicy.isMessagingPayloadParameter(
|
||||||
entryPoint, entryPoint.getParameters().get(0))).isTrue();
|
entryPoint, entryPoint.getParameters().get(0))).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void carrierNameAlternationIsNonEmptyForLinkerRegex() {
|
|
||||||
assertThat(EventCarrierPolicy.carrierNameAlternation())
|
|
||||||
.contains("message")
|
|
||||||
.contains("payload")
|
|
||||||
.contains("event");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user