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

com.vocalabs.egtest.processor.junit.JUnitExampleWriter Maven / Gradle / Ivy

package com.vocalabs.egtest.processor.junit;


import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeSpec;
import com.vocalabs.egtest.processor.MessageHandler;
import com.vocalabs.egtest.processor.data.*;

import javax.lang.model.element.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

abstract class JUnitExampleWriter> {
    protected final JUnitClassWriter classWriter;
    protected final List examples;
    protected final TypeSpec.Builder toAddTo;
    protected final MessageHandler messageHandler;
    protected final T element;
    protected final AnnotationSpec testAnnotation = AnnotationSpec.builder(ClassName.get("org.junit", "Test")).build();

    static void write(JUnitClassWriter classWriter, TypeSpec.Builder builder) {
        Map>> examplesByElement = classWriter.getItems().stream()
                .collect(Collectors.groupingBy(Example::getElement));

        for (Map.Entry>> entry: examplesByElement.entrySet()) {
            Element el = entry.getKey();
            List> examples = entry.getValue();

            new PatternMatchWriter(el, filterAndConvert(PatternMatchExample.class, examples), classWriter, builder)
                    .addTests();
            new FunctionMatchWriter(el, filterAndConvert(FunctionMatchExample.class, examples), classWriter, builder)
                    .addTests();

            if (el instanceof ExecutableElement) {
                ExecutableElement exEl = (ExecutableElement) el;

                List returnsExamples = filterAndConvert(ReturnsExample.class, examples);
                new ReturnsWriter(exEl, returnsExamples, classWriter, builder)
                        .addTests();

                List exceptionExamples = filterAndConvert(ExceptionExample.class, examples);
                new ExceptionWriter(exEl, exceptionExamples, classWriter, builder)
                        .addTests();
            }
        }
    }

    private static > List filterAndConvert(Class cl, List items) {
        return items.stream()
                .filter(it -> cl.isAssignableFrom(it.getClass()))
                .map(cl::cast)
                .collect(Collectors.toList());
    }

    protected JUnitExampleWriter(T element, List examples, JUnitClassWriter classWriter, TypeSpec.Builder toAddTo) {
        this.element = element;
        this.examples = examples;
        this.classWriter = classWriter;
        this.toAddTo = toAddTo;
        this.messageHandler = classWriter.getMessageHandler();
    }

    public abstract void addTests();

    /** If the element is unsupported, return false after writing to messageHandler. */
    protected boolean checkSupport() {
        if (examples.isEmpty())
            return false;

        if (! element.getEnclosingElement().equals(classWriter.getClassElement())) {
            messageHandler.unsupported(element, "inner classes");
            return false;
        }

        if (! visible(element) ) {
            messageHandler.unsupported(element, "private or protected");
            return false;
        }
        return true;
    }

    private boolean visible(Element el) {
        Set modifiers = el.getModifiers();
        if (modifiers.contains(Modifier.PRIVATE))
            return false;
        return ! modifiers.contains(Modifier.PROTECTED);
    }

    protected String testMethodName() {
        return "test"+baseName()+"$"+uniqueName();
    }

    private String uniqueName() {
        String simpleName = element.getSimpleName().toString();
        if (nameCollisions().isEmpty())
            return simpleName;
        return elementUniqueSuffix(element);
    }

    private List nameCollisions() {
        return element.getEnclosingElement()
                .getEnclosedElements().stream()
                .filter(it -> ! it.equals(element))
                .filter(it -> it.getSimpleName().toString().equals(element.getSimpleName().toString()))
                .map(it -> (Element) it)         // Some Java compilers don't like 
                .collect(Collectors.toList());
    }

    private static String elementUniqueSuffix(Element el) {
        if (el instanceof ExecutableElement) {
            Stream params = ((ExecutableElement)el).getParameters()
                    .stream()
                    .map(p -> p.asType().toString());
            return escapeParameterNames(params);
        }
        return "$"+el.getKind();
    }

    /**
     * Escape names for use in generating unique JUnit names. See the unit tests for expected results of the current
     * implementation; it may change over time.
     */
    static String escapeParameterNames(Stream names) {
        //  I was tempted to use ᛜ (runic ingwaz) but I'm sure people would complain
        return names
                .map(s -> s.replace("$", "$$"))
                .map(s -> s.replace("_", "__"))
                .map(s -> s.replace(".", "_"))
                .map(s -> s.replace("[]", "$_A"))
                .reduce("",  (a,b)  -> a+"$"+b);
    }


    /** The distinctive portion of the name constructed by {@link #testMethodName()}.  */
    protected abstract String baseName();
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy