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

com.javakoan.fixture.KoanRunner Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2014 Nicholas Smith
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at

 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.javakoan.fixture;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseException;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.comments.Comment;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.javakoan.fixture.error.KoanError;
import com.javakoan.fixture.io.KoanReader;
import com.javakoan.fixture.io.KoanWriter;

import org.junit.runner.Description;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;

/**
 * The type Koan runner.
 *
 * Class that provides mechanism to execute Koans within the JUnit framework.
 */
public final class KoanRunner extends BlockJUnit4ClassRunner {

    private static final String START_MARKER = "(@_@)";
    private static final String END_MARKER = "(^_^)";

    public KoanRunner(Class klass) throws InitializationError {
        super(klass);
    }

    protected List computeTestMethods() {
        return getTestClass().getAnnotatedMethods(com.javakoan.fixture.annotation.Koan.class);
    }


    @Override
    protected void runChild(final FrameworkMethod method, RunNotifier notifier) {

        Description description = describeChild(method);
        CompilationUnit compilationUnit = getCompilationUnit(description);

        if(compilationUnit == null){
            throw new KoanError("Failed to load Koan");
        }

        String classSource = KoanReader.getSourceByClass(description.getTestClass());
        KoanExecution koanExecution = new KoanExecution(method, classSource);

        if (koanExecution.isToBeEnlightened() && koanExecution.isToBeVexed()) {
            notifier.fireTestFailure(new Failure(description, new KoanError("@Vex and @Enlighten are mutually exclusive")));
            ignoreTest(notifier, description);
            return;
        }

        if (!isValidKoan(compilationUnit, koanExecution)) {
            notifier.fireTestFailure(new Failure(description, new KoanError("Koan is missing start " +START_MARKER+
                    " and end " +END_MARKER+ " markers")));
            ignoreTest(notifier, description);
            return;
        }

        if (koanExecution.isToBeEnlightened()) {
            determineSolution(description.getTestClass(), koanExecution);
            updateKoanSource(koanExecution, description);
            System.out.println("Koan "+method.getName()+" is ignored as currently marked with @Enlighten");
        }

        if (koanExecution.isToBeVexed()) {
            determineProblem(description.getTestClass(), koanExecution);
            updateKoanSource(koanExecution, description);
            System.out.println("Koan "+method.getName()+" is ignored as currently marked with @Vex");
        }

        if (koanExecution.isIgnored()) {
            ignoreTest(notifier, description);
        } else {
            runLeaf(methodBlock(method), description, notifier);
        }
    }


    private void ignoreTest(RunNotifier notifier, Description description) {
        notifier.fireTestIgnored(description);
    }


    private boolean isValidKoan(CompilationUnit compilationUnit, KoanExecution koanExecution) {

        new MethodVisitor().visit(compilationUnit, koanExecution);

        //TODO: Improve error handling
        if (koanExecution.getStartMarkerLine() == 0) {
            return false;
        }
        if (koanExecution.getEndMarkerLine() == 0) {
            return false;
        }

        return true;
    }

    private static class MethodVisitor extends VoidVisitorAdapter {

        @Override
        public void visit(MethodDeclaration method, Object arg) {

            KoanExecution koanExecution = (KoanExecution)arg;

            if(method.getName().equals(koanExecution.getMethod().getName())){
                List comments = method.getAllContainedComments();
                for(Comment comment : comments){
                    if (comment.getContent().contains(START_MARKER)) {
                        koanExecution.setStartMarkerLine(comment.getBeginLine());
                     } else if (comment.getContent().contains(END_MARKER)) {
                        koanExecution.setEndMarkerLine(comment.getBeginLine());
                    }
                }
            }
        }
    }

    private void determineSolution(Class testClass, KoanExecution koanExecution) {
        String solution = KoanReader.getSolutionFromFile(testClass, koanExecution.getMethod().getName());
        koanExecution.setSolution(solution);
    }

    private void determineProblem(Class testClass, KoanExecution koanExecution) {
        String problem = KoanReader.getProblemFromFile(testClass, koanExecution.getMethod().getName());
        koanExecution.setSolution(problem);
    }

    private void updateKoanSource(KoanExecution koanExecution, Description description) {
        final String newLine = System.lineSeparator();

        String[] lines = koanExecution.getClassSource().split(newLine);

        StringBuilder sb = new StringBuilder();

        for(int i = 0; i < koanExecution.getStartMarkerLine() ; i++){
            sb.append(lines[i]);
            sb.append(newLine);
        }
        sb.append(koanExecution.getSolution());
        for(int i = koanExecution.getEndMarkerLine() - 1; i < lines.length; i++){
            sb.append(lines[i]);
            sb.append(newLine);
        }

        KoanWriter.writeSourceToFile(description.getTestClass(), sb.toString());
    }

    private CompilationUnit getCompilationUnit(Description description) {
        CompilationUnit cu = null;
        FileInputStream in = null;

        try {
            in = KoanReader.getInputStreamByClass(description.getTestClass());
            cu = JavaParser.parse(in);
        } catch (ParseException e) {
            e.printStackTrace();
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return cu;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy