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;
}
}