import org.springframework.util.StringUtils;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Pattern;
public class GenerateUnitTestJava {
public static void main(String[] args) throws Exception {
List<ClassTemplate> l = Scan.scan();
for (ClassTemplate t : l) {
Write.write(t);
}
}
private static class Scan {
static Pattern JAVA_END = Pattern.compile(".+\\.java$");
static Pattern PACKAGE_PT = Pattern.compile(".*package .*;.*");
static List<ClassTemplate> scan() throws Exception {
return scan(new File(Path.find()));
}
static List<ClassTemplate> scan(File f) throws Exception {
if (null == f) {
return Collections.emptyList();
}
if (f.isDirectory()) {
File[] files = f.listFiles();
if (files.length < 1) {
return Collections.emptyList();
}
List<ClassTemplate> r = new ArrayList<>();
for (File f0 : files) {
r.addAll(scan(f0));
}
return r;
}
String fn = f.getName();
if (!JAVA_END.matcher(fn).matches()) {
return Collections.emptyList();
}
List<String> cns = findClassName(f);
List<ClassTemplate> r = new ArrayList<>();
for (String cn : cns) {
try {
Class<?> tClass = Class.forName(cn);
int mds = tClass.getModifiers();
if (tClass.isInterface() || Modifier.isAbstract(mds) || Modifier.isPrivate(mds)) {
continue;
}
r.add(Builder.buildTemplate(tClass));
} catch (Throwable throwable) {
}
}
return r;
}
static List<String> findClassName(File f) throws Exception {
List<String> r = new ArrayList<>();
BufferedReader br = new BufferedReader(new FileReader(f));
String t = null;
while (null != (t=br.readLine()) && !PACKAGE_PT.matcher(t).matches()) {
}
br.close();
if (null == t) {
return Collections.emptyList();
}
int ps = t.indexOf("package ");
String pn = t.substring(ps + 8, t.indexOf(";",ps));
r.add(String.format("%s.%s", pn, f.getName().substring(0, f.getName().length() - 5)));
return r;
}
}
private static class Path {
static String find() {
String p = GenerateUnitTestJava.class.getResource("").getPath();
if (p.contains("/target/test-classes/")) {
p = p.replace("/target/test-classes/", "/");
}
return p;
}
}
private static class Delete {
static boolean delete() throws Exception {
return delete(new File(Path.find()));
}
static boolean delete(File file) throws Exception {
if (null == file) {
return false;
}
String sbp = file.getAbsolutePath();
File f = new File(sbp.replace("/src/main/", "/src/test"));
if (!f.exists()) {
return false;
}
if (f.isDirectory()) {
File[] files = f.listFiles();
if (files.length < 1) {
return false;
}
for (File f0 : files) {
delete(f0);
}
return true;
}
if (!Builder.END_PATTERN.matcher(f.getName()).matches()) {
return false;
}
BufferedReader br = new BufferedReader(new FileReader(f));
String t = br.readLine();
if (!Builder.START_PATTERN.matcher(t).matches()) {
br.close();
return false;
}
String hashCode = t.substring(Builder.START.length());
StringBuilder sb = new StringBuilder();
while ((t=br.readLine()) != null) {
sb.append(t).append("\r\n");
}
br.close();
if (sb.length() > 2) {
sb.delete(sb.length()-2, sb.length());
}
if (!hashCode.equals(String.valueOf(sb.toString().hashCode()))) {
return false;
}
System.out.println(f.getName());
return f.delete();
}
}
private static class Write {
static boolean write(ClassTemplate ct) throws Exception {
if (null == ct || ct.testMethods.isEmpty()) {
return false;
}
String p = Path.find();
String fdp = String.format("%s/src/test/java/%s/", p,
ct.packageName.replace(".", "/"));
File fd = new File(fdp);
if (!fd.exists()) {
fd.mkdirs();
}
String fp = String.format("%s%s.java", fdp, ct.testClassName);
File f = new File(fp);
if (f.exists()) {
return false;
}
String s = Builder.build(ct);
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
bw.write(String.format("%s%s", Builder.START, s.hashCode()));
bw.newLine(); bw.flush();
bw.write(s);bw.flush();
bw.close();
System.out.println(ct.tClass.getName());
return true;
}
}
private static class Builder {
static Pattern END_PATTERN = Pattern.compile(".+AutoTest\\.java$");
static String END = "AutoTest";
static Pattern START_PATTERN = Pattern.compile("^// auto generate @sometwo\\.fun hashCode=\\d+$");
static String START = "// auto generate @sometwo.fun hashCode=";
static List<String> AUTO_SET_ANN = Arrays.asList(
"org.springframework.beans.factory.annotation.Autowired"
);
static String RUN_WITH_STR = "@RunWith(MockitoJUnitRunner.class)";
static String build(ClassTemplate ct) {
StringBuilder sb = new StringBuilder();
sb.append(String.format("package %s;\r\n\r\n", ct.packageName));
for (String s : ct.imports) {
sb.append(String.format("import %s;\r\n", s));
}
sb.append("\r\n");
sb.append(ct.runWithStr).append("\r\n");
sb.append(String.format("public class %s {\r\n", ct.testClassName));
if (ct.tClass.isEnum()) {
sb.append(String.format("private %s %s = %s;\r\n", ct.tClass.getSimpleName(), ct.injectPropertyName, DefaultValue.value(ct.tClass)));
} else {
sb.append("\t@InjectMocks\r\n");
sb.append(String.format("\tprivate %s %s;\r\n", ct.tClass.getSimpleName(), ct.injectPropertyName));
}
for (Map.Entry<String, Class<?>> p : ct.mockProperties.entrySet()) {
sb.append("\t@Mock\r\n");
sb.append(String.format("\tprivate %s %s;\r\n", p.getValue().getSimpleName(), p.getKey()));
}
sb.append("\r\n\t@Before\r\n");
sb.append(String.format("\tpublic void before%s () {\r\n", System.currentTimeMillis()));
for (String s : ct.beforeMethodLines) {
sb.append(String.format("\t\t%s\r\n", s));
}
sb.append("\t}");
for (Map.Entry<String, List<String>> m : ct.testMethods.entrySet()) {
sb.append("\r\n\r\n\t@Test\r\n");
sb.append(String.format("\tpublic void %sAutoTest () {\r\n", m.getKey()));
sb.append("\t\ttry {\r\n");
for (String s : m.getValue()) {
sb.append("\t\t\t").append(s);
}
sb.append("\r\n\t\t} catch (Throwable throwable) {\r\n\t\t\t// default\r\n\t\t}\r\n");
sb.append("\t}");
}
sb.append("\r\n}");
return sb.toString();
}
static ClassTemplate buildTemplate(Class<?> tClass) {
ClassTemplate ct = new ClassTemplate();
ct.tClass = tClass;
ct.injectPropertyName = StringUtils.uncapitalize(tClass.getSimpleName());
ct.packageName = tClass.getPackage().getName();
ct.runWithStr = RUN_WITH_STR;
ct.testClassName = (tClass.getSimpleName() + Builder.END).replace(".", "");
ct.imports.add("org.junit.*");
ct.imports.add("org.junit.runner.RunWith");
ct.imports.add("org.mockito.junit.MockitoJUnitRunner");
ct.imports.add("org.mockito.*");
ct.beforeMethodLines.add("MockitoAnnotations.initMocks(this);");
buildMockProperty(tClass, ct);
buildConstructMethod(tClass, ct);
buildMethod(tClass, ct);
ct.imports.remove(tClass.getName());
return ct;
}
static void buildMethod(Class<?> tClass, ClassTemplate ct) {
Method[] dms = tClass.getDeclaredMethods();
for (Method dm : dms) {
int m = dm.getModifiers();
if (Modifier.isPrivate(m)) {
continue;
}
StringBuilder s = new StringBuilder(ct.injectPropertyName)
.append(".")
.append(dm.getName())
.append("(");
Class<?>[] pts = dm.getParameterTypes();
for (Class<?> pt : pts) {
s.append(DefaultValue.value(pt)).append(",");
}
if (",".charAt(0) == s.charAt(s.length()-1)) {
s.deleteCharAt(s.length()-1);
}
s.append(");");
String n = dm.getName();
while (ct.testMethods.containsKey(n)) {
n += "1";
}
ct.testMethods.put(n, Collections.singletonList(s.toString()));
}
}
static void buildConstructMethod(Class<?> tClass, ClassTemplate ct) {
Constructor<?>[] dcs = tClass.getDeclaredConstructors();
for (Constructor<?> dc : dcs) {
int m = dc.getModifiers();
if (Modifier.isPrivate(m)) {
continue;
}
StringBuilder s = new StringBuilder("new ").append(tClass.getSimpleName()).append("(");
Class<?>[] pts = dc.getParameterTypes();
for (Class<?> pt : pts) {
s.append(DefaultValue.value(pt)).append(",");
}
if (",".charAt(0) == s.charAt(s.length()-1)) {
s.deleteCharAt(s.length()-1);
}
s.append(");");
String n = "constructor";
while (ct.testMethods.containsKey(n)) {
n += "1";
}
ct.testMethods.put(n, Collections.singletonList(s.toString()));
}
}
static void buildMockProperty(Class<?> tClass, ClassTemplate ct) {
Field[] dfs = tClass.getDeclaredFields();
for (Field fd : dfs) {
Annotation[] as = fd.getAnnotations();
if (as.length < 1) {
continue;
}
for (Annotation a : as) {
for (String s : AUTO_SET_ANN) {
if (a.toString().contains(s)) {
ct.mockProperties.put(fd.getName(), fd.getType());
ct.imports.add(fd.getType().getName());
break;
}
}
}
}
}
}
private static class ClassTemplate {
Class<?> tClass;
String packageName;
Set<String> imports = new HashSet<>();
String testClassName;
String runWithStr;
String injectPropertyName;
Map<String, Class<?>> mockProperties = new HashMap<>();
List<String> beforeMethodLines = new ArrayList<>();
Map<String, List<String>> testMethods = new HashMap<>();
}
private static class DefaultValue {
static Map<Class<?>, String> valMap;
static {
valMap = new HashMap<>();
valMap.put(null, "null");
valMap.put(Integer.class, "1");
valMap.put(int.class, "11");
valMap.put(Long.class, "2L");
valMap.put(long.class, "22");
valMap.put(Short.class, "(short) 3");
valMap.put(short.class, "(short) 33");
valMap.put(Double.class, "4D");
valMap.put(double.class, "44D");
valMap.put(BigDecimal.class, "new BigDecimal(5)");
valMap.put(Boolean.class, "true");
valMap.put(boolean.class, "true");
valMap.put(Class.class, "Object.class");
}
static String value(Class<?> clzss) {
if (valMap.containsKey(clzss)) {
return valMap.get(clzss);
}
if (clzss.isArray()) {
return "{}";
}
if (clzss.isEnum()) {
Field[] df = clzss.getDeclaredFields();
for (Field f : df) {
if (f.isEnumConstant()) {
return String.format("%s.%s", clzss.getSimpleName(), f.getName());
}
}
}
return String.format("Mock(%s.class)", clzss.getSimpleName());
}
}
}
|