/*
* Copyright (c) 2013-2015 Chris Newland.
* Licensed under https://github.com/AdoptOpenJDK/jitwatch/blob/master/LICENSE-BSD
* Instructions: https://github.com/AdoptOpenJDK/jitwatch/wiki
*/
package org.adoptopenjdk.jitwatch.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_TYPE_NAME_VOID;
import org.adoptopenjdk.jitwatch.loader.BytecodeLoader;
import org.adoptopenjdk.jitwatch.logger.NullLogListener;
import org.adoptopenjdk.jitwatch.model.MemberSignatureParts;
import org.adoptopenjdk.jitwatch.model.bytecode.ClassBC;
import org.adoptopenjdk.jitwatch.model.bytecode.MemberBytecode;
import org.adoptopenjdk.jitwatch.model.bytecode.SourceMapper;
import org.adoptopenjdk.jitwatch.process.compiler.CompilerJava;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/*
javap -v * | egrep "Classfile|line|public"
Classfile /home/chris/.pp/jitwatch/sandbox/classes/TestInner.class
public TestInner();
line 4: 0
line 5: 4
line 7: 12
line 9: 16
line 10: 25
public void a();
line 14: 0
line 15: 8
public static void main(java.lang.String[]);
line 52: 0
line 53: 8
Classfile /home/chris/.pp/jitwatch/sandbox/classes/TestInner$Inner1.class
public TestInner$Inner1(TestInner);
line 20: 0
line 21: 9
line 23: 17
line 25: 21
line 26: 30
public void b();
line 30: 0
line 31: 8
Classfile /home/chris/.pp/jitwatch/sandbox/classes/TestInner$Inner1$Inner2.class
public TestInner$Inner1$Inner2(TestInner$Inner1);
line 36: 0
line 37: 9
line 39: 17
line 40: 21
public void c();
line 44: 0
line 45: 8
*/
public class TestBytecodeLoaderWithInnerClasses
{
private String classNameOuter = "TestInner";
private String classNameInner1 = "TestInner$Inner1";
private String classNameInner2 = "TestInner$Inner1$Inner2";
private Path pathToSourceDir;
private Path pathToTempClassDir;
private List<String> classpathLocations;
private ClassBC classBytecodeForOuter;
private ClassBC classBytecodeForInner1;
private ClassBC classBytecodeForInner2;
@Before
public void setUp()
{
try
{
SourceMapper.clear();
pathToSourceDir = Paths.get("src", "main", "resources", "examples");
pathToTempClassDir = Files.createTempDirectory("testInnerClasses");
Path pathToSourceFile = Paths.get(pathToSourceDir.toString(), classNameOuter + ".java");
List<File> sources = new ArrayList<>();
sources.add(pathToSourceFile.toFile());
classpathLocations = new ArrayList<String>();
classpathLocations.add(pathToTempClassDir.toString());
CompilerJava compiler = new CompilerJava(System.getProperty("java.home"));
List<String> compileClasspath = new ArrayList<>();
boolean success = compiler.compile(sources, compileClasspath, pathToTempClassDir.toFile(), new NullLogListener());
if (!success)
{
System.err.println(compiler.getErrorStream());
fail();
}
}
catch (Exception e)
{
e.printStackTrace();
fail();
}
classBytecodeForOuter = BytecodeLoader.fetchBytecodeForClass(classpathLocations, classNameOuter, true);
BytecodeLoader.fetchBytecodeForClass(classpathLocations, classNameInner1, true);
BytecodeLoader.fetchBytecodeForClass(classpathLocations, classNameInner2, true);
List<ClassBC> classBytecodeListForOuter = SourceMapper.getClassBytecodeList(classBytecodeForOuter);
classBytecodeForOuter = classBytecodeListForOuter.get(0);
classBytecodeForInner1 = classBytecodeListForOuter.get(1);
classBytecodeForInner2 = classBytecodeListForOuter.get(2);
}
@After
public void tearDown()
{
}
private void checkMemberNames(ClassBC classBytecode, String... memberNames)
{
List<MemberBytecode> memberBytecodeList = classBytecode.getMemberBytecodeList();
Set<String> memberNameSet = new HashSet<>(Arrays.asList(memberNames));
for (MemberBytecode memberBytecode : memberBytecodeList)
{
assertTrue(memberNameSet.contains(memberBytecode.getMemberSignatureParts().getMemberName()));
}
assertEquals(memberNames.length, memberBytecodeList.size());
}
@Test
public void testCompilationCreatedCorrectOutputs()
{
assertTrue(Paths.get(pathToTempClassDir.toString(), classNameOuter + ".class").toFile().exists());
assertTrue(Paths.get(pathToTempClassDir.toString(), classNameInner1 + ".class").toFile().exists());
assertTrue(Paths.get(pathToTempClassDir.toString(), classNameInner2 + ".class").toFile().exists());
assertEquals(classNameOuter + ".java", classBytecodeForOuter.getSourceFile());
checkMemberNames(classBytecodeForOuter, "main", "TestInner", "a");
List<String> innerClasses = classBytecodeForOuter.getInnerClassNames();
assertEquals(1, innerClasses.size());
assertEquals(classNameInner1, innerClasses.get(0));
assertEquals(classNameOuter + ".java", classBytecodeForInner1.getSourceFile());
checkMemberNames(classBytecodeForInner1, "TestInner$Inner1", "b");
List<String> innerClassesOfInner1 = classBytecodeForInner1.getInnerClassNames();
assertEquals(1, innerClassesOfInner1.size());
assertEquals(classNameInner2, innerClassesOfInner1.get(0));
assertEquals(classNameOuter + ".java", classBytecodeForInner2.getSourceFile());
checkMemberNames(classBytecodeForInner2, "TestInner$Inner1$Inner2", "c");
List<ClassBC> classBytecodeListForOuter = SourceMapper.getClassBytecodeList(classBytecodeForOuter);
assertNotNull(classBytecodeListForOuter);
assertEquals(3, classBytecodeListForOuter.size());
}
@Test
public void testSearchFromSourceOuterClassConstructor()
{
String fqClassNameOuter = classBytecodeForOuter.getFullyQualifiedClassName();
assertEquals(classNameOuter, fqClassNameOuter);
MemberBytecode memberBytecodeForConstructor = SourceMapper.getMemberBytecodeForSourceLine(classBytecodeForOuter, 4);
assertNotNull(memberBytecodeForConstructor);
MemberSignatureParts mspOuterConstructor = memberBytecodeForConstructor.getMemberSignatureParts();
assertNotNull(mspOuterConstructor);
assertEquals(S_TYPE_NAME_VOID, mspOuterConstructor.getReturnType());
assertEquals(0, mspOuterConstructor.getParamTypes().size());
assertEquals(classNameOuter, mspOuterConstructor.getMemberName());
}
@Test
public void testSearchFromSourceOuterClassMethod()
{
MemberBytecode memberBytecodeForMethod = SourceMapper.getMemberBytecodeForSourceLine(classBytecodeForOuter, 14);
assertNotNull(memberBytecodeForMethod);
MemberSignatureParts mspOuterMethod = memberBytecodeForMethod.getMemberSignatureParts();
assertNotNull(mspOuterMethod);
assertEquals(S_TYPE_NAME_VOID, mspOuterMethod.getReturnType());
assertEquals(0, mspOuterMethod.getParamTypes().size());
assertEquals("a", mspOuterMethod.getMemberName());
}
@Test
public void testSearchFromSourceInner1ClassConstructor()
{
String fqClassNameInner1 = classBytecodeForInner1.getFullyQualifiedClassName();
assertEquals(classNameInner1, fqClassNameInner1);
MemberBytecode memberBytecodeForInner1Constructor = SourceMapper.getMemberBytecodeForSourceLine(classBytecodeForInner1, 20);
assertNotNull(memberBytecodeForInner1Constructor);
MemberSignatureParts mspInner1Constructor = memberBytecodeForInner1Constructor.getMemberSignatureParts();
assertNotNull(mspInner1Constructor);
assertEquals(S_TYPE_NAME_VOID, mspInner1Constructor.getReturnType());
assertEquals(1, mspInner1Constructor.getParamTypes().size());
assertEquals(classNameOuter, mspInner1Constructor.getParamTypes().get(0));
assertEquals(classNameInner1, mspInner1Constructor.getMemberName());
}
@Test
public void testSearchFromSourceInner1ClassMethod()
{
MemberBytecode memberBytecodeForInner1Method = SourceMapper.getMemberBytecodeForSourceLine(classBytecodeForInner1, 30);
assertNotNull(memberBytecodeForInner1Method);
MemberSignatureParts mspInner1Method = memberBytecodeForInner1Method.getMemberSignatureParts();
assertNotNull(mspInner1Method);
assertEquals(S_TYPE_NAME_VOID, mspInner1Method.getReturnType());
assertEquals(0, mspInner1Method.getParamTypes().size());
assertEquals("b", mspInner1Method.getMemberName());
}
@Test
public void testSearchFromSourceInner2ClassConstructor()
{
String fqClassNameInner2 = classBytecodeForInner2.getFullyQualifiedClassName();
assertEquals(classNameInner2, fqClassNameInner2);
MemberBytecode memberBytecodeForInner2Constructor = SourceMapper.getMemberBytecodeForSourceLine(classBytecodeForInner2, 36);
assertNotNull(memberBytecodeForInner2Constructor);
MemberSignatureParts mspInner2Constructor = memberBytecodeForInner2Constructor.getMemberSignatureParts();
assertNotNull(mspInner2Constructor);
assertEquals(S_TYPE_NAME_VOID, mspInner2Constructor.getReturnType());
assertEquals(1, mspInner2Constructor.getParamTypes().size());
assertEquals(classNameInner1, mspInner2Constructor.getParamTypes().get(0));
assertEquals(classNameInner2, mspInner2Constructor.getMemberName());
}
@Test
public void testSearchFromSourceInner2ClassMethod()
{
MemberBytecode memberBytecodeForInner2Method = SourceMapper.getMemberBytecodeForSourceLine(classBytecodeForInner2, 44);
assertNotNull(memberBytecodeForInner2Method);
MemberSignatureParts mspInner2Method = memberBytecodeForInner2Method.getMemberSignatureParts();
assertNotNull(mspInner2Method);
assertEquals(S_TYPE_NAME_VOID, mspInner2Method.getReturnType());
assertEquals(0, mspInner2Method.getParamTypes().size());
assertEquals("c", mspInner2Method.getMemberName());
}
@Test
public void testSearchFromBytecodeOuterClassConstructor()
{
MemberBytecode memberBytecode = SourceMapper.getMemberBytecodeForSourceLine(classBytecodeForOuter, 4);
// line 4: 0
// line 5: 4
// line 7: 12
// line 9: 16
// line 10: 25
assertEquals(4, SourceMapper.getSourceLineFromBytecode(memberBytecode, 0));
assertEquals(5, SourceMapper.getSourceLineFromBytecode(memberBytecode, 4));
assertEquals(7, SourceMapper.getSourceLineFromBytecode(memberBytecode, 12));
assertEquals(9, SourceMapper.getSourceLineFromBytecode(memberBytecode, 16));
assertEquals(10, SourceMapper.getSourceLineFromBytecode(memberBytecode, 25));
}
@Test
public void testSearchFromBytecodeOuterClassMethod()
{
MemberBytecode memberBytecode = SourceMapper.getMemberBytecodeForSourceLine(classBytecodeForOuter, 14);
// line 14: 0
// line 15: 8
assertEquals(14, SourceMapper.getSourceLineFromBytecode(memberBytecode, 0));
assertEquals(15, SourceMapper.getSourceLineFromBytecode(memberBytecode, 8));
}
@Test
public void testSearchFromBytecodeInner1ClassConstructor()
{
MemberBytecode memberBytecode = SourceMapper.getMemberBytecodeForSourceLine(classBytecodeForInner1, 20);
// line 20: 0
// line 21: 9
// line 23: 17
// line 25: 21
// line 26: 30
assertEquals(20, SourceMapper.getSourceLineFromBytecode(memberBytecode, 0));
assertEquals(21, SourceMapper.getSourceLineFromBytecode(memberBytecode, 9));
assertEquals(23, SourceMapper.getSourceLineFromBytecode(memberBytecode, 17));
assertEquals(25, SourceMapper.getSourceLineFromBytecode(memberBytecode, 21));
assertEquals(26, SourceMapper.getSourceLineFromBytecode(memberBytecode, 30));
}
@Test
public void testSearchFromBytecodeInner1ClassMethod()
{
MemberBytecode memberBytecode = SourceMapper.getMemberBytecodeForSourceLine(classBytecodeForInner1, 30);
// line 30: 0
// line 31: 8
assertEquals(30, SourceMapper.getSourceLineFromBytecode(memberBytecode, 0));
assertEquals(31, SourceMapper.getSourceLineFromBytecode(memberBytecode, 8));
}
@Test
public void testSearchFromBytecodeInner2ClassConstructor()
{
MemberBytecode memberBytecode = SourceMapper.getMemberBytecodeForSourceLine(classBytecodeForInner2, 36);
// line 36: 0
// line 37: 9
// line 39: 17
// line 40: 21
assertEquals(36, SourceMapper.getSourceLineFromBytecode(memberBytecode, 0));
assertEquals(37, SourceMapper.getSourceLineFromBytecode(memberBytecode, 9));
assertEquals(39, SourceMapper.getSourceLineFromBytecode(memberBytecode, 17));
assertEquals(40, SourceMapper.getSourceLineFromBytecode(memberBytecode, 21));
}
@Test
public void testSearchFromBytecodeInner2ClassMethod()
{
MemberBytecode memberBytecode = SourceMapper.getMemberBytecodeForSourceLine(classBytecodeForInner2, 44);
// line 44: 0
// line 45: 8
assertEquals(44, SourceMapper.getSourceLineFromBytecode(memberBytecode, 0));
assertEquals(45, SourceMapper.getSourceLineFromBytecode(memberBytecode, 8));
}
}