- Revision
- 893
- Author
- mauro
- Date
- 2008-08-25 12:34:58 -0500 (Mon, 25 Aug 2008)
Log Message
JBEHAVE-128: Refactored candidate step argument converters. Added support for list of numbers.
Modified Paths
- trunk/jbehave-core/src/behaviour/org/jbehave/scenario/steps/CandidateStepBehaviour.java
- trunk/jbehave-core/src/java/org/jbehave/scenario/steps/CandidateStep.java
- trunk/jbehave-core/src/java/org/jbehave/scenario/steps/PrintStreamStepMonitor.java
- trunk/jbehave-core/src/java/org/jbehave/scenario/steps/StepMonitor.java
Diff
Modified: trunk/jbehave-core/src/behaviour/org/jbehave/scenario/steps/CandidateStepBehaviour.java (892 => 893)
--- trunk/jbehave-core/src/behaviour/org/jbehave/scenario/steps/CandidateStepBehaviour.java 2008-08-24 16:41:41 UTC (rev 892) +++ trunk/jbehave-core/src/behaviour/org/jbehave/scenario/steps/CandidateStepBehaviour.java 2008-08-25 17:34:58 UTC (rev 893) @@ -109,12 +109,37 @@ } @Test + public void shouldConvertArgsToListOfNumbers() throws Exception { + SomeSteps someSteps = new SomeSteps(); + CandidateStep candidateStep = new CandidateStep("windows on the $nth floors", + methodFor("aMethodWithListOfLongs"), someSteps, PATTERN_BUILDER, MONITOR, "Given", "When", "Then"); + candidateStep.createFrom("When windows on the 1L,2L,3L floors").perform(); + ensureThat(((List<?>) someSteps.args).toString(), equalTo(asList(1L, 2L, 3L).toString())); + + candidateStep = new CandidateStep("windows on the $nth floors", methodFor("aMethodWithListOfIntegers"), + someSteps, PATTERN_BUILDER, MONITOR, "Given", "When", "Then"); + candidateStep.createFrom("When windows on the 1,2,3 floors").perform(); + ensureThat(((List<?>) someSteps.args).toString(), equalTo(asList(1, 2, 3).toString())); + + candidateStep = new CandidateStep("windows on the $nth floors", methodFor("aMethodWithListOfDoubles"), + someSteps, PATTERN_BUILDER, MONITOR, "Given", "When", "Then"); + candidateStep.createFrom("When windows on the 1.1,2.2,3.3 floors").perform(); + ensureThat(((List<?>) someSteps.args).toString(), equalTo(asList(1.1, 2.2, 3.3).toString())); + + candidateStep = new CandidateStep("windows on the $nth floors", methodFor("aMethodWithListOfFloats"), + someSteps, PATTERN_BUILDER, MONITOR, "Given", "When", "Then"); + candidateStep.createFrom("When windows on the 1.1f,2.2f,3.3f floors").perform(); + ensureThat(((List<?>) someSteps.args).toString(), equalTo(asList(1.1f, 2.2f, 3.3f).toString())); + + } + + @Test public void shouldConvertArgsToListOfStrings() throws Exception { SomeSteps someSteps = new SomeSteps(); CandidateStep candidateStep = new CandidateStep("windows on the $nth floors", methodFor("aMethodWithListOfStrings"), someSteps, PATTERN_BUILDER, MONITOR, "Given", "When", "Then"); candidateStep.createFrom("When windows on the 1,2,3 floors").perform(); - ensureThat(((List<?>) someSteps.args).toString(), equalTo(asList("1","2","3").toString())); + ensureThat(((List<?>) someSteps.args).toString(), equalTo(asList("1", "2", "3").toString())); } public static Method methodFor(String methodName) throws IntrospectionException { @@ -157,5 +182,22 @@ public void aMethodWithListOfStrings(List<String> args) { this.args = args; } + + public void aMethodWithListOfLongs(List<Long> args) { + this.args = args; + } + + public void aMethodWithListOfIntegers(List<Integer> args) { + this.args = args; + } + + public void aMethodWithListOfDoubles(List<Double> args) { + this.args = args; + } + + public void aMethodWithListOfFloats(List<Float> args) { + this.args = args; + } + } }
Modified: trunk/jbehave-core/src/java/org/jbehave/scenario/steps/CandidateStep.java (892 => 893)
--- trunk/jbehave-core/src/java/org/jbehave/scenario/steps/CandidateStep.java 2008-08-24 16:41:41 UTC (rev 892) +++ trunk/jbehave-core/src/java/org/jbehave/scenario/steps/CandidateStep.java 2008-08-25 17:34:58 UTC (rev 893) @@ -6,6 +6,9 @@ import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -13,7 +16,6 @@ import org.jbehave.scenario.errors.PendingError; import org.jbehave.scenario.parser.StepPatternBuilder; - public class CandidateStep { private static final String NL = System.getProperty("line.separator"); @@ -21,20 +23,25 @@ private final Method method; private final Steps steps; private final StepMonitor monitor; - private Pattern pattern; - private String[] startingWords; + private final String[] startingWords; + private final Pattern pattern; + private final List<? extends ArgumentConverter> converters; - public CandidateStep(String matchThis, Method method, Steps steps, StepPatternBuilder patterBuilder, StepMonitor monitor, String... startingWords) { + public CandidateStep(String matchThis, Method method, Steps steps, StepPatternBuilder patterBuilder, + StepMonitor monitor, String... startingWords) { this.method = method; this.steps = steps; this.monitor = monitor; this.startingWords = startingWords; - pattern = patterBuilder.buildPattern(matchThis); + this.pattern = patterBuilder.buildPattern(matchThis); + this.converters = asList(new NumberConverter(), new NumberListConverter(), new StringListConverter()); } public boolean matches(String step) { String word = findStartingWord(step); - if (word == null) { return false; } + if (word == null) { + return false; + } String trimmed = trimStartingWord(word, step); Matcher matcher = pattern.matcher(trimmed); boolean matches = matcher.matches(); @@ -50,10 +57,11 @@ String startingWord = findStartingWord(stepAsString); Matcher matcher = pattern.matcher(trimStartingWord(startingWord, stepAsString)); matcher.find(); + Type[] types = method.getGenericParameterTypes(); final Object[] args = new Object[matcher.groupCount()]; for (int group = 0; group < args.length; group++) { String arg = matcher.group(group + 1); - Object converted = convert(arg, method.getGenericParameterTypes()[group]); + Object converted = convert(arg, types[group]); args[group] = converted; } return createStep(stepAsString, args); @@ -74,8 +82,7 @@ try { method.invoke(steps, args); return StepResult.success(stepAsString); - } - catch (Throwable t) { + } catch (Throwable t) { return failureWithOriginalException(stepAsString, t); } } @@ -99,31 +106,109 @@ } private Object convert(String value, Type type) { - monitor.convertingValueOfType(value, type); - if (type == Integer.class || type == int.class) { - return Integer.valueOf(value); - } else if (type == Long.class || type == long.class) { - return Long.valueOf(value); - } else if (type == Double.class || type == double.class) { - return Double.valueOf(value); - } else if (type == Float.class || type == float.class) { - return Float.valueOf(value); - } else if (type instanceof ParameterizedType ){ - return listFor(value, (ParameterizedType)type); - } else if (type == String.class) { - return replaceNewlinesWithSystemNewlines(value); + // check if any converters accepts type + for (ArgumentConverter converter : converters) { + if (converter.accept(type)) { + monitor.convertingValueOfType(value, type, converter.getClass()); + return converter.convertValue(value, type); + } } - return value; + // default to String + return replaceNewlinesWithSystemNewlines(value); } - private Object listFor(String value, ParameterizedType type) { - if ( List.class.isAssignableFrom((Class<?>)type.getRawType()) ){ + private Object replaceNewlinesWithSystemNewlines(String value) { + return value.replaceAll("(\n)|(\r\n)", NL); + } + + private static interface ArgumentConverter { + + boolean accept(Type type); + + Object convertValue(String value, Type type); + + } + + @SuppressWarnings("serial") + private static class InvalidArgumentException extends RuntimeException { + + public InvalidArgumentException(String message, Throwable cause) { + super(message, cause); + } + + } + + private static class NumberConverter implements ArgumentConverter { + + public boolean accept(Type type) { + if (type instanceof Class) { + return (type == Integer.class || type == int.class || type == Long.class || type == long.class + || type == Double.class || type == double.class || type == Float.class || type == float.class); + } + return false; + } + + public Object convertValue(String value, Type type) { + if (type == Integer.class || type == int.class) { + return Integer.valueOf(value); + } else if (type == Long.class || type == long.class) { + return Long.valueOf(value); + } else if (type == Double.class || type == double.class) { + return Double.valueOf(value); + } else if (type == Float.class || type == float.class) { + return Float.valueOf(value); + } + return value; + } + + } + + private static class NumberListConverter implements ArgumentConverter { + + public boolean accept(Type type) { + if (type instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) type; + Type rawType = parameterizedType.getRawType(); + Type argumentType = parameterizedType.getActualTypeArguments()[0]; + return List.class.isAssignableFrom((Class<?>) rawType) + && Number.class.isAssignableFrom((Class<?>) argumentType); + } + return false; + } + + public Object convertValue(String value, Type type) { + List<String> values = asList(value.split(COMMA)); + NumberFormat numberFormat = NumberFormat.getInstance(); + List<Number> numbers = new ArrayList<Number>(); + for (String numberValue : values) { + try { + numbers.add(numberFormat.parse(numberValue)); + } catch (ParseException e) { + throw new InvalidArgumentException(numberValue, e); + } + } + return numbers; + } + + } + + private static class StringListConverter implements ArgumentConverter { + + public boolean accept(Type type) { + if (type instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) type; + Type rawType = parameterizedType.getRawType(); + Type argumentType = parameterizedType.getActualTypeArguments()[0]; + return List.class.isAssignableFrom((Class<?>) rawType) + && String.class.isAssignableFrom((Class<?>) argumentType); + } + return false; + } + + public Object convertValue(String value, Type type) { return asList(value.split(COMMA)); } - return replaceNewlinesWithSystemNewlines(value); + } - private Object replaceNewlinesWithSystemNewlines(String value) { - return value.replaceAll("(\n)|(\r\n)", NL); - } }
Modified: trunk/jbehave-core/src/java/org/jbehave/scenario/steps/PrintStreamStepMonitor.java (892 => 893)
--- trunk/jbehave-core/src/java/org/jbehave/scenario/steps/PrintStreamStepMonitor.java 2008-08-24 16:41:41 UTC (rev 892) +++ trunk/jbehave-core/src/java/org/jbehave/scenario/steps/PrintStreamStepMonitor.java 2008-08-25 17:34:58 UTC (rev 893) @@ -18,15 +18,15 @@ public void stepMatchesPattern(String step, boolean matches, String pattern) { String message = format("Step ''{0}'' {1} pattern ''{2}''", step, (matches ? "matches" : "does not match"), - pattern); + pattern); print(output, message); } - public void convertingValueOfType(String value, Type type) { - String message = format("Converting value ''{0}'' of type ''{1}''", value, type); - print(output,message); + public void convertingValueOfType(String value, Type type, Class<?> converterClass) { + String message = format("Converting value ''{0}'' of type ''{1}'' with converter ''{2}''", value, type, converterClass); + print(output, message); } - + protected void print(PrintStream output, String message) { output.println(message); }
Modified: trunk/jbehave-core/src/java/org/jbehave/scenario/steps/StepMonitor.java (892 => 893)
--- trunk/jbehave-core/src/java/org/jbehave/scenario/steps/StepMonitor.java 2008-08-24 16:41:41 UTC (rev 892) +++ trunk/jbehave-core/src/java/org/jbehave/scenario/steps/StepMonitor.java 2008-08-25 17:34:58 UTC (rev 893) @@ -11,6 +11,6 @@ void stepMatchesPattern(String string, boolean matches, String pattern); - void convertingValueOfType(String value, Type type); + void convertingValueOfType(String value, Type type, Class<?> converterClass); }
To unsubscribe from this list please visit:
