Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.test4j.mock.processor.filer.MocksFiler Maven / Gradle / Ivy
package org.test4j.mock.processor.filer;
import com.squareup.javapoet.*;
import org.test4j.mock.faking.fluent.MocksApply;
import org.test4j.mock.processor.MocksProcessor;
import org.test4j.mock.processor.filer.attr.ClassNames;
import org.test4j.mock.processor.filer.file.MockClassFiler;
import org.test4j.mock.processor.filer.file.MockTypeFiler;
import org.test4j.mock.processor.filer.file.MockUpFiler;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import java.util.*;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.function.Consumer;
import static org.test4j.mock.processor.MocksProcessor.error;
/**
* MocksFiler
*
* @author wudarui
*/
public class MocksFiler {
private static final Set Has_Mocks = new ConcurrentSkipListSet<>();
private final ClassName fullName;
private final String mocksClass;
private final Map mocks = new HashMap<>();
public MocksFiler(String fullName, String suffix, Set classNames) {
this.fullName = ClassNames.getClassName(fullName);
this.mocksClass = this.fullName.simpleName() + suffix;
this.addToMockClass(classNames);
}
private void addToMockClass(Collection classNames) {
for (ClassName className : classNames) {
this.addMockFile(className);
}
}
private void addMockFile(ClassName className) {
if (className == null) {
return;
}
ClassName mockClassName = ClassNames.mockup(className);
this.mocks.put(className.toString(), mockClassName);
}
public void writeFiler() {
TypeSpec.Builder builder = TypeSpec.classBuilder(mocksClass)
.addModifiers(Modifier.PUBLIC)
.superclass(MocksApply.class);
this.build(builder);
JavaFile.Builder javaBuilder = JavaFile.builder(this.fullName.packageName(), builder.build());
MocksProcessor.writeFiler(javaBuilder.build());
}
/**
* key: toFaked.simpleName(), value: 同名类名出现的次数
*/
private final Map counts = new HashMap<>();
private int count(ClassName toFaked) {
String name = toFaked.simpleName();
Integer count = counts.get(name);
count = count == null ? 0 : count + 1;
counts.put(name, count);
return count;
}
private void build(TypeSpec.Builder spec) {
spec.addField(this.f_mocks(mocksClass))
.addMethod(this.m_mocks(mocksClass));
for (Map.Entry entry : this.mocks.entrySet()) {
ClassName toFaked = ClassNames.getClassName(entry.getKey());
int count = count(toFaked);
if (count > 0) {
toFaked = ClassNames.getClassName(entry.getKey() + "__" + count);
}
spec.addMethod(this.m_mockUp1(toFaked, entry.getValue()));
spec.addMethod(this.m_mockUp2(toFaked, entry.getValue()));
spec.addField(this.f_mockUpField(toFaked, entry.getValue()));
}
while (!this.mocks.isEmpty()) {
Iterator> it = this.mocks.entrySet().iterator();
Map.Entry entry = it.next();
it.remove();
MockUpFiler mockUpFiler = this.generateMockUp(entry.getKey());
if (mockUpFiler == null) {
continue;
}
mockUpFiler.writeFiler();
this.addMockFile(mockUpFiler.getSuperClass());
}
}
private static final String Mock1_JavaDoc = "" +
" mock {@link $T} 多个方法, 示例代码\n" +
" \n" +
" mocks.$L(fake->{\n" +
" fake.toMockMethod1.restReturn(\"返回值1\",\"返回值2\");\n" +
" fake.toMockMethod2.restReturn(\"返回值1\",\"返回值2\");\n" +
" });\n" +
" \n\n" +
" @param faker {@link $LMockUp} 构造\n" +
" @param targets 指定, 表示对特定$L实例进行mock;否则,表示对所有$L实例进行mock";
private static final String Mock2_JavaDoc = "" +
" mock {@link $T} 单个方法, 示例代码\n" +
" \n" +
" mocks.$L().toMockMethod1.restReturn(\"返回值1\",\"返回值2\");\n" +
" \n\n" +
" @param targets 指定, 表示对特定$L实例进行mock;否则,表示对所有$L实例进行mock";
private MethodSpec m_mockUp1(ClassName toFaked, ClassName mockUp) {
String name = toFaked.simpleName();
return MethodSpec.methodBuilder(toFaked.simpleName())
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addJavadoc(Mock1_JavaDoc, toFaked, name, name, name, name)
.addParameter(ParameterizedTypeName.get(ClassName.get(Consumer.class), mockUp), "faker")
.addParameter(ArrayTypeName.of(Object.class), "targets")
.varargs(true)
.returns(TypeVariableName.get(mocksClass))
.addStatement("return super.apply(faker, new $T(targets))", mockUp)
.build();
}
private MethodSpec m_mockUp2(ClassName toFaked, ClassName mockUp) {
String name = toFaked.simpleName();
return MethodSpec.methodBuilder(name)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addJavadoc(Mock2_JavaDoc, toFaked, name, name, name)
.addParameter(ArrayTypeName.of(Object.class), "targets")
.varargs(true)
.returns(mockUp)
.addStatement("return new $T(targets)", mockUp)
.build();
}
private FieldSpec f_mockUpField(ClassName toFaked, ClassName mockUp) {
String name = toFaked.simpleName();
return FieldSpec.builder(mockUp, name, Modifier.FINAL, Modifier.PUBLIC)
.addJavadoc("@see #$L(Object...), 无参模式 ", name)
.initializer("$L()", name)
.build();
}
/**
* 构造public static final XyzMocks mocks = new XyzMocks() 单例变量
*
* @param mocksClass mock class
* @return ignore
*/
private FieldSpec f_mocks(String mocksClass) {
return FieldSpec.builder(ClassNames.getClassName(mocksClass), "mocks", Modifier.FINAL, Modifier.STATIC, Modifier.PUBLIC)
.addJavadoc("" +
"全局变量, 方便在测试方法中引用$L实例\n" +
"每个测试执行完毕, 本实例中定义的mock行为会被清除\n" +
"如果想定义全局mock行为, 使用 mocks()方法引用", mocksClass)
.initializer("mocks()")
.build();
}
private MethodSpec m_mocks(String mocksClass) {
return MethodSpec.methodBuilder("mocks")
.returns(ClassNames.getClassName(mocksClass))
.addModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PUBLIC)
.addJavadoc("$L全局变量, 方便引用", mocksClass)
.addJavadoc("每个测试执行完毕, mock行为会被清除")
.addStatement("return new $L()", mocksClass)
.build();
}
private MockUpFiler generateMockUp(String className) {
if (Has_Mocks.contains(className)) {
return null;
}
Has_Mocks.add(className);
try {
return new MockClassFiler(Class.forName(className));
} catch (ClassNotFoundException e) {
TypeElement typeElement = MocksProcessor.getTypeElement(className);
if (typeElement == null) {
error("ClassNotFoundException", e);
} else {
return new MockTypeFiler(typeElement);
}
}
return null;
}
}