package me.lzb.jvm;
import me.lzb.common.utils.ByteUtils;
import me.lzb.jvm.clz.ClassFile;
import me.lzb.jvm.clz.ClassIndex;
import me.lzb.jvm.cmd.BiPushCmd;
import me.lzb.jvm.cmd.ByteCodeCommand;
import me.lzb.jvm.cmd.OneOperandCmd;
import me.lzb.jvm.cmd.TwoOperandCmd;
import me.lzb.jvm.constant.*;
import me.lzb.jvm.field.Field;
import me.lzb.jvm.loader.ClassFileLoader;
import me.lzb.jvm.method.Method;
import me.lzb.jvm.print.ClassPrinter;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
public class ClassFileloaderTest {
static String path1 = EmployeeV1.class.getResource("/").getPath();
static String path2 = "C:\\temp";
static String className = "me.lzb.jvm.EmployeeV1";
private static final String FULL_QUALIFIED_CLASS_NAME = "me/lzb/jvm/EmployeeV1";
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void testPath() {
String s = EmployeeV1.class.getResource("/").getPath();
String s2 = EmployeeV1.class.getResource("").getPath();
// System.out.println(s);
// System.out.println(s2);
}
@Test
public void testClassPath() {
ClassFileLoader loader = new ClassFileLoader();
loader.addClassPath(path1);
loader.addClassPath(path2);
String clzPath = loader.getClassPath();
Assert.assertEquals(path1 + ";" + path2, clzPath);
}
@Test
public void testClassFileLength() throws Exception {
ClassFileLoader loader = new ClassFileLoader();
loader.addClassPath(path1);
byte[] byteCodes = loader.readBinaryCode(className);
Assert.assertEquals(1030, byteCodes.length);
}
@Test
public void testMagicNumber() throws Exception {
ClassFileLoader loader = new ClassFileLoader();
loader.addClassPath(path1);
byte[] byteCodes = loader.readBinaryCode(className);
byte[] codes = new byte[]{byteCodes[0], byteCodes[1], byteCodes[2], byteCodes[3]};
String acctualValue = ByteUtils.byteToHexString(codes);
Assert.assertEquals("cafebabe", acctualValue);
}
static ClassFile clzFile = null;
static {
ClassFileLoader loader = new ClassFileLoader();
loader.addClassPath(path1);
clzFile = loader.loadClass(className);
clzFile.print();
}
@Test
public void testVersion() {
Assert.assertEquals(0, clzFile.getMinorVersion());
Assert.assertEquals(52, clzFile.getMajorVersion());
}
@Test
public void testConstantPool() {
ConstantPool pool = clzFile.getConstantPool();
Assert.assertEquals(53, pool.getSize());
{
ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(7);
Assert.assertEquals(44, clzInfo.getUtf8Index());
UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(44);
Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, utf8Info.getValue());
}
{
ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(11);
Assert.assertEquals(48, clzInfo.getUtf8Index());
UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(48);
Assert.assertEquals("java/lang/Object", utf8Info.getValue());
}
{
UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(12);
Assert.assertEquals("name", utf8Info.getValue());
utf8Info = (UTF8Info) pool.getConstantInfo(13);
Assert.assertEquals("Ljava/lang/String;", utf8Info.getValue());
utf8Info = (UTF8Info) pool.getConstantInfo(14);
Assert.assertEquals("age", utf8Info.getValue());
utf8Info = (UTF8Info) pool.getConstantInfo(15);
Assert.assertEquals("I", utf8Info.getValue());
utf8Info = (UTF8Info) pool.getConstantInfo(16);
Assert.assertEquals("<init>", utf8Info.getValue());
utf8Info = (UTF8Info) pool.getConstantInfo(17);
Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue());
utf8Info = (UTF8Info) pool.getConstantInfo(18);
Assert.assertEquals("Code", utf8Info.getValue());
}
{
MethodRefInfo methodRef = (MethodRefInfo) pool.getConstantInfo(1);
Assert.assertEquals(11, methodRef.getClassInfoIndex());
Assert.assertEquals(36, methodRef.getNameAndTypeIndex());
}
{
NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(36);
Assert.assertEquals(16, nameAndType.getIndex1());
Assert.assertEquals(28, nameAndType.getIndex2());
}
//抽查几个吧
{
MethodRefInfo methodRef = (MethodRefInfo) pool.getConstantInfo(10);
Assert.assertEquals(7, methodRef.getClassInfoIndex());
Assert.assertEquals(47, methodRef.getNameAndTypeIndex());
}
{
UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(35);
Assert.assertEquals("EmployeeV1.java", utf8Info.getValue());
}
}
@Test
public void testClassIndex() {
ClassIndex clzIndex = clzFile.getClzIndex();
ClassInfo thisClassInfo = (ClassInfo) clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex());
ClassInfo superClassInfo = (ClassInfo) clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex());
Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName());
Assert.assertEquals("java/lang/Object", superClassInfo.getClassName());
}
/**
* 下面是第三次JVM课应实现的测试用例
*/
@Test
public void testReadFields() {
List<Field> fields = clzFile.getFields();
Assert.assertEquals(2, fields.size());
{
Field f = fields.get(0);
Assert.assertEquals("name:Ljava/lang/String;", f.toString());
}
{
Field f = fields.get(1);
Assert.assertEquals("age:I", f.toString());
}
}
@Test
public void testMethods() {
List<Method> methods = clzFile.getMethods();
ConstantPool pool = clzFile.getConstantPool();
{
Method m = methods.get(0);
assertMethodEquals(pool, m,
"<init>",
"(Ljava/lang/String;I)V",
"2ab700012a2bb500022a1cb50003b1");
}
{
Method m = methods.get(1);
assertMethodEquals(pool, m,
"setName",
"(Ljava/lang/String;)V",
"2a2bb50002b1");
}
{
Method m = methods.get(2);
assertMethodEquals(pool, m,
"setAge",
"(I)V",
"2a1bb50003b1");
}
{
Method m = methods.get(3);
assertMethodEquals(pool, m,
"sayHello",
"()V",
"b200041205b60006b1");
}
{
Method m = methods.get(4);
assertMethodEquals(pool, m,
"main",
"([Ljava/lang/String;)V",
"bb0007591208101db700094c2bb6000ab1");
}
}
private void assertMethodEquals(ConstantPool pool, Method m, String expectedName, String expectedDesc, String expectedCode) {
String methodName = pool.getUTF8String(m.getNameIndex());
String methodDesc = pool.getUTF8String(m.getDescriptorIndex());
String code = m.getCodeAttr().getCode();
Assert.assertEquals(expectedName, methodName);
Assert.assertEquals(expectedDesc, methodDesc);
Assert.assertEquals(expectedCode, code);
}
/**
* 第四次JVM
*/
@Test
public void testByteCodeCommand() {
{
Method initMethod = this.clzFile.getMethod("<init>", "(Ljava/lang/String;I)V");
ByteCodeCommand[] cmds = initMethod.getCmds();
assertOpCodeEquals("0: aload_0", cmds[0]);
assertOpCodeEquals("1: invokespecial #1", cmds[1]);
assertOpCodeEquals("4: aload_0", cmds[2]);
assertOpCodeEquals("5: aload_1", cmds[3]);
assertOpCodeEquals("6: putfield #2", cmds[4]);
assertOpCodeEquals("9: aload_0", cmds[5]);
assertOpCodeEquals("10: iload_2", cmds[6]);
assertOpCodeEquals("11: putfield #3", cmds[7]);
assertOpCodeEquals("14: return", cmds[8]);
}
{
Method setNameMethod = this.clzFile.getMethod("setName", "(Ljava/lang/String;)V");
ByteCodeCommand[] cmds = setNameMethod.getCmds();
assertOpCodeEquals("0: aload_0", cmds[0]);
assertOpCodeEquals("1: aload_1", cmds[1]);
assertOpCodeEquals("2: putfield #2", cmds[2]);
assertOpCodeEquals("5: return", cmds[3]);
}
{
Method sayHelloMethod = this.clzFile.getMethod("sayHello", "()V");
ByteCodeCommand[] cmds = sayHelloMethod.getCmds();
assertOpCodeEquals("0: getstatic #4", cmds[0]);
assertOpCodeEquals("3: ldc #5", cmds[1]);
assertOpCodeEquals("5: invokevirtual #6", cmds[2]);
assertOpCodeEquals("8: return", cmds[3]);
}
{
Method mainMethod = this.clzFile.getMainMethod();
ByteCodeCommand[] cmds = mainMethod.getCmds();
assertOpCodeEquals("0: new #7", cmds[0]);
assertOpCodeEquals("3: dup", cmds[1]);
assertOpCodeEquals("4: ldc #8", cmds[2]);
assertOpCodeEquals("6: bipush 29", cmds[3]);
assertOpCodeEquals("8: invokespecial #9", cmds[4]);
assertOpCodeEquals("11: astore_1", cmds[5]);
assertOpCodeEquals("12: aload_1", cmds[6]);
assertOpCodeEquals("13: invokevirtual #10", cmds[7]);
assertOpCodeEquals("16: return", cmds[8]);
}
}
private void assertOpCodeEquals(String expected, ByteCodeCommand cmd) {
String acctual = cmd.getOffset() + ": " + cmd.getReadableCodeText();
if (cmd instanceof OneOperandCmd) {
if (cmd instanceof BiPushCmd) {
acctual += " " + ((OneOperandCmd) cmd).getOperand();
} else {
acctual += " #" + ((OneOperandCmd) cmd).getOperand();
}
}
if (cmd instanceof TwoOperandCmd) {
acctual += " #" + ((TwoOperandCmd) cmd).getIndex();
}
Assert.assertEquals(expected, acctual);
}
@Test
public void testPrint() {
ClassPrinter classPrinter = new ClassPrinter(clzFile);
classPrinter.print();
}
}