This commit is contained in:
2026-07-07 21:11:32 +02:00
parent 9a5f122bd2
commit 1be8d5e950
3 changed files with 102 additions and 13 deletions

View File

@@ -85,8 +85,8 @@ public class StrictFqnMatchingEngine implements EventMatchingEngine {
if (triggerEvent == null || smEvent == null) return false;
if (triggerEvent.equals(smEvent)) return true;
String tConst = triggerEvent.contains(".") ? triggerEvent.substring(triggerEvent.lastIndexOf('.') + 1) : triggerEvent;
String smConst = smEvent.contains(".") ? smEvent.substring(smEvent.lastIndexOf('.') + 1) : smEvent;
String tConst = constantName(triggerEvent);
String smConst = constantName(smEvent);
if (!tConst.equals(smConst)) return false;
@@ -100,20 +100,46 @@ public class StrictFqnMatchingEngine implements EventMatchingEngine {
return false;
}
if (eventTypeFqn != null && eventTypeFqn.contains(".") && smEvent.contains(".")) {
String fullTriggerFqn = eventTypeFqn + "." + tConst;
return fullTriggerFqn.equals(smEvent);
if (smEvent.contains(".")) {
String smEnumType = smEvent.substring(0, smEvent.lastIndexOf('.'));
if (eventTypeFqn != null) {
return enumTypesMatch(eventTypeFqn, smEnumType);
}
if (triggerEvent.contains(".")) {
String triggerEnumType = triggerEvent.substring(0, triggerEvent.lastIndexOf('.'));
return enumTypesMatch(triggerEnumType, smEnumType);
}
// Bare constant name (e.g. after Enum.name()) with no type context must not match every enum
return false;
}
if (triggerEvent.contains(".") && smEvent.contains(".")) {
String tClass = triggerEvent.substring(0, triggerEvent.lastIndexOf('.'));
String smClass = smEvent.substring(0, smEvent.lastIndexOf('.'));
String tClassSimple = tClass.contains(".") ? tClass.substring(tClass.lastIndexOf('.') + 1) : tClass;
String smClassSimple = smClass.contains(".") ? smClass.substring(smClass.lastIndexOf('.') + 1) : smClass;
return tClassSimple.equals(smClassSimple);
}
// Both sides are unqualified identifiers (string/primitive events)
return !triggerEvent.contains(".");
}
return true;
private String constantName(String event) {
return event.contains(".") ? event.substring(event.lastIndexOf('.') + 1) : event;
}
private boolean enumTypesMatch(String type1, String type2) {
if (type1 == null || type2 == null) return false;
if (type1.equals(type2)) return true;
if (type1.endsWith("." + type2) || type2.endsWith("." + type1)) return true;
String simple1 = simpleName(type1);
String simple2 = simpleName(type2);
if (!simple1.equals(simple2)) return false;
// Same simple name only matches when at least one side is package-less (import-style reference).
// Prevents com.foo.OrderEvents from matching com.bar.OrderEvents.
return !type1.contains(".") || !type2.contains(".");
}
private String simpleName(String name) {
return name.contains(".") ? name.substring(name.lastIndexOf('.') + 1) : name;
}
private boolean isStringTypeOrPrimitive(String typeFqn) {

View File

@@ -143,7 +143,38 @@ class TransitionLinkerEnricherTest {
assertThat(updatedChain.getMatchedTransitions()).hasSize(1);
}
@Test
void shouldNotLinkAllEnumTransitionsWhenConstantNamesCollide() {
Transition orderPay = new Transition();
orderPay.setSourceStates(List.of(State.of("NEW", "NEW")));
orderPay.setTargetStates(List.of(State.of("PAID", "PAID")));
orderPay.setEvent(Event.of("PAY", "com.example.OrderEvents.PAY"));
Transition invoicePay = new Transition();
invoicePay.setSourceStates(List.of(State.of("DRAFT", "DRAFT")));
invoicePay.setTargetStates(List.of(State.of("SENT", "SENT")));
invoicePay.setEvent(Event.of("PAY", "com.example.InvoiceEvents.PAY"));
CallChain chain = CallChain.builder()
.triggerPoint(TriggerPoint.builder()
.event("OrderEvents.PAY")
.eventTypeFqn("com.example.OrderEvents")
.build())
.contextMachineId("testMachine")
.build();
AnalysisResult result = AnalysisResult.builder()
.name("testMachine")
.transitions(List.of(orderPay, invoicePay))
.metadata(CodebaseMetadata.builder().callChains(List.of(chain)).build())
.build();
enricher.enrich(result, null, null);
CallChain updatedChain = result.getMetadata().getCallChains().get(0);
assertThat(updatedChain.getMatchedTransitions()).hasSize(1);
assertThat(updatedChain.getMatchedTransitions().get(0).getEvent()).isEqualTo("com.example.OrderEvents.PAY");
}
@Test
void shouldMatchBaseEventDespiteScrapedPolyEvents() {

View File

@@ -196,6 +196,38 @@ class StrictFqnMatchingEngineTest {
assertThat(engine.matches(smEvent, triggerPoint)).isTrue();
}
@Test
void shouldNotMatchBareStrippedConstantToAnyEnumWithoutTypeContext() {
Event smEvent = Event.of("PAY", "com.example.OrderEvents.PAY");
TriggerPoint triggerPoint = TriggerPoint.builder()
.event("PAY")
.build();
assertThat(engine.matches(smEvent, triggerPoint)).isFalse();
}
@Test
void shouldNotMatchSameEnumSimpleNameFromDifferentPackages() {
Event smEvent = Event.of("PAY", "com.example.other.OrderEvents.PAY");
TriggerPoint triggerPoint = TriggerPoint.builder()
.event("OrderEvents.PAY")
.eventTypeFqn("com.example.OrderEvents")
.build();
assertThat(engine.matches(smEvent, triggerPoint)).isFalse();
}
@Test
void shouldNotMatchPolymorphicStrippedConstantWithoutTypeContext() {
Event smEvent = Event.of("PAY", "com.example.InvoiceEvents.PAY");
TriggerPoint triggerPoint = TriggerPoint.builder()
.event("getType()")
.polymorphicEvents(List.of("PAY"))
.build();
assertThat(engine.matches(smEvent, triggerPoint)).isFalse();
}
@Test
void shouldMatchDynamicMethodCallAsVariable() {
Event smEvent = Event.of("PAY", "com.example.OrderEvents.PAY");