Package org.jbehave.core.steps

Source Code of org.jbehave.core.steps.StepCreator$BeforeOrAfter

package org.jbehave.core.steps;

import static java.util.Arrays.asList;
import static org.jbehave.core.steps.AbstractStepResult.failed;
import static org.jbehave.core.steps.AbstractStepResult.ignorable;
import static org.jbehave.core.steps.AbstractStepResult.notPerformed;
import static org.jbehave.core.steps.AbstractStepResult.pending;
import static org.jbehave.core.steps.AbstractStepResult.skipped;
import static org.jbehave.core.steps.AbstractStepResult.successful;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map;

import org.jbehave.core.annotations.Named;
import org.jbehave.core.annotations.AfterScenario.Outcome;
import org.jbehave.core.failures.BeforeOrAfterFailed;
import org.jbehave.core.parsers.StepMatcher;

import com.thoughtworks.paranamer.NullParanamer;
import com.thoughtworks.paranamer.Paranamer;

public class StepCreator {

    public static final String PARAMETER_NAME_START = "<";
    public static final String PARAMETER_NAME_END = ">";
    public static final String PARAMETER_VALUE_START = "\uFF5F";
    public static final String PARAMETER_VALUE_END = "\uFF60";
    public static final String PARAMETER_VALUE_NEWLINE = "\u2424";
    private final Object stepsInstance;
    private final ParameterConverters parameterConverters;
    private final StepMatcher stepMatcher;
    private final StepRunner beforeOrAfter;
    private final StepRunner skip;
    private StepMonitor stepMonitor;
    private Paranamer paranamer = new NullParanamer();
    private boolean dryRun = false;

    public StepCreator(Object stepsInstance, StepMonitor stepMonitor) {
        this(stepsInstance, null, null, stepMonitor);
    }

    public StepCreator(Object stepsInstance, ParameterConverters parameterConverters, StepMatcher stepMatcher,
            StepMonitor stepMonitor) {
        this.stepsInstance = stepsInstance;
        this.parameterConverters = parameterConverters;
        this.stepMatcher = stepMatcher;
        this.stepMonitor = stepMonitor;
        this.beforeOrAfter = new BeforeOrAfter();
        this.skip = new Skip();
    }

    public void useStepMonitor(StepMonitor stepMonitor) {
        this.stepMonitor = stepMonitor;
    }

    public void useParanamer(Paranamer paranamer) {
        this.paranamer = paranamer;
    }

    public void doDryRun(boolean dryRun) {
        this.dryRun = dryRun;
    }

    public Step createBeforeOrAfterStep(final Method method) {
        return new Step() {
            public StepResult doNotPerform() {
                return beforeOrAfter.run(method);
            }

            public StepResult perform() {
                return beforeOrAfter.run(method);
            }
        };
    }

    public Step createAfterStepUponOutcome(final Method method, Outcome outcome) {
        switch (outcome) {
        case ANY:
        default:
            return new Step() {

                public StepResult doNotPerform() {
                    return beforeOrAfter.run(method);
                }

                public StepResult perform() {
                    return beforeOrAfter.run(method);
                }

            };
        case SUCCESS:
            return new Step() {

                public StepResult doNotPerform() {
                    return skip.run(method);
                }

                public StepResult perform() {
                    return beforeOrAfter.run(method);
                }

            };
        case FAILURE:
            return new Step() {

                public StepResult doNotPerform() {
                    return beforeOrAfter.run(method);
                }

                public StepResult perform() {
                    return skip.run(method);
                }

            };
        }
    }

    public Step createParametrisedStep(final Method method, final String stepAsString,
            final String stepWithoutStartingWord, final Map<String, String> tableRow) {
        return new Step() {
            private Object[] convertedParameters;
            private String parametrisedStep;

            public StepResult perform() {
                try {
                    parametriseStep();
                    stepMonitor.performing(stepAsString, dryRun);
                    if (!dryRun) {
                        method.invoke(stepsInstance, convertedParameters);
                    }
                    return successful(stepAsString).withParameterValues(parametrisedStep);
                } catch (ParameterNotFound e) {
                    // step parametrisation failed, return pending StepResult
                    return pending(stepAsString).withParameterValues(parametrisedStep);
                } catch (InvocationTargetException e) {
                    return failed(stepAsString, e.getCause()).withParameterValues(parametrisedStep);
                } catch (Throwable t) {
                    return failed(stepAsString, t).withParameterValues(parametrisedStep);
                }
            }

            public StepResult doNotPerform() {
                try {
                    parametriseStep();
                } catch (ParameterNotFound e) {
                    // step parametrisation failed, but still return
                    // notPerformed StepResult
                }
                return notPerformed(stepAsString).withParameterValues(parametrisedStep);
            }

            private void parametriseStep() {
                stepMatcher.find(stepWithoutStartingWord);
                String[] annotationNames = annotatedParameterNames(method);
                String[] parameterNames = paranamer.lookupParameterNames(method, false);
                Type[] types = method.getGenericParameterTypes();
                String[] parameters = parametersForStep(tableRow, types, annotationNames, parameterNames);
                convertedParameters = convertParameters(parameters, types);
                parametrisedStep = parametrisedStep(stepAsString, tableRow, types, annotationNames, parameterNames,
                        parameters);
            }

        };
    }

    /**
     * Extract annotated parameter names from the @Named parameter annotations
     * of the method
     *
     * @param method
     *            the Method containing the annotations
     * @return An array of annotated parameter names, which <b>may</b> include
     *         <code>null</code> values for parameters that are not annotated
     */
    private String[] annotatedParameterNames(Method method) {
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        String[] names = new String[parameterAnnotations.length];
        for (int x = 0; x < parameterAnnotations.length; x++) {
            Annotation[] annotations = parameterAnnotations[x];
            for (Annotation annotation : annotations) {
                names[x] = annotationName(annotation);
            }
        }
        return names;
    }

    private String annotationName(Annotation annotation) {
        if (annotation.annotationType().isAssignableFrom(Named.class)) {
            return ((Named) annotation).value();
        } else if ("javax.inject.Named".equals(annotation.annotationType().getName())) {
            return Jsr330Helper.getNamedValue(annotation);
        } else {
            return null;
        }
    }

    private String parametrisedStep(String stepAsString, Map<String, String> tableRow, Type[] types,
            String[] annotationNames, String[] parameterNames, String[] parameters) {
        String parametrisedStep = stepAsString;
        for (int position = 0; position < types.length; position++) {
            parametrisedStep = replaceParameterValuesInStep(parametrisedStep, position, annotationNames,
                    parameterNames, parameters, tableRow);
        }
        return parametrisedStep;
    }

    private String replaceParameterValuesInStep(String stepText, int position, String[] annotationNames,
            String[] parameterNames, String[] parameters, Map<String, String> tableRow) {
        int annotatedNamePosition = parameterPosition(annotationNames, position);
        int parameterNamePosition = parameterPosition(parameterNames, position);
        if (annotatedNamePosition != -1) {
            stepText = replaceTableValue(stepText, tableRow, annotationNames[position]);
        } else if (parameterNamePosition != -1) {
            stepText = replaceTableValue(stepText, tableRow, parameterNames[position]);
        }
        stepText = replaceParameterValue(stepText, position, parameters);
        return stepText;
    }

    private String replaceParameterValue(String stepText, int position, String[] parameters) {
        String value = parameters[position];
        if (value != null) {
            stepText = stepText.replace(value, PARAMETER_VALUE_START + value + PARAMETER_VALUE_END);
            stepText = stepText.replace("\n", PARAMETER_VALUE_NEWLINE);
        }
        return stepText;
    }

    private String replaceTableValue(String stepText, Map<String, String> tableRow, String name) {
        String value = getTableValue(tableRow, name);
        if (value != null) {
            stepText = stepText.replace(PARAMETER_NAME_START + name + PARAMETER_NAME_END, PARAMETER_VALUE_START + value
                    + PARAMETER_VALUE_END);
        }
        return stepText;
    }

    private String[] parametersForStep(Map<String, String> tableRow, Type[] types, String[] annotationNames,
            String[] parameterNames) {
        final String[] parameters = new String[types.length];
        for (int position = 0; position < types.length; position++) {
            parameters[position] = parameterForPosition(position, annotationNames, parameterNames, tableRow);
        }
        return parameters;
    }

    private Object[] convertParameters(String[] parametersAsString, Type[] types) {
        final Object[] parameters = new Object[parametersAsString.length];
        for (int position = 0; position < parametersAsString.length; position++) {
            parameters[position] = parameterConverters.convert(parametersAsString[position], types[position]);
        }
        return parameters;
    }

    private String parameterForPosition(int position, String[] annotationNames, String[] parameterNames,
            Map<String, String> tableRow) {
        int annotatedNamePosition = parameterPosition(annotationNames, position);
        int parameterNamePosition = parameterPosition(parameterNames, position);
        String parameter = null;
        if (annotatedNamePosition != -1 && isGroupName(annotationNames[position])) {
            String name = annotationNames[position];
            stepMonitor.usingAnnotatedNameForParameter(name, position);
            parameter = matchedParameter(name);
        } else if (parameterNamePosition != -1 && isGroupName(parameterNames[position])) {
            String name = parameterNames[position];
            stepMonitor.usingParameterNameForParameter(name, position);
            parameter = matchedParameter(name);
        } else if (annotatedNamePosition != -1 && isTableFieldName(tableRow, annotationNames[position])) {
            String name = annotationNames[position];
            stepMonitor.usingTableAnnotatedNameForParameter(name, position);
            parameter = getTableValue(tableRow, name);
        } else if (parameterNamePosition != -1 && isTableFieldName(tableRow, parameterNames[position])) {
            String name = parameterNames[position];
            stepMonitor.usingTableParameterNameForParameter(name, position);
            parameter = getTableValue(tableRow, name);
        } else {
            stepMonitor.usingNaturalOrderForParameter(position);
            parameter = matchedParameter(position);
        }
        stepMonitor.foundParameter(parameter, position);
        return parameter;
    }

    String matchedParameter(String name) {
        String[] parameterNames = stepMatcher.parameterNames();
        for (int i = 0; i < parameterNames.length; i++) {
            String parameterName = parameterNames[i];
            if (name.equals(parameterName)) {
                return matchedParameter(i);
            }
        }
        throw new ParameterNotFound(name, parameterNames);
    }

    private String matchedParameter(int position) {
        String[] parameterNames = stepMatcher.parameterNames();
        int matchedPosition = position + 1;
        if (matchedPosition <= parameterNames.length) {
            return stepMatcher.parameter(matchedPosition);
        }
        throw new ParameterNotFound(position, parameterNames);
    }

    private int parameterPosition(String[] names, int position) {
        if (names.length == 0) {
            return -1;
        }
        String positionName = names[position];
        for (int i = 0; i < names.length; i++) {
            String name = names[i];
            if (name != null && positionName.equals(name)) {
                return i;
            }
        }
        return -1;
    }

    private boolean isGroupName(String name) {
        String[] groupNames = stepMatcher.parameterNames();
        for (String groupName : groupNames) {
            if (name.equals(groupName)) {
                return true;
            }
        }
        return false;
    }

    private String getTableValue(Map<String, String> tableRow, String name) {
        return tableRow.get(name);
    }

    private boolean isTableFieldName(Map<String, String> tableRow, String name) {
        return tableRow.get(name) != null;
    }

    public interface StepRunner {

        StepResult run(Method method);

    }

    private class BeforeOrAfter implements StepRunner {
        public StepResult run(Method method) {
            try {
                method.invoke(stepsInstance);
            } catch (InvocationTargetException e) {
                throw new BeforeOrAfterFailed(method, e.getCause());
            } catch (Throwable t) {
                throw new BeforeOrAfterFailed(t);
            }
            return skipped();
        }
    }

    private class Skip implements StepRunner {
        public StepResult run(Method method) {
            return skipped();
        }
    }

    public static Step createPendingStep(final String stepAsString) {
        return new Step() {
            public StepResult perform() {
                return pending(stepAsString);
            }

            public StepResult doNotPerform() {
                return pending(stepAsString);
            }
        };
    }

    public static Step createIgnorableStep(final String stepAsString) {
        return new Step() {
            public StepResult perform() {
                return ignorable(stepAsString);
            }

            public StepResult doNotPerform() {
                return ignorable(stepAsString);
            }
        };
    }

    /**
     * This is a different class, because the @Inject jar may not be in the
     * classpath.
     */
    public static class Jsr330Helper {

        private static String getNamedValue(Annotation annotation) {
            return ((javax.inject.Named) annotation).value();
        }

    }

    @SuppressWarnings("serial")
    public static class ParameterNotFound extends RuntimeException {

        public ParameterNotFound(String name, String[] parameters) {
            super("Parameter not found for name '" + name + "' amongst '" + asList(parameters) + "'");
        }

        public ParameterNotFound(int position, String[] parameters) {
            super("Parameter not found for position '" + position + "' amongst '" + asList(parameters) + "'");
        }
    }

}
TOP

Related Classes of org.jbehave.core.steps.StepCreator$BeforeOrAfter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.