84 lines
3.7 KiB
Java
84 lines
3.7 KiB
Java
|
package ch.usi.inf.sp.cfg;
|
||
|
|
||
|
import ch.usi.inf.sp.bytecode.Disassembler;
|
||
|
import org.junit.jupiter.api.BeforeEach;
|
||
|
import org.junit.jupiter.api.Test;
|
||
|
import org.objectweb.asm.ClassReader;
|
||
|
import org.objectweb.asm.tree.AbstractInsnNode;
|
||
|
import org.objectweb.asm.tree.ClassNode;
|
||
|
import org.objectweb.asm.tree.InsnList;
|
||
|
import org.objectweb.asm.tree.MethodNode;
|
||
|
|
||
|
import java.io.File;
|
||
|
import java.io.FileInputStream;
|
||
|
import java.io.FileNotFoundException;
|
||
|
import java.io.IOException;
|
||
|
import java.util.Iterator;
|
||
|
import java.util.List;
|
||
|
|
||
|
import static org.junit.jupiter.api.Assertions.*;
|
||
|
|
||
|
/**
|
||
|
* This tests the ControlFlowGraphBuilder by running it on the compiled ExampleClass.
|
||
|
* It loads the ExampleClass.class (as compiled by Java10's javac).
|
||
|
* The different test methods test the CFGB on different inputs
|
||
|
* (different methods in class ExampleClass).
|
||
|
* The test is VERY WEAK.
|
||
|
* That is, there are many bugs it will not discover.
|
||
|
*/
|
||
|
class ControlFlowGraphBuilderTest {
|
||
|
|
||
|
private static ClassNode classNode;
|
||
|
|
||
|
private static MethodNode getMethod(String name, String desc) {
|
||
|
for (MethodNode methodNode : classNode.methods) {
|
||
|
if (methodNode.name.equals(name) && methodNode.desc.equals(desc)) {
|
||
|
return methodNode;
|
||
|
}
|
||
|
}
|
||
|
throw new IllegalArgumentException("Error in test harness: method "+name+" not found!");
|
||
|
}
|
||
|
|
||
|
@BeforeEach
|
||
|
void setUp() throws IOException {
|
||
|
// Use ASM to read a class file (from test-input) and create a ClassNode
|
||
|
File classFile = new File("test-input/java10/ExampleClass.class");
|
||
|
final ClassReader cr = new ClassReader(new FileInputStream(classFile));
|
||
|
// create an empty ClassNode (in-memory representation of a class)
|
||
|
classNode = new ClassNode();
|
||
|
// have the ClassReader read the class file and populate the ClassNode with the corresponding information
|
||
|
cr.accept(classNode, 0);
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
void createControlFlowGraphOfEmptyMethod() {
|
||
|
MethodNode methodNode = getMethod("emptyMethod", "()V");
|
||
|
ControlFlowGraph g = ControlFlowGraphBuilder.createControlFlowGraph(methodNode);
|
||
|
assertEquals(3, g.getNodes().size(), "CFG should contain three basic blocks: entry, exit, and one with code");
|
||
|
BasicBlock bb = ((ControlFlowEdge)g.getEntry().getOutEdges().get(0)).getTo();
|
||
|
final InsnList asmInstructions = methodNode.instructions;
|
||
|
assertEquals(asmInstructions.size(), bb.getInstructionCount(), "basic block's instruction count differs from number of instructions in method node");
|
||
|
for (int i = 0; i < asmInstructions.size(); i++) {
|
||
|
AbstractInsnNode asmInstruction = asmInstructions.get(i);
|
||
|
String asmInstructionAsString = Disassembler.disassembleInstruction(asmInstruction, i, asmInstructions);
|
||
|
String bbInstruction = bb.getInstruction(i);
|
||
|
assertEquals(asmInstructionAsString, bbInstruction, "basic block's instruction string differs from disassembled ASM instruction");
|
||
|
//System.out.println(asmInstructionAsString+" == "+bbInstruction);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
void createControlFlowGraphOfIfMethod() {
|
||
|
MethodNode methodNode = getMethod("ifMethod", "(I)I");
|
||
|
ControlFlowGraph g = ControlFlowGraphBuilder.createControlFlowGraph(methodNode);
|
||
|
assertEquals(5, g.getNodes().size(), "CFG should contain five basic blocks: entry, exit, before if, then, after if");
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
void createControlFlowGraphOfIfElseMethod() {
|
||
|
MethodNode methodNode = getMethod("ifElseMethod", "(I)I");
|
||
|
ControlFlowGraph g = ControlFlowGraphBuilder.createControlFlowGraph(methodNode);
|
||
|
assertEquals(6, g.getNodes().size(), "CFG should contain five basic blocks: entry, exit, before if, then, else, after if");
|
||
|
}
|
||
|
|
||
|
}
|