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

org.tap4j.ext.junit.util.TapJUnitUtil Maven / Gradle / Ivy

There is a newer version: 4.4.2
Show newest version
/*
 * The MIT License
 * 
 * Copyright (c) 2010 tap4j team (see AUTHORS)
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.tap4j.ext.junit.util;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.junit.runner.Description;
import org.tap4j.ext.junit.model.JUnitTestData;
import org.tap4j.model.Directive;
import org.tap4j.model.TestResult;
import org.tap4j.util.DirectiveValues;
import org.tap4j.util.StatusValues;
import org.yaml.snakeyaml.DumperOptions.LineBreak;

/**
 * JUnit TAP extension utility class.
 *
 * @since 1.4.3
 */
public final class TapJUnitUtil {
    
    public static final String LINE_SEPARATOR = LineBreak.UNIX.getString();

    /**
     * Default constructor.
     */
    private TapJUnitUtil() {
        super();
    }

    /**
     * Generate TAP test result
     * 
     * @param testMethod
     * @param number
     * @return TestResult
     */
    public static TestResult generateTAPTestResult(JUnitTestData testMethod,
            Integer number, boolean yaml) {
        final TestResult tapTestResult = new TestResult();

        final String testResultDescription = generateTAPTestResultDescription(testMethod);
        tapTestResult.setDescription(testResultDescription);

        setTapTestStatus(tapTestResult, testMethod);
        
        if (yaml) {
            String message = getMessage(testMethod);
            String severity = getSeverity(testMethod);
            String source = getSource(
                    extractMethodName(testMethod.getDescription()),
                    extractClassName(testMethod.getDescription()));
            String datetime = getDatetime();
            String file = getFile(testMethod);
            String line = getLine(testMethod);
            String name = getName(testMethod);
            String error = getError(testMethod);
            String backtrace = getBacktrace(testMethod);
            TapJUnitYamlUtil.createJUnitYAMLishData(tapTestResult, message,
                    severity, source, datetime, file, line, name, error, backtrace);
        }
        
        return tapTestResult;
    }

    /**
     * Get the tap test description
     * 
     * @param testMethod
     * @return the tap test description
     */
    public static String generateTAPTestResultDescription(JUnitTestData testMethod) {
        final StringBuilder description = new StringBuilder();

        // An extra space is added before the description by the TAP Representer
        description.append("- ");
        description.append(extractClassName(testMethod
            .getDescription()));
        description.append(':');
        description.append(extractMethodName(testMethod
            .getDescription()));

        return description.toString();
    }

    /**
     * Set the tap status
     * 
     * @param tapTestResult
     * @param testMethod
     */
    public static void setTapTestStatus(TestResult tapTestResult,
                                        JUnitTestData testMethod) {
        if (testMethod.isIgnored()) {
            tapTestResult.setStatus(StatusValues.NOT_OK);
            Directive skip = new Directive(DirectiveValues.SKIP,
                                           "JUnit test was skipped");
            tapTestResult.setDirective(skip);
        } else if (testMethod.isFailed()) {
            tapTestResult.setStatus(StatusValues.NOT_OK);
        } else {
            tapTestResult.setStatus(StatusValues.OK);
        }
    }

    /**
     * Extract the class name from a given junit test description
     * 
     * @param description
     * @return a class name
     */
    public static String extractClassName(Description description) {
        final String displayName = description.getDisplayName();

        final String regex = "^" + "[^\\(\\)]+" // non-parens
                       + "\\((" // then an open-paren (start matching a group)
                       + "[^\\\\(\\\\)]+" // non-parens
                       + ")\\)" + "$";
        // System.out.println(regex);
        final Pattern parens = Pattern.compile(regex); // then a close-paren
                                                       // (end group match)
        final Matcher m = parens.matcher(displayName);
        if (!m.find()) {
            return displayName;
        }
        return m.group(1);
    }

    /**
     * Extract the simple class name from a given junit test description
     * 
     * @param description
     * @return a simple class name
     */
    public static String extractSimpleClassName(Description description) {
        String simpleClassName = null;
        final String className = extractClassName(description);
        final String[] splitClassName = className.split("\\.");

        if (splitClassName.length > 0) {
            simpleClassName = splitClassName[splitClassName.length - 1];
        }

        return simpleClassName;
    }
    
    /**
     * Get the tested method name
     * 
     * @param description
     * @return tested methode name
     */
    public static String extractMethodName(Description description) {
        String methodName = null;
        final String[] splitDisplayName = description.getDisplayName().split("\\(");

        if (splitDisplayName.length > 0) {
            methodName = splitDisplayName[0];
        }

        return methodName;
    }

    /**
     * Get the file name of the tested method
     * 
     * @param testMethod
     * @return the file name
     */
    public static String getFile(JUnitTestData testMethod) {
        return extractClassName(testMethod.getDescription());
    }

    /**
     * Get tested method name
     * 
     * @param testMethod
     * @return tested method name
     */
    public static String getName(JUnitTestData testMethod) {
        return extractMethodName(testMethod.getDescription());
    }

    /**
     * Get the line of the error in the exception info
     * 
     * @param testMethod
     * @return line of the error in the exception info
     */
    public static String getLine(JUnitTestData testMethod) {
        String line = "~";
        Throwable testException = testMethod.getFailException();
        if (testException != null) {
            StringBuilder lookFor = new StringBuilder();
            lookFor.append(extractClassName(testMethod.getDescription()));
            lookFor.append('.');
            lookFor.append(extractMethodName(testMethod.getDescription()));
            lookFor.append('(');
            lookFor.append(extractSimpleClassName(testMethod.getDescription()));
            lookFor.append(".java:");

            StackTraceElement[] els = testException.getStackTrace();

            for (int i = 0; i < els.length; i++) {
                StackTraceElement el = els[i];
                line = getLineNumberFromExceptionTraceLine(el.toString(),
                                                           lookFor.toString());
                if (line.equals("") == Boolean.FALSE) {
                    break;
                }
            }
        }
        return line;
    }

    /**
     * Get the error line number from the exception stack trace
     * 
     * @param exceptionTraceLine
     * @param substrToSearch
     * @return error line number
     */
    public static String getLineNumberFromExceptionTraceLine(String exceptionTraceLine,
                                                             String substrToSearch) {
        String lineNumber = "";
        int index = exceptionTraceLine.indexOf(substrToSearch);
        if (index >= 0) {
            int length = substrToSearch.length() + index;
            if (exceptionTraceLine.lastIndexOf(')') > length) {
                lineNumber = exceptionTraceLine
                    .substring(length, exceptionTraceLine.lastIndexOf(')'));
            }
        }
        return lineNumber;
    }
    
    /**
     * Get the error message from a given failed JUnit test result
     * 
     * @param testMethod
     * @return error message from a given failed JUnit test result
     */
    public static String getError(JUnitTestData testMethod) {
        String error = "~";
        Throwable t = testMethod.getFailException();
        if (t != null) {
            error = t.getMessage();
        }
        return error;
    }

    /**
     * Generate a message with the name of the tested method
     * 
     * @param testMethod
     * @return test message
     */
    public static String getMessage(JUnitTestData testMethod) {
        return "JUnit 4.0 Test " + testMethod.getDescription().getDisplayName();
    }

    /**
     * Get the severity of the test
     * 
     * @param testMethod
     * @return severity
     */
    public static String getSeverity(JUnitTestData testMethod) {
        String severity = "~";
        if (testMethod.getFailException() != null) {
            severity = "High";
        }
        return severity;
    }

    /**
     * @param testMethod
     * @param testClass
     * @return test source
     */
    public static String getSource(String testMethod, String testClass) {
        return testClass + ":" + testMethod;
    }

    /**
     * Get a date time string
     * 
     * @return date time string
     */
    public static String getDatetime() {
        long currentTimeMillis = System.currentTimeMillis();
        final Date date = new Date(currentTimeMillis);
        // ISO-8061 for YAMLish diagnostic
        return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(date);
    }

    /**
     * Get the backtrace from a given failed JUnit test result
     * 
     * @param testMethod
     * @return Backtrace from a given failed JUnit test result
     */
    public static String getBacktrace(JUnitTestData testMethod) {
        StringBuilder stackTrace = new StringBuilder();

        Throwable throwable = testMethod.getFailException();

        if (throwable != null) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            throwable.printStackTrace(pw);
            String stackTraceString = sw.toString();
            stackTraceString = stackTraceString.trim().replaceAll("\\r\\n",
                    "\n");

            StringTokenizer st = new StringTokenizer(stackTraceString,
                    LINE_SEPARATOR);

            while (st.hasMoreTokens()) {
                String stackTraceLine = st.nextToken();
                stackTrace.append(stackTraceLine);
                stackTrace.append(LINE_SEPARATOR);
            }

        } else {
            stackTrace.append('~');
        }

        return stackTrace.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy