diff --git a/clojure/pom.xml b/clojure/pom.xml old mode 100755 new mode 100644 index 23a1318608..2108e5048e --- a/clojure/pom.xml +++ b/clojure/pom.xml @@ -12,7 +12,6 @@ clojure - 0.4.3-SNAPSHOT jar Cucumber: Clojure diff --git a/core/pom.xml b/core/pom.xml old mode 100755 new mode 100644 index b10c0739b8..d2a6ebbdf0 --- a/core/pom.xml +++ b/core/pom.xml @@ -12,7 +12,6 @@ core - 0.4.3-SNAPSHOT jar Cucumber: Core diff --git a/core/src/main/java/cucumber/runtime/CucumberException.java b/core/src/main/java/cucumber/runtime/CucumberException.java index 669a619767..beaf2fdc0c 100644 --- a/core/src/main/java/cucumber/runtime/CucumberException.java +++ b/core/src/main/java/cucumber/runtime/CucumberException.java @@ -1,7 +1,12 @@ package cucumber.runtime; public class CucumberException extends RuntimeException { - public CucumberException(String message) { + /** + * + */ + private static final long serialVersionUID = 1393513206771603671L; + + public CucumberException(String message) { super(message); } diff --git a/core/src/main/java/cucumber/runtime/Runtime.java b/core/src/main/java/cucumber/runtime/Runtime.java index 7459368030..89f4133c55 100644 --- a/core/src/main/java/cucumber/runtime/Runtime.java +++ b/core/src/main/java/cucumber/runtime/Runtime.java @@ -1,9 +1,7 @@ package cucumber.runtime; -import cucumber.classpath.Classpath; -import gherkin.GherkinParser; +import static java.util.Arrays.asList; import gherkin.formatter.Argument; -import gherkin.formatter.model.Feature; import gherkin.formatter.model.Step; import java.util.ArrayList; @@ -11,11 +9,13 @@ import java.util.Comparator; import java.util.List; -import static java.util.Arrays.asList; +import cucumber.classpath.Classpath; +import cucumber.runtime.transformers.Transformer; public class Runtime { private final List backends; private final List undefinedSteps = new ArrayList(); + private Transformer transformer; public Runtime(Backend... backends) { this.backends = asList(backends); @@ -45,7 +45,7 @@ private List stepDefinitionMatches(Step step) { for (StepDefinition stepDefinition : backend.getStepDefinitions()) { List arguments = stepDefinition.matchedArguments(step); if (arguments != null) { - result.add(new StepDefinitionMatch(arguments, stepDefinition, step)); + result.add(new StepDefinitionMatch(arguments, stepDefinition, step, getTransformer())); } } } @@ -84,4 +84,15 @@ public int compare(Step a, Step b) { public World newWorld() { return new World(backends, this); } + + public Transformer getTransformer() { + if (this.transformer == null) { + this.transformer = new Transformer(); + } + return this.transformer; + } + + public void setTransformer(Transformer transformer) { + this.transformer = transformer; + } } diff --git a/core/src/main/java/cucumber/runtime/StepDefinitionMatch.java b/core/src/main/java/cucumber/runtime/StepDefinitionMatch.java index b412bbf0c0..4c5649b8ef 100644 --- a/core/src/main/java/cucumber/runtime/StepDefinitionMatch.java +++ b/core/src/main/java/cucumber/runtime/StepDefinitionMatch.java @@ -6,17 +6,22 @@ import java.lang.reflect.InvocationTargetException; import java.util.List; +import java.util.Locale; + +import cucumber.runtime.transformers.Transformer; import static java.util.Arrays.asList; public class StepDefinitionMatch extends Match { private final StepDefinition stepDefinition; private final Step step; + private Transformer transformer; - public StepDefinitionMatch(List arguments, StepDefinition stepDefinition, Step step) { + public StepDefinitionMatch(List arguments, StepDefinition stepDefinition, Step step, Transformer transformer) { super(arguments, stepDefinition.getLocation()); this.stepDefinition = stepDefinition; this.step = step; + this.transformer = transformer; } public void run(String path) throws Throwable { @@ -39,13 +44,15 @@ private Object[] getTransformedArgs(Class[] parameterTypes) { Object[] result = new Object[getArguments().size()]; int n = 0; for (Argument a : getArguments()) { - // TODO: Use the Locale for transformation - // TODO: Also use method signature to transform ints... - result[n++] = a.getVal(); + result[n] = this.transformer.transform(a, parameterTypes[n++], getLocale()); } return result; } + private Locale getLocale() { + return this.stepDefinition.getLocale(); + } + private Throwable filterStacktrace(Throwable error, StackTraceElement stepLocation) { StackTraceElement[] stackTraceElements = error.getStackTrace(); if (error.getCause() != null && error.getCause() != error) { diff --git a/core/src/main/java/cucumber/runtime/World.java b/core/src/main/java/cucumber/runtime/World.java index 268d23ef4e..97ab471608 100644 --- a/core/src/main/java/cucumber/runtime/World.java +++ b/core/src/main/java/cucumber/runtime/World.java @@ -40,7 +40,7 @@ public void runStep(Step step, String path, Reporter reporter) { } finally { long duration = System.nanoTime() - start; String status = e == null ? Result.PASSED : Result.FAILED; - Result result = new Result(status, duration, e); + Result result = new Result(status, duration, e, null); reporter.result(result); } } else { diff --git a/core/src/main/java/cucumber/runtime/transformers/BigDecimalTransformable.java b/core/src/main/java/cucumber/runtime/transformers/BigDecimalTransformable.java new file mode 100644 index 0000000000..ded02d6f37 --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/BigDecimalTransformable.java @@ -0,0 +1,14 @@ +package cucumber.runtime.transformers; + +import java.math.BigDecimal; + +public class BigDecimalTransformable extends + TransformableWithNumberFormat { + + @Override + protected BigDecimal doTransform(Number number) { + // See http://java.sun.com/j2se/6/docs/api/java/math/BigDecimal.html#BigDecimal%28double%29 + return new BigDecimal(Double.toString(number.doubleValue())); + } + +} diff --git a/core/src/main/java/cucumber/runtime/transformers/BigIntegerTransformable.java b/core/src/main/java/cucumber/runtime/transformers/BigIntegerTransformable.java new file mode 100644 index 0000000000..b34660bb63 --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/BigIntegerTransformable.java @@ -0,0 +1,12 @@ +package cucumber.runtime.transformers; + +import java.math.BigInteger; + +public class BigIntegerTransformable extends TransformableWithNumberFormat { + + @Override + protected BigInteger doTransform(Number argument) { + return BigInteger.valueOf(argument.longValue()); + } + +} diff --git a/core/src/main/java/cucumber/runtime/transformers/BooleanTransformable.java b/core/src/main/java/cucumber/runtime/transformers/BooleanTransformable.java new file mode 100644 index 0000000000..2b16029270 --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/BooleanTransformable.java @@ -0,0 +1,15 @@ +package cucumber.runtime.transformers; + +import java.util.Locale; + +public class BooleanTransformable implements Transformable { + + public Boolean transform(String argument, Locale locale) { + if ("false".equalsIgnoreCase(argument) || "true".equalsIgnoreCase(argument)) { + return Boolean.parseBoolean(argument); + } else { + throw new TransformationException(String.format(locale, "Could not convert %s to Boolean", argument)); + } + } + +} diff --git a/core/src/main/java/cucumber/runtime/transformers/ByteTransformable.java b/core/src/main/java/cucumber/runtime/transformers/ByteTransformable.java new file mode 100644 index 0000000000..c8294d4eda --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/ByteTransformable.java @@ -0,0 +1,10 @@ +package cucumber.runtime.transformers; + +public class ByteTransformable extends TransformableWithNumberFormat { + + @Override + protected Byte doTransform(Number value) { + return Byte.valueOf(value.byteValue()); + } + +} diff --git a/core/src/main/java/cucumber/runtime/transformers/CharacterTransformable.java b/core/src/main/java/cucumber/runtime/transformers/CharacterTransformable.java new file mode 100644 index 0000000000..11529bd227 --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/CharacterTransformable.java @@ -0,0 +1,14 @@ +package cucumber.runtime.transformers; + +import java.util.Locale; + +public class CharacterTransformable implements Transformable { + + public Character transform(String argument, Locale locale) { + if (argument.length() < 1) { + return null; + } + return Character.valueOf(argument.charAt(0)); + } + +} diff --git a/core/src/main/java/cucumber/runtime/transformers/DateTransformable.java b/core/src/main/java/cucumber/runtime/transformers/DateTransformable.java new file mode 100644 index 0000000000..30d59080b4 --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/DateTransformable.java @@ -0,0 +1,17 @@ +package cucumber.runtime.transformers; + +import java.text.DateFormat; +import java.text.Format; +import java.util.Date; +import java.util.Locale; + +public class DateTransformable extends TransformableWithFormat { + + public Format getFormat(Locale locale) { + DateFormat format = DateFormat + .getDateInstance(DateFormat.SHORT, locale); + format.setLenient(false); + return format; + } + +} diff --git a/core/src/main/java/cucumber/runtime/transformers/DoubleTransformable.java b/core/src/main/java/cucumber/runtime/transformers/DoubleTransformable.java new file mode 100644 index 0000000000..03c2ab7a9f --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/DoubleTransformable.java @@ -0,0 +1,10 @@ +package cucumber.runtime.transformers; + +public class DoubleTransformable extends TransformableWithNumberFormat { + + @Override + protected Double doTransform(Number transform) { + return Double.valueOf(transform.doubleValue()); + } + +} diff --git a/core/src/main/java/cucumber/runtime/transformers/FloatTransformable.java b/core/src/main/java/cucumber/runtime/transformers/FloatTransformable.java new file mode 100644 index 0000000000..0668b38764 --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/FloatTransformable.java @@ -0,0 +1,10 @@ +package cucumber.runtime.transformers; + +public class FloatTransformable extends TransformableWithNumberFormat { + + @Override + protected Float doTransform(Number argument) { + return Float.valueOf(argument.floatValue()); + } + +} diff --git a/core/src/main/java/cucumber/runtime/transformers/IntegerTransformable.java b/core/src/main/java/cucumber/runtime/transformers/IntegerTransformable.java new file mode 100644 index 0000000000..97a4aa861d --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/IntegerTransformable.java @@ -0,0 +1,10 @@ +package cucumber.runtime.transformers; + +public class IntegerTransformable extends TransformableWithNumberFormat { + + @Override + protected Integer doTransform(Number number) { + return Integer.valueOf(number.intValue()); + } + +} diff --git a/core/src/main/java/cucumber/runtime/transformers/LongTransformable.java b/core/src/main/java/cucumber/runtime/transformers/LongTransformable.java new file mode 100644 index 0000000000..229f1d1763 --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/LongTransformable.java @@ -0,0 +1,10 @@ +package cucumber.runtime.transformers; + +public class LongTransformable extends TransformableWithNumberFormat { + + @Override + protected Long doTransform(Number argument) { + return Long.valueOf(argument.longValue()); + } + +} diff --git a/core/src/main/java/cucumber/runtime/transformers/ShortTransformable.java b/core/src/main/java/cucumber/runtime/transformers/ShortTransformable.java new file mode 100644 index 0000000000..64464f9d54 --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/ShortTransformable.java @@ -0,0 +1,10 @@ +package cucumber.runtime.transformers; + +public class ShortTransformable extends TransformableWithNumberFormat { + + @Override + protected Short doTransform(Number argument) { + return Short.valueOf(argument.shortValue()); + } + +} diff --git a/core/src/main/java/cucumber/runtime/transformers/StringTransformable.java b/core/src/main/java/cucumber/runtime/transformers/StringTransformable.java new file mode 100644 index 0000000000..88fe93d3f3 --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/StringTransformable.java @@ -0,0 +1,11 @@ +package cucumber.runtime.transformers; + +import java.util.Locale; + +public class StringTransformable implements Transformable { + + public String transform(String argument, Locale locale) { + return argument; + } + +} diff --git a/core/src/main/java/cucumber/runtime/transformers/Transformable.java b/core/src/main/java/cucumber/runtime/transformers/Transformable.java new file mode 100644 index 0000000000..6ed96e493d --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/Transformable.java @@ -0,0 +1,7 @@ +package cucumber.runtime.transformers; + +import java.util.Locale; + +public interface Transformable { + public T transform(String argument, Locale locale); +} diff --git a/core/src/main/java/cucumber/runtime/transformers/TransformableWithFormat.java b/core/src/main/java/cucumber/runtime/transformers/TransformableWithFormat.java new file mode 100644 index 0000000000..8b3b171f22 --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/TransformableWithFormat.java @@ -0,0 +1,45 @@ +package cucumber.runtime.transformers; + +import java.text.Format; +import java.text.ParsePosition; +import java.util.Locale; + +public abstract class TransformableWithFormat implements Transformable { + + public T transform(String argument, Locale locale) { + return transform(getFormat(locale), argument, locale); + } + + /** + * + * @param locale + * The locale used to parse + * @return A Format to parse the argument + */ + public abstract Format getFormat(Locale locale); + + /** + * Parses a value using one of the java.util.text format classes. + * + * @param format + * The format to use + * @param argument + * The object to parse + * @param locale + * The locale used to parse + * @return The object + * @throws TransformationException + * Thrown if parsing fails + */ + @SuppressWarnings("unchecked") + protected T transform(final Format format, final String argument, + Locale locale) { + ParsePosition position = new ParsePosition(0); + Object result = format.parseObject(argument, position); + if (position.getErrorIndex() != -1) { + throw new TransformationException("Can't parse '" + argument + + "' using format " + format); + } + return (T) result; + } +} diff --git a/core/src/main/java/cucumber/runtime/transformers/TransformableWithNumberFormat.java b/core/src/main/java/cucumber/runtime/transformers/TransformableWithNumberFormat.java new file mode 100644 index 0000000000..1ccf9f51a8 --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/TransformableWithNumberFormat.java @@ -0,0 +1,22 @@ +package cucumber.runtime.transformers; + +import java.text.Format; +import java.text.NumberFormat; +import java.util.Locale; + +public abstract class TransformableWithNumberFormat extends + TransformableWithFormat { + + @Override + public T transform(String argument, Locale locale) { + return doTransform(super.transform(argument, locale)); + } + + @Override + public Format getFormat(Locale locale) { + return NumberFormat.getNumberInstance(locale); + } + + protected abstract T doTransform(Number argument); + +} diff --git a/core/src/main/java/cucumber/runtime/transformers/TransformationException.java b/core/src/main/java/cucumber/runtime/transformers/TransformationException.java new file mode 100644 index 0000000000..8c61fdd182 --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/TransformationException.java @@ -0,0 +1,21 @@ +package cucumber.runtime.transformers; + +public class TransformationException extends RuntimeException { + + /** + * + */ + private static final long serialVersionUID = 3893851462286949513L; + + public TransformationException(Throwable t) { + super(t); + } + + public TransformationException(String message, Throwable t) { + super (message, t); + } + + public TransformationException(String message) { + super (message); + } +} diff --git a/core/src/main/java/cucumber/runtime/transformers/Transformer.java b/core/src/main/java/cucumber/runtime/transformers/Transformer.java new file mode 100644 index 0000000000..7e26370439 --- /dev/null +++ b/core/src/main/java/cucumber/runtime/transformers/Transformer.java @@ -0,0 +1,78 @@ +package cucumber.runtime.transformers; + +import gherkin.formatter.Argument; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +/** + * + * Class for transforming argument to a certain type using a Locale + * + */ +public class Transformer { + private Map, Transformable> transformables; + + @SuppressWarnings("unchecked") + public T transform(Argument argument, Class clazz, Locale locale) { + Transformable transformable = getTransformable(clazz); + if (transformable == null) { + throw new TransformationException("Can't transform " + argument.getVal() + " to: " + clazz.getName() + ". No transformable found."); + } + return (T) transformable.transform(argument.getVal(), locale); + } + + private Transformable getTransformable(Class clazz) { + return getTransformables().get(clazz); + } + + public Map, Transformable> getTransformables() { + if (this.transformables == null) { + this.transformables = registerDefaultTransformables(); + } + return this.transformables; + } + + protected Map, Transformable> registerDefaultTransformables() { + HashMap, Transformable> hashMap = new HashMap, Transformable>(); + hashMap.put(String.class, new StringTransformable()); + hashMap.put(Date.class, new DateTransformable()); + hashMap.put(BigDecimal.class, new BigDecimalTransformable()); + hashMap.put(BigIntegerTransformable.class, new BigIntegerTransformable()); + BooleanTransformable booleanTransformable = new BooleanTransformable(); + hashMap.put(Boolean.TYPE, booleanTransformable); + hashMap.put(Boolean.class, booleanTransformable); + ByteTransformable byteTransformable = new ByteTransformable(); + hashMap.put(Byte.TYPE, byteTransformable); + hashMap.put(Byte.class, byteTransformable); + CharacterTransformable characterTransformable = new CharacterTransformable(); + hashMap.put(Character.TYPE, characterTransformable); + hashMap.put(Character.class, characterTransformable); + DoubleTransformable doubleTransformable = new DoubleTransformable(); + hashMap.put(Double.TYPE, doubleTransformable); + hashMap.put(Double.class, doubleTransformable); + FloatTransformable floatTransformable = new FloatTransformable(); + hashMap.put(Float.TYPE, floatTransformable); + hashMap.put(Float.class, floatTransformable); + IntegerTransformable integerTransformable = new IntegerTransformable(); + hashMap.put(Integer.TYPE, integerTransformable); + hashMap.put(Integer.class, integerTransformable); + LongTransformable longTransformable = new LongTransformable(); + hashMap.put(Long.TYPE, longTransformable); + hashMap.put(Long.class, longTransformable); + ShortTransformable shortTransformable = new ShortTransformable(); + hashMap.put(Short.TYPE, shortTransformable); + hashMap.put(Short.class, shortTransformable); + return hashMap; + } + + public void addTransformable(Class clazz, Transformable transformable) { + getTransformables().put(clazz, transformable); + } + + public void setTransformables(Map, Transformable> transformables) { + this.transformables = transformables; + } +} diff --git a/core/src/main/java/cuke4duke/internal/Utils.java b/core/src/main/java/cuke4duke/internal/Utils.java index bee2aa56b2..31b9d7bb3d 100644 --- a/core/src/main/java/cuke4duke/internal/Utils.java +++ b/core/src/main/java/cuke4duke/internal/Utils.java @@ -20,4 +20,15 @@ public static Locale localeFor(String isoString) { return new Locale(languageAndCountry[0], languageAndCountry[1]); } } + + public static String join(Object[] objects, String separator) { + StringBuilder sb = new StringBuilder(); + int i = 0; + for (Object o : objects) { + if (i != 0) sb.append(separator); + sb.append(o); + i++; + } + return sb.toString(); + } } diff --git a/core/src/main/java/cuke4duke/internal/jvmclass/DefaultJvmTransforms.java b/core/src/main/java/cuke4duke/internal/jvmclass/DefaultJvmTransforms.java deleted file mode 100644 index 002081a6f1..0000000000 --- a/core/src/main/java/cuke4duke/internal/jvmclass/DefaultJvmTransforms.java +++ /dev/null @@ -1,85 +0,0 @@ -package cuke4duke.internal.jvmclass; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.text.NumberFormat; -import java.text.ParseException; -import java.util.Locale; - -public class DefaultJvmTransforms { - public static Object transformStringToObject(String argument, Locale locale) { - return argument; - } - - public static int transformStringToInt(String argument, Locale locale) throws ParseException { - return NumberFormat.getInstance(locale).parse(argument).intValue(); - } - - public static Integer transformStringToInteger(String argument, Locale locale) throws ParseException { - return transformStringToInt(argument, locale); - } - - public static long transformStringToLongPrimitive(String argument, Locale locale) throws ParseException { - return NumberFormat.getInstance(locale).parse(argument).longValue(); - } - - public static Long transformStringToLong(String argument, Locale locale) throws ParseException { - return transformStringToLongPrimitive(argument, locale); - } - - public static double transformStringToDoublePrimitive(String argument, Locale locale) throws ParseException { - return NumberFormat.getInstance(locale).parse(argument).doubleValue(); - } - - public static Double transformStringToDouble(String argument, Locale locale) throws ParseException { - return transformStringToDoublePrimitive(argument, locale); - } - - public static float transformStringToFloatPrimitive(String argument, Locale locale) throws ParseException { - return NumberFormat.getInstance(locale).parse(argument).floatValue(); - } - - public static Float transformStringToFloat(String argument, Locale locale) throws ParseException { - return transformStringToFloatPrimitive(argument, locale); - } - - public static short transformStringToShortPrimitive(String argument, Locale locale) throws ParseException { - return NumberFormat.getInstance(locale).parse(argument).shortValue(); - } - - public static Short transformStringToShort(String argument, Locale locale) throws ParseException { - return transformStringToShortPrimitive(argument, locale); - } - - public static byte transformStringToBytePrimitive(String argument, Locale locale) throws ParseException { - return NumberFormat.getInstance(locale).parse(argument).byteValue(); - } - - public static Byte transformStringToByte(String argument, Locale locale) throws ParseException { - return transformStringToBytePrimitive(argument, locale); - } - - public static char transformStringToChar(String argument, Locale locale) { - return argument.charAt(0); - } - - public static Character transformStringToCharacters(String argument, Locale locale) { - return argument.charAt(0); - } - - public static BigDecimal transformStringToBigDecimal(String argument, Locale locale) throws ParseException { - return BigDecimal.valueOf(transformStringToDoublePrimitive(argument, locale)); - } - - public static BigInteger transformStringToBigInteger(String argument, Locale locale) throws ParseException { - return BigInteger.valueOf(transformStringToLongPrimitive(argument, locale)); - } - - public static boolean transformStringToBooleanPrimitive(String argument, Locale locale) { - return Boolean.valueOf(argument); - } - - public static Boolean transformStringToBoolean(String argument, Locale locale) { - return Boolean.valueOf(argument); - } -} diff --git a/core/src/test/java/cucumber/runtime/StepDefinitionMatchTest.java b/core/src/test/java/cucumber/runtime/StepDefinitionMatchTest.java new file mode 100644 index 0000000000..57571f254a --- /dev/null +++ b/core/src/test/java/cucumber/runtime/StepDefinitionMatchTest.java @@ -0,0 +1,29 @@ +package cucumber.runtime; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import gherkin.formatter.Argument; +import gherkin.formatter.model.Step; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +import org.junit.Test; + +import cucumber.runtime.transformers.Transformer; +public class StepDefinitionMatchTest { + @Test + public void shouldConvertParameters() throws Throwable { + List arguments = Arrays.asList(new Argument(0, "5")); + StepDefinition stepDefinition = mock(StepDefinition.class); + when(stepDefinition.getLocale()).thenReturn(Locale.ENGLISH); + Class[] parameterTypes = {Integer.TYPE}; + when(stepDefinition.getParameterTypes()).thenReturn(parameterTypes ); + StepDefinitionMatch stepDefinitionMatch = new StepDefinitionMatch(arguments, stepDefinition, mock(Step.class), new Transformer()); + stepDefinitionMatch.run("step-definition-match-test"); + Object[] args = {5}; + verify(stepDefinition).execute(args); + } +} diff --git a/core/src/test/java/cucumber/runtime/transformers/StandardTransformersTest.java b/core/src/test/java/cucumber/runtime/transformers/StandardTransformersTest.java new file mode 100644 index 0000000000..d2a0b94bc7 --- /dev/null +++ b/core/src/test/java/cucumber/runtime/transformers/StandardTransformersTest.java @@ -0,0 +1,133 @@ +package cucumber.runtime.transformers; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; + +import org.junit.Assert; +import org.junit.Test; + +import cuke4duke.internal.Utils; + +public class StandardTransformersTest { + @Test + public void shouldTransformBoolean() { + Boolean transformFalse = new BooleanTransformable().transform("false", Locale.ENGLISH); + Boolean transformTrue = new BooleanTransformable().transform("true", Locale.ENGLISH); + Assert.assertFalse(transformFalse); + Assert.assertTrue(transformTrue); + } + + @Test(expected = TransformationException.class) + public void shouldThrowTransformationExceptionWhenConvertingBoolean() { + new BooleanTransformable().transform("vrai", Locale.ENGLISH); + } + + @Test + public void shouldTransformBigDecimal() { + BigDecimal englishBigDecimal = new BigDecimalTransformable().transform("300.15", + Locale.ENGLISH); + BigDecimal englishBigDecimal2 = new BigDecimalTransformable().transform("30000000.15", + Locale.ENGLISH); + BigDecimal englishInteger = new BigDecimalTransformable().transform("300", Locale.ENGLISH); + BigDecimal frenchBigDecimal = new BigDecimalTransformable().transform("300,15", + Locale.FRENCH); + Assert.assertEquals(new BigDecimal("300.15"), englishBigDecimal); + Assert.assertEquals(new BigDecimal("30000000.15"), englishBigDecimal2); + Assert.assertEquals(new BigDecimal("300.15"), frenchBigDecimal); + Assert.assertEquals(new BigDecimal("300.0"), englishInteger); + } + + @Test + public void shouldTransformDate() { + Assert.assertEquals(getDateToTest(), + new DateTransformable().transform("11/29/2011", Locale.ENGLISH)); + Assert.assertEquals(getDateToTest(), + new DateTransformable().transform("29/11/2011", Locale.FRENCH)); + } + + @Test(expected = TransformationException.class) + public void shouldThrowTransformationExceptionWhenConvertingInvalidDate() { + Assert.assertEquals(getDateToTest(), + new DateTransformable().transform("29/11/2011", Locale.ENGLISH)); + } + + private Date getDateToTest() { + Calendar calendar = Calendar.getInstance(); + calendar.set(2011, 10, 29, 0, 0, 0); + calendar.set(Calendar.MILLISECOND, 0); + return calendar.getTime(); + } + + @Test + public void shouldTransformIntegers() { + Integer expected = Integer.valueOf(1000); + Assert.assertEquals(expected, new IntegerTransformable().transform("1000", Locale.ENGLISH)); + Assert.assertEquals(expected, new IntegerTransformable().transform("1,000", Locale.ENGLISH)); + Assert.assertEquals(expected, + new IntegerTransformable().transform("1.000", Utils.localeFor("pt"))); + } + + @Test + public void shouldTransformDoubles() { + Double expected = Double.valueOf(3000.15); + Assert.assertEquals(expected, + new DoubleTransformable().transform("3000.15", Locale.ENGLISH)); + Assert.assertEquals(expected, + new DoubleTransformable().transform("3,000.15", Locale.ENGLISH)); + Assert.assertEquals(expected, + new DoubleTransformable().transform("3.000,15", Utils.localeFor("pt"))); + Assert.assertEquals(expected, + new DoubleTransformable().transform("3000,15", Locale.FRENCH)); + } + + @Test + public void shouldTransformLongs() { + Long expected = Long.valueOf(8589934592L); + Assert.assertEquals(expected, new LongTransformable().transform("8589934592", Locale.ENGLISH)); + Assert.assertEquals(expected, new LongTransformable().transform("8,589,934,592", Locale.ENGLISH)); + } + + @Test + public void shouldTransformShorts() { + short exp = 32767; + short exp2 = -32768; + Short expected = Short.valueOf(exp); + Short expected2 = Short.valueOf(exp2); + Assert.assertEquals(expected, new ShortTransformable().transform("32767", Locale.ENGLISH)); + Assert.assertEquals(expected, new ShortTransformable().transform("32,767", Locale.ENGLISH)); + Assert.assertEquals(expected2, new ShortTransformable().transform("-32,768", Locale.ENGLISH)); + } + + @Test + public void shouldTransformBytes() { + byte exp = 127; + Byte expected = Byte.valueOf(exp); + Assert.assertEquals(expected, new ByteTransformable().transform("127", Locale.ENGLISH)); + Assert.assertEquals(expected, new ByteTransformable().transform("127", Locale.ENGLISH)); + } + + @Test + public void shouldTransformChars() { + Character expected = Character.valueOf('C'); + Assert.assertEquals(expected, new CharacterTransformable().transform("Cedric", Locale.ENGLISH)); + Assert.assertEquals(expected, new CharacterTransformable().transform("C", Locale.ENGLISH)); + } + + @Test + public void shouldTransformFloats() { + Float expected = Float.valueOf(3000.15f); + Assert.assertEquals(expected, new FloatTransformable().transform("3000.15", Locale.ENGLISH)); + Assert.assertEquals(expected, new FloatTransformable().transform("3,000.15", Locale.ENGLISH)); + } + + @Test + public void shouldTransformBigInteger() { + BigInteger expected = BigInteger.valueOf(8589934592L); + Assert.assertEquals(expected, new BigIntegerTransformable().transform("8589934592", Locale.ENGLISH)); + Assert.assertEquals(expected, new BigIntegerTransformable().transform("8,589,934,592", Locale.ENGLISH)); + } + +} diff --git a/core/src/test/java/cucumber/runtime/transformers/TransformerTest.java b/core/src/test/java/cucumber/runtime/transformers/TransformerTest.java new file mode 100644 index 0000000000..890d499c16 --- /dev/null +++ b/core/src/test/java/cucumber/runtime/transformers/TransformerTest.java @@ -0,0 +1,25 @@ +package cucumber.runtime.transformers; + +import gherkin.formatter.Argument; + +import java.math.BigDecimal; +import java.util.Locale; + +import org.junit.Assert; +import org.junit.Test; + +public class TransformerTest { + @Test + public void shouldTransformToTheRightType() { + Argument argument = new Argument(0, "true"); + Transformer transformer = new Transformer(); + Locale english = Locale.ENGLISH; + Boolean transformBool = transformer.transform(argument, Boolean.class, english); + Assert.assertTrue(transformBool); + boolean transformBoolPrimitive = transformer.transform(argument, Boolean.TYPE, english); + Assert.assertTrue("Boolean primitive transformation", transformBoolPrimitive); + Assert.assertEquals("Float class transformation", Float.valueOf(3000.15f), transformer.transform(new Argument(0, "3000.15"), Float.class, english)); + Assert.assertEquals("Float primitive transformation", Float.valueOf(3000.15f), transformer.transform(new Argument(0, "3000.15"), Float.TYPE, english)); + Assert.assertEquals("BigDecimal transformation", new BigDecimal("3000.15"), transformer.transform(new Argument(0, "3000.15"), BigDecimal.class, english)); + } +} diff --git a/cucumber-ant/pom.xml b/cucumber-ant/pom.xml index 5f8cfd7a00..6a3f9a8932 100644 --- a/cucumber-ant/pom.xml +++ b/cucumber-ant/pom.xml @@ -12,7 +12,6 @@ cucumber-ant - 0.4.3-SNAPSHOT jar Cucumber: Ant diff --git a/groovy/pom.xml b/groovy/pom.xml old mode 100755 new mode 100644 index 523f0e1413..d7432aa10f --- a/groovy/pom.xml +++ b/groovy/pom.xml @@ -12,7 +12,6 @@ groovy - 0.4.3-SNAPSHOT jar Cucumber: Groovy diff --git a/guice/pom.xml b/guice/pom.xml old mode 100755 new mode 100644 index 75d2ea95d6..5d11b7f7a5 --- a/guice/pom.xml +++ b/guice/pom.xml @@ -12,7 +12,6 @@ guice - 0.4.3-SNAPSHOT jar Cucumber: Guice diff --git a/ioke/pom.xml b/ioke/pom.xml old mode 100755 new mode 100644 index 6fff81e07b..8a94b643b6 --- a/ioke/pom.xml +++ b/ioke/pom.xml @@ -12,7 +12,6 @@ ioke - 0.4.3-SNAPSHOT jar Cucumber: Ioke diff --git a/java/pom.xml b/java/pom.xml old mode 100755 new mode 100644 index 8a398e917b..1e25af7eaa --- a/java/pom.xml +++ b/java/pom.xml @@ -12,7 +12,6 @@ java - 0.4.3-SNAPSHOT jar Cucumber: Java @@ -26,5 +25,11 @@ junit test + + org.mockito + mockito-all + test + true + diff --git a/java/src/main/java/cucumber/runtime/java/ClasspathMethodScanner.java b/java/src/main/java/cucumber/runtime/java/ClasspathMethodScanner.java index bd90ff58a6..426a8f5d7e 100644 --- a/java/src/main/java/cucumber/runtime/java/ClasspathMethodScanner.java +++ b/java/src/main/java/cucumber/runtime/java/ClasspathMethodScanner.java @@ -49,7 +49,7 @@ private void scan(Method method, Collection> cucumbe if (isHookAnnotation(annotation)) { // TODO Add hook } - + //TODO: scan cucumber.annotation.Transform annotations Locale locale = Utils.localeFor(annotation.annotationType().getAnnotation(CucumberAnnotation.class).value()); try { Method regexpMethod = annotation.getClass().getMethod("value"); diff --git a/java/src/main/java/cucumber/runtime/java/JavaBackend.java b/java/src/main/java/cucumber/runtime/java/JavaBackend.java index 71cab99ec5..a906704ff4 100644 --- a/java/src/main/java/cucumber/runtime/java/JavaBackend.java +++ b/java/src/main/java/cucumber/runtime/java/JavaBackend.java @@ -1,10 +1,14 @@ package cucumber.runtime.java; +import cucumber.annotation.Pending; import cucumber.classpath.Classpath; import cucumber.runtime.Backend; +import cucumber.runtime.CucumberException; import cucumber.runtime.StepDefinition; +import cuke4duke.internal.Utils; import gherkin.formatter.model.Step; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; @@ -19,6 +23,11 @@ public JavaBackend(String packagePrefix) { this.objectFactory = Classpath.instantiateSubclass(ObjectFactory.class); new ClasspathMethodScanner().scan(this, packagePrefix); } + + public JavaBackend(ObjectFactory objectFactory, List stepDefinitions) { + this.objectFactory = objectFactory; + this.stepDefinitions = stepDefinitions; + } public List getStepDefinitions() { return stepDefinitions; @@ -41,4 +50,22 @@ void addStepDefinition(Pattern pattern, Method method, Locale locale) { objectFactory.addClass(clazz); stepDefinitions.add(new JavaStepDefinition(pattern, method, objectFactory, locale)); } + + public Object invoke(Method method, Object[] javaArgs) { + try { + if (method.isAnnotationPresent(Pending.class)) { + throw new CucumberException(method.getAnnotation(Pending.class).value()); + } else { + return method.invoke(this.objectFactory.getInstance(method.getDeclaringClass()), javaArgs); + } + } catch (IllegalArgumentException e) { + String m = "Couldn't invokeWithArgs " + method.toGenericString() + " with " + + Utils.join(javaArgs, ","); + throw new CucumberException(m); + } catch (InvocationTargetException e) { + throw new CucumberException("Couldn't invoke method", e.getTargetException()); + } catch (IllegalAccessException e) { + throw new CucumberException("Couldn't invoke method", e); + } + } } diff --git a/java/src/main/java/cucumber/runtime/java/JavaMethodTransform.java b/java/src/main/java/cucumber/runtime/java/JavaMethodTransform.java new file mode 100644 index 0000000000..9a9066d367 --- /dev/null +++ b/java/src/main/java/cucumber/runtime/java/JavaMethodTransform.java @@ -0,0 +1,23 @@ +package cucumber.runtime.java; + +import java.lang.reflect.Method; +import java.util.Locale; + +import cucumber.runtime.transformers.Transformable; + +public class JavaMethodTransform implements Transformable { + + private Method transformMethod; + private JavaBackend backend; + + public JavaMethodTransform(Method transformMethod, JavaBackend backend) { + super(); + this.transformMethod = transformMethod; + this.backend = backend; + } + + public Object transform(String argument, Locale locale) { + return this.backend.invoke(this.transformMethod, new Object[] {argument}); + } + +} diff --git a/java/src/test/java/cucumber/runtime/java/JavaMethodTransformTest.java b/java/src/test/java/cucumber/runtime/java/JavaMethodTransformTest.java new file mode 100644 index 0000000000..19f472131c --- /dev/null +++ b/java/src/test/java/cucumber/runtime/java/JavaMethodTransformTest.java @@ -0,0 +1,68 @@ +package cucumber.runtime.java; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.lang.reflect.Method; +import java.util.Locale; + +import junit.framework.Assert; + +import org.junit.Test; + +import cucumber.annotation.Pending; +import cucumber.annotation.Transform; +import cucumber.runtime.CucumberException; + +public class JavaMethodTransformTest { + + @Test + public void shouldTransformToUser() throws Exception { + HasATransformMethod hasATransformMethod = new HasATransformMethod(); + Method transformMethod = hasATransformMethod.getClass().getMethod("transformToUser", String.class); + ObjectFactory objectFactory = mock(ObjectFactory.class); + when(objectFactory.getInstance(HasATransformMethod.class)).thenReturn(hasATransformMethod); + JavaBackend backend = new JavaBackend(objectFactory, null); + JavaMethodTransform javaMethodTransform = new JavaMethodTransform(transformMethod, backend); + Object transformed = javaMethodTransform.transform("Cucumber", Locale.getDefault()); + Assert.assertEquals(User.class, transformed.getClass()); + Assert.assertEquals("Cucumber", ((User)transformed).getName()); + } + + @Test(expected=CucumberException.class) + public void shouldThrowExceptionWhenUsingPendingTransform() throws Exception { + HasAPendingTransformMethod hasATransformMethod = new HasAPendingTransformMethod(); + Method transformMethod = hasATransformMethod.getClass().getMethod("transformToUser", String.class); + ObjectFactory objectFactory = mock(ObjectFactory.class); + when(objectFactory.getInstance(HasAPendingTransformMethod.class)).thenReturn(hasATransformMethod); + JavaBackend backend = new JavaBackend(objectFactory, null); + new JavaMethodTransform(transformMethod, backend).transform("WhatEver", Locale.getDefault()); + } + + public class User { + private String name; + + public String getName() { + return name; + } + + public User setName(String name) { + this.name = name; + return this; + } + } + + public class HasATransformMethod { + @Transform + public User transformToUser(String name) { + return new User().setName(name); + } + } + + public class HasAPendingTransformMethod { + @Transform + @Pending("Testing") + public User transformToUser(String name) { + return new User().setName(name); + } + } +} diff --git a/picocontainer/pom.xml b/picocontainer/pom.xml old mode 100755 new mode 100644 index 59e9168169..801261fc92 --- a/picocontainer/pom.xml +++ b/picocontainer/pom.xml @@ -12,7 +12,6 @@ picocontainer - 0.4.3-SNAPSHOT jar Cucumber: PicoContainer diff --git a/pom.xml b/pom.xml index 5e0de63bc0..892e704184 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ UTF-8 UTF-8 - 2.4.2 + 2.4.5 3.3 1.7 1.5.3 diff --git a/rhino/pom.xml b/rhino/pom.xml old mode 100755 new mode 100644 index 3f2e40de0a..a4277bddeb --- a/rhino/pom.xml +++ b/rhino/pom.xml @@ -12,7 +12,6 @@ rhino - 0.4.3-SNAPSHOT jar Cucumber: Rhino diff --git a/spring/pom.xml b/spring/pom.xml old mode 100755 new mode 100644 index c37a5c7701..ee4ba6e964 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -12,7 +12,6 @@ spring - 0.4.3-SNAPSHOT jar Cucumber: Spring