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

org.specrunner.junit.JUnitUtils Maven / Gradle / Ivy

/*
    SpecRunner - Acceptance Test Driven Development Tool
    Copyright (C) 2011-2014  Thiago Santos

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see 
 */
package org.specrunner.junit;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import nu.xom.Node;
import nu.xom.Nodes;

import org.junit.runner.Description;
import org.junit.runner.notification.Failure;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.TestClass;
import org.specrunner.SRServices;
import org.specrunner.context.IContext;
import org.specrunner.listeners.INodeListener;
import org.specrunner.listeners.IScenarioListener;
import org.specrunner.listeners.core.ScenarioCleanerListener;
import org.specrunner.listeners.core.ScenarioFrameListener;
import org.specrunner.result.IResultSet;
import org.specrunner.source.ISource;
import org.specrunner.source.ISourceFactoryManager;
import org.specrunner.util.UtilLog;
import org.specrunner.util.string.UtilString;
import org.specrunner.util.xom.UtilNode;
import org.specrunner.util.xom.node.INodeHolder;
import org.specrunner.util.xom.node.INodeHolderFactory;

/**
 * JUnit useful functions.
 * 
 * @author Thiago Santos
 * 
 */
public final class JUnitUtils {

    /**
     * Output path.
     */
    public static final String PATH = System.getProperty("sr.output", "target/output/");

    /**
     * Default constructor.
     */
    private JUnitUtils() {
    }

    /**
     * Get the HTML file corresponding to the Java.
     * 
     * @param clazz
     *            The test class.
     * 
     * @return The input HTML file.
     */
    public static File getFile(Class clazz) {
        URL location = clazz.getProtectionDomain().getCodeSource().getLocation();
        String str;
        try {
            str = new File(location.toURI()).toString();
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
        Package pkg = clazz.getPackage();
        if (pkg == null) {
            throw new RuntimeException("Test class must be in a package.");
        }
        // exact match
        String path = str + File.separator + pkg.getName().replace(".", File.separator) + File.separator;
        String exact = path + clazz.getSimpleName();
        Set extensions = SRServices.get(ISourceFactoryManager.class).keySet();
        for (String s : extensions) {
            File tmp = new File(exact + "." + s);
            if (UtilLog.LOG.isDebugEnabled()) {
                UtilLog.LOG.debug("Looking for " + tmp);
            }
            if (tmp.exists()) {
                return tmp;
            }
        }
        // remove 'Test' part.
        String clean = path + clazz.getSimpleName().replace("Test", "");
        for (String s : extensions) {
            File tmp = new File(clean + "." + s);
            if (UtilLog.LOG.isDebugEnabled()) {
                UtilLog.LOG.debug("Looking for " + tmp);
            }
            if (tmp.exists()) {
                return tmp;
            }
        }
        throw new RuntimeException("File with one of extensions '" + extensions + "' to " + exact + " not found!");
    }

    /**
     * Get the output file.
     * 
     * @param clazz
     *            The test class.
     * @param input
     *            The input file.
     * @return The output file.
     */
    public static File getOutput(Class clazz, File input) {
        return new File(new File(PATH + clazz.getPackage().getName().replace('.', File.separatorChar)).getAbsoluteFile(), input.getName());
    }

    /**
     * Get the output name adjusted.
     * 
     * @param name
     *            The original name.
     * @return The adjusted name. ie. Excel (.xls,.xlsx) test files are
     *         transformed to HTML (.html).
     */
    public static String getOutputName(String name) {
        if (name != null && name.contains(".") && !name.endsWith(".html")) {
            return name.substring(0, name.lastIndexOf('.')) + ".html";
        } else {
            return name;
        }
    }

    /**
     * Given a class return instances for scenario listeners.
     * 
     * @param type
     *            The base object type.
     * @return An array of listener instances.
     */
    public static IScenarioListener[] getScenarioListener(Class type) {
        List> scan = scanAnnotation(type);
        if (scan.isEmpty()) {
            return new IScenarioListener[0];
        }
        IScenarioListener[] result = new IScenarioListener[scan.size()];
        for (int i = 0; i < result.length; i++) {
            try {
                result[i] = scan.get(i).newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * Get full list of scenario listeners in annotations.
     * 
     * @param type
     *            A type.
     * @return A list of scenario listeners classes for the given type, in
     *         order, from top most class to bottom class.
     */
    public static List> scanAnnotation(Class type) {
        List> scan = new LinkedList>();
        Class tmp = type;
        while (tmp != Object.class) {
            SRScenarioListeners local = tmp.getAnnotation(SRScenarioListeners.class);
            if (local != null) {
                Class[] value = local.value();
                if (value != null) {
                    for (int i = 0; i < value.length; i++) {
                        scan.add(0, value[i]);
                    }
                }
                if (!local.inheritListeners()) {
                    break;
                }
            }
            tmp = tmp.getSuperclass();
        }
        return scan;
    }

    /**
     * Prepare scenario runners.
     * 
     * @param runner
     *            Runners.
     * @return A list of methods.
     */
    public static List prepareScenarios(final IRunnerScenario runner) {
        List methods = new LinkedList();
        try {
            final TestClass testClass = runner.getTestClass();
            Class javaClass = testClass.getJavaClass();
            Method fake = javaClass.getMethod("toString");
            FrameworkMethod fakeMethod = new FrameworkMethod(fake);
            methods.add(fakeMethod);
            runner.setFakeMethod(fakeMethod);

            // read scenario entries
            File input = JUnitUtils.getFile(javaClass);
            ISource source = SRServices.get(ISourceFactoryManager.class).newSource(input.toString());
            Nodes scenarios = UtilNode.getCssNodesOrElements(source.getDocument(), ScenarioFrameListener.CSS_SCENARIO);
            List listeners = new LinkedList();
            runner.setListeners(listeners);
            Set titles = new HashSet();
            Boolean execute = null;
            for (int i = 0; i < scenarios.size(); i++) {
                Node sc = scenarios.get(i);
                INodeHolder scHolder = SRServices.get(INodeHolderFactory.class).newHolder(sc);
                if (scHolder.attributeEquals(ScenarioFrameListener.ATT_EXECUTE, "true")) {
                    if (scHolder.hasAttribute(UtilNode.IGNORE) || scHolder.hasAttribute(UtilNode.PENDING)) {
                        String title = UtilNode.getCssNodeOrElement(sc, ScenarioFrameListener.CSS_TITLE).getValue();
                        throw new RuntimeException("Scenario '" + title + "' cannot have pending='true' or ignore='true' with execute='true'. Remove pending/ignore or execute.");
                    }
                    execute = true;
                }
            }
            for (int i = 0; i < scenarios.size(); i++) {
                Node sc = scenarios.get(i);
                String title = UtilNode.getCssNodeOrElement(sc, ScenarioFrameListener.CSS_TITLE).getValue();
                title = UtilString.getNormalizer().camelCase(title, true);
                if (titles.contains(title)) {
                    throw new RuntimeException("Scenario named '" + title + "' already exists. Scenarios must have different names.");
                }
                titles.add(title);

                ScenarioFrameworkMethod scenarioMethod = new ScenarioFrameworkMethod(fake, title);
                methods.add(scenarioMethod);
                final Description description = runner.describeChild(scenarioMethod);

                IScenarioListener[] annotationListeners = JUnitUtils.getScenarioListener(javaClass);
                IScenarioListener[] fullListeners = Arrays.copyOf(annotationListeners, annotationListeners.length + 2);
                fullListeners[fullListeners.length - 1] = new ScenarioCleanerListener();
                final ScenarioFrameListener frameListener = new ScenarioFrameListener(title, execute, fullListeners) {
                    @Override
                    public Object getInstance() {
                        return runner.getInstance();
                    }
                };
                fullListeners[fullListeners.length - 2] = new IScenarioListener() {
                    @Override
                    public void beforeScenario(String title, Node node, IContext context, IResultSet result, Object instance) {
                        IResultSet r = frameListener.getResult();
                        if (frameListener.isPending() || frameListener.isIgnored()) {
                            runner.getNotifier().fireTestIgnored(description);
                        } else if (r == null || r.countErrors() == 0) {
                            runner.getNotifier().fireTestStarted(description);
                        }
                    }

                    @Override
                    public void afterScenario(String title, Node node, IContext context, IResultSet result, Object instance) {
                        IResultSet r = frameListener.getResult();
                        if (frameListener.isPending() || frameListener.isIgnored()) {
                            runner.getNotifier().fireTestIgnored(description);
                        } else if (r == null || r.countErrors() == 0) {
                            runner.getNotifier().fireTestFinished(description);
                        } else {
                            String msg = "OUTPUT: " + runner.getStatement().getOutput().getAbsoluteFile() + "\n" + r.asString();
                            runner.getNotifier().fireTestFailure(new Failure(description, new Exception(msg)));
                        }
                    }
                };
                listeners.add(frameListener);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return methods;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy