All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.test4j.mock.faking.FakeInvoker Maven / Gradle / Ivy

package org.test4j.mock.faking;

import g_asm.org.objectweb.asm.Type;
import org.test4j.mock.Invocation;
import org.test4j.mock.MockUp;
import org.test4j.mock.faking.fluent.FluentMockUp;
import org.test4j.mock.faking.meta.FakeInvocation;
import org.test4j.mock.faking.meta.FakeMethod;
import org.test4j.mock.faking.modifier.BridgeFakeInvocation;
import org.test4j.mock.faking.modifier.BridgeTransformer;
import org.test4j.mock.faking.util.ClassLoad;
import org.test4j.mock.faking.util.ReflectUtility;
import org.test4j.mock.faking.util.TypeUtility;

import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.util.Objects;

import static org.test4j.mock.faking.modifier.BridgeFakeInvocation.Enter_Non_Mock_Block;
import static org.test4j.mock.faking.util.ReflectUtility.invoke;

/**
 * 执行调用{@link MockUp} 的mock操作
 *
 * @author darui.wu
 */
public class FakeInvoker {
    /**
     * 真实对象实例, not MockUp instance
     */
    private final Object target;
    /**
     * new MockUp()实例
     */
    private final FakeMethod fakeMethod;
    /**
     * 真实对象对应类名称描述 (L....;)
     */
    private final String realClassDesc;
    /**
     * 真实方法的方法名称
     */
    private final String methodName;
    /**
     * 真实方法的参数描述
     */
    private final String paramsDesc;

    /**
     * args of method, 第一个参数可能是Invocation
     */
    private final Object[] args;

    public FakeInvoker(Object target, FakeMethod fakeMethod, Class realClass, Method method, Object[] args) {
        this.target = target;
        this.fakeMethod = fakeMethod;
        this.realClassDesc = TypeUtility.classPath(realClass);
        this.methodName = method.getName();
        this.paramsDesc = Type.getMethodDescriptor(method);
        this.args = args;
    }

    public FakeInvoker(Object target, FakeMethod fakeMethod, String realClassDesc, String methodName,
                       String paramsDesc, Object[] args) {
        this.target = target;
        this.fakeMethod = fakeMethod;
        this.realClassDesc = realClassDesc;
        this.methodName = methodName;
        this.paramsDesc = paramsDesc;
        this.args = args;
    }

    /**
     * 执行具体的fake逻辑
     * 

* called by {@link BridgeFakeInvocation#invoke(Object, Method, Object[])} * * @return */ public Object callFakeMethod() { assert fakeMethod != null; if (this.fakeMethod.fake instanceof FluentMockUp) { return this.callFluentMockUpInvocation(); } else if (this.fakeMethod.meta.hasInvocation) { return this.callMockWithInvocation(); } else { return callMockWithoutInvocation(this.fakeMethod, args); } } private Object callFluentMockUpInvocation() { return ((FluentMockUp) this.fakeMethod.fake).invoke(this.newInvocation(), fakeMethod.meta.methodDesc, args); } /** * 调用没有 Invocation 参数的mock方法 * * @return */ public static Object callMockWithoutInvocation(FakeMethod fakeMethod, Object[] args) { Method method = fakeMethod.findMockMethod(); return invoke(method, () -> method.invoke(fakeMethod.fake, args)); } /** * 调用带 Invocation参数的mock方法 * * @return */ private Object callMockWithInvocation() { if (this.isCallSuperOverrideMethod()) { return Enter_Non_Mock_Block; } else { Invocation invocation = this.newInvocation(); Object result = callMockWithInvocation(this.fakeMethod, invocation, args); if (invocation instanceof FakeInvocation && ((FakeInvocation) invocation).isProceedIntoConstructor()) { return Enter_Non_Mock_Block; } else { return result; } } } /** * 是否进入了重载方法调用 * super.sameName(same para type) * * @return */ private boolean isCallSuperOverrideMethod() { /** mock 静态方法 **/ FakeInvocation invocation = this.fakeMethod.getProceedingInvocation(); if (target == null || invocation == null) { return false; } Executable executable = invocation.getInvokedMember(); if (target == invocation.getTarget() && executable instanceof Method) { String invokedClassDesc = TypeUtility.classPath(executable.getDeclaringClass()); return !Objects.equals(invokedClassDesc, realClassDesc); } else { return false; } } public static Object callMockWithInvocation(FakeMethod fakeMethod, Invocation inv, Object[] args) { Object[] args2 = new Object[1 + args.length]; args2[0] = inv; if (args.length > 0) { System.arraycopy(args, 0, args2, 1, args.length); } Method method = fakeMethod.findMockMethod(); return invoke(method, () -> method.invoke(fakeMethod.fake, args2)); } protected Invocation newInvocation() { Class fakedClass = ClassLoad.loadClass(realClassDesc); Executable invokedMember = ReflectUtility.findMethodByDesc(fakedClass, methodName, paramsDesc); return new FakeInvocation(target, args, fakeMethod, invokedMember); } public static String getHostClassName() { return BridgeTransformer.initBridgeField(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy