package de.tutorials.testing;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({
"de.tutorials.testing.Testing.Tested",
"de.tutorials.testing.Testing.NotTested" })
public class Testing extends AbstractProcessor {
@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE })
public static @interface Tested {
}
@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE })
public static @interface NotTested {
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(Tested.class)) {
switch (element.asType().getKind()) {
case DECLARED:
processingEnv.getMessager().printMessage(Kind.NOTE, "generateTestCase for " + element, element);
generateTestCase(element);
break;
default:
;
}
}
return true;
}
private void generateTestCase(Element element) {
TypeElement clazz = (TypeElement) element;
List<? extends Element> allMembers = processingEnv.getElementUtils().getAllMembers(clazz);
try {
String classNameSuffix = "Test";
JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(clazz.getQualifiedName() + classNameSuffix, clazz);
FileObject res = processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, "", "generated_tests.txt");
try (PrintWriter sourceWriter = new PrintWriter(sourceFile.openWriter());
PrintWriter resWriter = new PrintWriter(res.openWriter())) {
sourceWriter.println(processingEnv.getElementUtils().getPackageOf(element).toString()+ ";");
sourceWriter.println("import org.junit.Test;");
sourceWriter.println("import static org.junit.Assert.*;");
sourceWriter.println("import javax.annotation.Generated;");
sourceWriter.println("@Generated(\"" + getClass().getName()+ "\")");
sourceWriter.println("public class " + clazz.getSimpleName()+ classNameSuffix + " {");
for (Element member : allMembers) {
switch (member.getKind()) {
case METHOD:
if (skipTestMethodGeneration(clazz, member)) {
continue;
}
String qualifiedTestMethodName = generateTestMethod(clazz, member, sourceWriter);
resWriter.println(qualifiedTestMethodName);
break;
default:
break;
}
}
sourceWriter.println("}");
}
} catch (IOException e) {
e.printStackTrace();
}
}
private boolean skipTestMethodGeneration(Element clazz, Element member) {
boolean hasNotTestedAnnotation = member.getAnnotation(NotTested.class) != null;
boolean sameType = processingEnv.getTypeUtils().isSameType(
member.getEnclosingElement().asType(), clazz.asType());
return hasNotTestedAnnotation || !sameType;
}
private String generateTestMethod(TypeElement clazz, Element member,
PrintWriter sourceWriter) {
String testMethodName = member.getSimpleName().charAt(0) == '<' /*
* <init>
*/? "constructor"
: member.getSimpleName().toString();
sourceWriter.println(" @Test ");
sourceWriter.println(" public void " + testMethodName + "() {");
sourceWriter.println(" fail(\"test: " + testMethodName + " not implemented yet\");");
sourceWriter.println(" }");
return clazz.getQualifiedName() + "." + testMethodName;
}
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
}
}