diff --git a/spock-core/src/main/java/org/spockframework/compiler/ConditionRewriter.java b/spock-core/src/main/java/org/spockframework/compiler/ConditionRewriter.java index e96b854dd4..7bd6c2b047 100644 --- a/spock-core/src/main/java/org/spockframework/compiler/ConditionRewriter.java +++ b/spock-core/src/main/java/org/spockframework/compiler/ConditionRewriter.java @@ -28,8 +28,11 @@ import org.spockframework.util.AbstractExpressionConverter; import org.spockframework.util.Assert; import org.spockframework.util.Identifiers; +import org.spockframework.util.ReflectionUtil; import org.spockframework.util.TextUtil; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; @@ -59,6 +62,9 @@ public class ConditionRewriter extends AbstractExpressionConverter implements GroovyCodeVisitorCompat { private static final Pattern COMMENTS_PATTERN = Pattern.compile("/\\*.*?\\*/|//.*$"); private static final String THROWABLE = "$spock_condition_throwable"; + private static final Constructor RANGE_EXPRESSION_CONSTRUCTOR_GROOVY_4 = ReflectionUtil.getDeclaredConstructorBySignature(RangeExpression.class, Expression.class, Expression.class, Boolean.TYPE, Boolean.TYPE); + private static final Method RANGE_EXPRESSION_IS_EXCLUSIVE_LEFT = ReflectionUtil.getDeclaredMethodBySignature(RangeExpression.class, "isExclusiveLeft"); + private static final Method RANGE_EXPRESSION_IS_EXCLUSIVE_RIGHT = ReflectionUtil.getDeclaredMethodBySignature(RangeExpression.class, "isExclusiveRight"); private final IRewriteResources resources; @@ -340,11 +346,20 @@ public void visitListExpression(ListExpression expr) { @Override public void visitRangeExpression(RangeExpression expr) { - RangeExpression conversion = - new RangeExpression( - convert(expr.getFrom()), - convert(expr.getTo()), - expr.isInclusive()); + RangeExpression conversion; + if (RANGE_EXPRESSION_CONSTRUCTOR_GROOVY_4 != null) { + conversion = ReflectionUtil.newInstance(RANGE_EXPRESSION_CONSTRUCTOR_GROOVY_4, + convert(expr.getFrom()), + convert(expr.getTo()), + ReflectionUtil.invokeMethod(expr, RANGE_EXPRESSION_IS_EXCLUSIVE_LEFT), + ReflectionUtil.invokeMethod(expr, RANGE_EXPRESSION_IS_EXCLUSIVE_RIGHT) + ); + } else { + conversion = new RangeExpression( + convert(expr.getFrom()), + convert(expr.getTo()), + expr.isInclusive()); + } conversion.setSourcePosition(expr); result = record(conversion); diff --git a/spock-core/src/main/java/org/spockframework/util/ReflectionUtil.java b/spock-core/src/main/java/org/spockframework/util/ReflectionUtil.java index ec26a9418e..ea0a2cce81 100644 --- a/spock-core/src/main/java/org/spockframework/util/ReflectionUtil.java +++ b/spock-core/src/main/java/org/spockframework/util/ReflectionUtil.java @@ -153,6 +153,24 @@ public static Method getDeclaredMethodBySignature(Class clazz, String name, C } } + @Nullable + public static Constructor getConstructorBySignature(Class clazz, Class... parameterTypes) { + try { + return clazz.getConstructor(parameterTypes); + } catch (NoSuchMethodException e) { + return null; + } + } + + @Nullable + public static Constructor getDeclaredConstructorBySignature(Class clazz, Class... parameterTypes) { + try { + return clazz.getDeclaredConstructor(parameterTypes); + } catch (NoSuchMethodException e) { + return null; + } + } + /** * Returns the class file for the given class (which has been verified to exist in the returned location), * or null if the class file could not be found (e.g. because it is contained in a Jar). diff --git a/spock-specs/src/test-groovy-ge-4.0/groovy/org/spockframework/smoke/condition/ConditionG4Spec.groovy b/spock-specs/src/test-groovy-ge-4.0/groovy/org/spockframework/smoke/condition/ConditionG4Spec.groovy new file mode 100644 index 0000000000..1e9ab3f267 --- /dev/null +++ b/spock-specs/src/test-groovy-ge-4.0/groovy/org/spockframework/smoke/condition/ConditionG4Spec.groovy @@ -0,0 +1,17 @@ +package org.spockframework.smoke.condition + +import spock.lang.Issue +import spock.lang.Specification + +class ConditionG4Spec extends Specification { + + @Issue("https://github.com/spockframework/spock/issues/1956") + def "test range"() { + expect: + (0..5) == [0, 1, 2, 3, 4, 5] + + (0<..5) == [1, 2, 3, 4, 5] + (0..<5) == [0, 1, 2, 3, 4] + (0<..<5) == [1, 2, 3, 4] + } +}