better tests

This commit is contained in:
2026-06-27 15:10:36 +02:00
parent 8a56e92a65
commit 60c666f7a1
4 changed files with 98 additions and 17 deletions

View File

@@ -352,7 +352,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
resolvedValue = cic.toString() + "." + methodName + "()";
}
}
if (!polymorphicEvents.isEmpty()) {
System.out.println("Returning early with events: " + polymorphicEvents + " for " + resolvedValue); if (!polymorphicEvents.isEmpty()) {
return TriggerPoint.builder()
.event(resolvedValue)
.className(tp.getClassName())
@@ -438,6 +438,21 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
if (values != null && !values.isEmpty()) {
polymorphicEvents.addAll(values);
}
if (polymorphicEvents.isEmpty() && variableTracer != null) {
String initializer = variableTracer.traceLocalVariable(methodFqn, varName);
if (initializer != null && !initializer.equals(varName)) {
ASTParser mapParser = ASTParser.newParser(AST.JLS17);
mapParser.setKind(ASTParser.K_EXPRESSION);
mapParser.setSource(initializer.toCharArray());
ASTNode mapNode = mapParser.createAST(null);
if (mapNode instanceof Expression) {
List<Expression> mapTraced = variableTracer.traceVariableAll((Expression) mapNode);
for (Expression t : mapTraced) {
constantExtractor.extractConstantsFromExpression(t, polymorphicEvents);
}
}
}
}
sourceMethod = methodFqn;
break;
}

View File

@@ -72,11 +72,20 @@ public class ConstantExtractor {
} else if (expr instanceof MethodInvocation mi) {
String methodName = mi.getName().getIdentifier();
if (methodName.equals("get") && mi.arguments().size() == 1 && mi.getExpression() != null) {
extractConstantsFromExpression(mi.getExpression(), constants);
System.out.println("Processing mi: " + mi); if (methodName.equals("get") || methodName.equals("getOrDefault")) {
if (mi.getExpression() != null) {
if (variableTracer != null) {
List<Expression> traced = variableTracer.traceVariableAll(mi.getExpression());
for (Expression t : traced) {
extractConstantsFromExpression(t, constants);
}
} else {
extractConstantsFromExpression(mi.getExpression(), constants);
}
}
return;
}
if ((methodName.equals("of") || methodName.equals("asList")) && mi.getExpression() instanceof SimpleName) {
if (methodName.equals("of") || methodName.equals("ofEntries") || methodName.equals("asList") || methodName.equals("entry")) {
for (Object argObj : mi.arguments()) {
extractConstantsFromExpression((Expression) argObj, constants);
}

View File

@@ -341,19 +341,7 @@ public class VariableTracer {
Expression traced = traceVariable(expr);
if (traced instanceof MethodInvocation mi) {
Expression innerMost = unwrapMethodInvocation(mi, 0);
if (innerMost instanceof MethodInvocation innerMi) {
if (innerMi.getExpression() instanceof SimpleName sn) {
stringified.add(sn.getIdentifier() + "." + innerMi.getName().getIdentifier() + "()");
} else {
stringified.add(innerMi.getName().getIdentifier() + "()");
}
} else if (innerMost instanceof SimpleName sn) {
stringified.add(sn.getIdentifier());
} else {
stringified.add(innerMost.toString());
}
} else if (traced instanceof SimpleName sn) {
stringified.add(sn.getIdentifier());
stringified.add(innerMost.toString());
} else if (traced instanceof ArrayInitializer) {
stringified.add("new Object[]" + traced.toString());
} else {

View File

@@ -0,0 +1,69 @@
package click.kamil.springstatemachineexporter.analysis.service;
import click.kamil.springstatemachineexporter.analysis.model.CallChain;
import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class NewBugTest {
@Test
void shouldResolveMapLookup() throws IOException {
String source = """
package com.example;
import java.util.Map;
public class Controller {
private StateMachine machine;
private static final Map<InputEnum, TransitionEnum> MAP = Map.of(
InputEnum.IN_A, TransitionEnum.STATE_X,
InputEnum.IN_B, TransitionEnum.STATE_Y
);
public void process(InputEnum input) {
TransitionEnum trans = MAP.get(input);
machine.fire(trans);
}
}
class StateMachine {
public void fire(TransitionEnum event) {}
}
enum InputEnum { IN_A, IN_B }
enum TransitionEnum { STATE_X, STATE_Y }
""";
Path tempDir = Files.createTempDirectory("callgraph_test_map");
Files.writeString(tempDir.resolve("Config.java"), source);
CodebaseContext context = new CodebaseContext();
context.scan(tempDir);
HeuristicCallGraphEngine engine = new HeuristicCallGraphEngine(context);
EntryPoint entryPoint = EntryPoint.builder()
.className("com.example.Controller")
.methodName("process")
.build();
TriggerPoint trigger = TriggerPoint.builder()
.className("com.example.StateMachine")
.methodName("fire")
.event("event")
.build();
List<CallChain> chains = engine.findChains(List.of(entryPoint), List.of(trigger));
assertThat(chains).hasSize(1);
System.out.println("Poly events: " + chains.get(0).getTriggerPoint().getPolymorphicEvents());
assertThat(chains.get(0).getTriggerPoint().getPolymorphicEvents()).contains("TransitionEnum.STATE_X", "TransitionEnum.STATE_Y");
}
}