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

org.test4j.mock.faking.meta.FakeMethods Maven / Gradle / Ivy

package org.test4j.mock.faking.meta;

import g_asm.org.objectweb.asm.Type;
import org.test4j.mock.faking.fluent.FluentMockUp;
import org.test4j.mock.faking.util.ClassLoad;
import org.test4j.mock.faking.util.TypeUtility;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static org.test4j.mock.faking.meta.MethodId.getDesc;
import static org.test4j.mock.faking.meta.MethodId.getName;

/**
 * FakeMethods
 *
 * @author wudarui
 */
@SuppressWarnings("rawtypes")
public class FakeMethods {
    /**
     * mock行为序号
     */
    public final long fakeSeqNo;
    /**
     * mock方法列表
     */
    private final List methods = new ArrayList<>();

    public FakeMethods(long fakeSeqNo) {
        this.fakeSeqNo = fakeSeqNo;
    }

    public boolean isEmpty() {
        return methods.isEmpty();
    }

    public AbstractFake getMockUp() {
        return isEmpty() ? null : methods.get(0).fake;
    }

    public FakeMethod findMethod(MethodId methodId) {
        FakeMethod compatible = null;
        for (FakeMethod method : this.methods) {
            if (!isClassMatch(methodId, method.meta)) {
                continue;
            }
            if (Objects.equals(method.meta.methodDesc, methodId.methodDesc)) {
                return method;
            }
            if (this.isCompatible(method.meta.methodDesc, methodId.methodDesc)) {
                compatible = method;
            }
        }
        return compatible;
    }

    /**
     * 如果是构造函数, 必须是本类
     * 如果是普通函数, 必须是本类或子类
     *
     * @param real real method
     * @param fake fake method
     * @return ignore
     */
    private boolean isClassMatch(MethodId real, MethodId fake) {
        if (Objects.equals(real.declaredClassDesc, fake.declaredClassDesc) || fake.declaredClassDesc == null) {
            return TypeUtility.isAssignable(fake.realClass(), real.realClass());
        } else {
            return false;
        }
    }

    /**
     * 实际声明的方法和fake中定义的方法是否兼容
     *
     * @param fakeDesc     fake method签名
     * @param declaredDesc 声明方法签名
     * @return ignore
     */
    private boolean isCompatible(String fakeDesc, String declaredDesc) {
        if (!Objects.equals(getName(fakeDesc), getName(declaredDesc))) {
            return false;
        }
        Type[] fakeTypes = Type.getArgumentTypes(getDesc(fakeDesc));
        Type[] declaredTypes = Type.getArgumentTypes(getDesc(declaredDesc));
        if (fakeTypes.length != declaredTypes.length) {
            return false;
        }
        for (int index = 0; index < fakeTypes.length; index++) {
            String fakeTypeName = fakeTypes[index].getClassName();
            String declareTypeName = declaredTypes[index].getClassName();
            if (Objects.equals(fakeTypeName, declareTypeName)) {
                continue;
            }
            Class fakeType = ClassLoad.loadClass(fakeTypeName);
            Class declaredType = ClassLoad.loadClass(declareTypeName);
            if (!TypeUtility.isAssignable(declaredType, fakeType)) {
                return false;
            }
        }
        return true;
    }

    public void clear() {
        for (FakeMethod fm : this.methods) {
            if (fm.fake instanceof FluentMockUp) {
                ((FluentMockUp) fm.fake).clear();
            }
        }
        this.methods.clear();
    }

    public void add(FakeMethod fakeMethod) {
        this.methods.add(fakeMethod);
    }

    @Override
    public String toString() {
        return "[" + fakeSeqNo + "]:" + methods;
    }

    /**
     * 是否是FluentMockUp定义的
     */
    public boolean mockByFluent() {
        return this.isEmpty() || this.getMockUp() instanceof FluentMockUp;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy