diff --git a/spock-core/src/main/java/org/spockframework/runtime/extension/builtin/PendingFeatureBaseInterceptor.java b/spock-core/src/main/java/org/spockframework/runtime/extension/builtin/PendingFeatureBaseInterceptor.java new file mode 100644 index 0000000000..8d9f532553 --- /dev/null +++ b/spock-core/src/main/java/org/spockframework/runtime/extension/builtin/PendingFeatureBaseInterceptor.java @@ -0,0 +1,30 @@ +package org.spockframework.runtime.extension.builtin; + +import org.junit.AssumptionViolatedException; + +/** + * @author Leonard Brünings + */ +public class PendingFeatureBaseInterceptor { + protected final Class[] expectedExceptions; + + public PendingFeatureBaseInterceptor(Class[] expectedExceptions) { + this.expectedExceptions = expectedExceptions; + } + + protected boolean isExpected(Throwable e) { + for (Class exception : expectedExceptions) { + if(exception.isInstance(e)) { + return true; + } + } + return false; + } + protected AssertionError featurePassedUnexpectedly() { + return new AssertionError("Feature is marked with @PendingFeature but passes unexpectedly"); + } + + protected AssumptionViolatedException assumptionViolation() { + return new AssumptionViolatedException("Feature not yet implemented correctly."); + } +} diff --git a/spock-core/src/main/java/org/spockframework/runtime/extension/builtin/PendingFeatureExtension.java b/spock-core/src/main/java/org/spockframework/runtime/extension/builtin/PendingFeatureExtension.java index 19be34a84d..047fc0de96 100644 --- a/spock-core/src/main/java/org/spockframework/runtime/extension/builtin/PendingFeatureExtension.java +++ b/spock-core/src/main/java/org/spockframework/runtime/extension/builtin/PendingFeatureExtension.java @@ -11,9 +11,9 @@ public class PendingFeatureExtension extends AbstractAnnotationDrivenExtension

[] handledExceptions) { + super(handledExceptions); + } + @Override public void intercept(IMethodInvocation invocation) throws Throwable { try { invocation.proceed(); } catch (AssertionError e) { - throw new AssumptionViolatedException("Feature not yet implemented correctly."); + throw assumptionViolation(); + } catch (Throwable e) { + if (isExpected(e)) { + throw assumptionViolation(); + } else { + throw e; + } } - throw new AssertionError("Feature is marked with @PendingFeature but passes unexpectedly"); + throw featurePassedUnexpectedly(); } + } diff --git a/spock-core/src/main/java/org/spockframework/runtime/extension/builtin/PendingFeatureIterationInterceptor.java b/spock-core/src/main/java/org/spockframework/runtime/extension/builtin/PendingFeatureIterationInterceptor.java index 45ef89177b..1a67395b71 100644 --- a/spock-core/src/main/java/org/spockframework/runtime/extension/builtin/PendingFeatureIterationInterceptor.java +++ b/spock-core/src/main/java/org/spockframework/runtime/extension/builtin/PendingFeatureIterationInterceptor.java @@ -1,6 +1,5 @@ package org.spockframework.runtime.extension.builtin; -import org.junit.AssumptionViolatedException; import org.spockframework.runtime.extension.IMethodInterceptor; import org.spockframework.runtime.extension.IMethodInvocation; @@ -9,24 +8,30 @@ /** * @author Leonard Brünings */ -class PendingFeatureIterationInterceptor implements IMethodInterceptor { +class PendingFeatureIterationInterceptor extends PendingFeatureBaseInterceptor implements IMethodInterceptor { + + public PendingFeatureIterationInterceptor(Class[] expectedExceptions) { + super(expectedExceptions); + } + @Override public void intercept(IMethodInvocation invocation) throws Throwable { AtomicBoolean pass = new AtomicBoolean(false); - invocation.getFeature().getFeatureMethod().addInterceptor(new InnerIterationInterceptor(pass)); + invocation.getFeature().getFeatureMethod().addInterceptor(new InnerIterationInterceptor(pass, expectedExceptions)); invocation.proceed(); if (pass.get()) { - throw new AssumptionViolatedException("Feature not yet implemented correctly."); + throw assumptionViolation(); } else { - throw new AssertionError("Feature is marked with @PendingFeature but passes unexpectedly"); + throw featurePassedUnexpectedly(); } } - private static class InnerIterationInterceptor implements IMethodInterceptor { + private static class InnerIterationInterceptor extends PendingFeatureBaseInterceptor implements IMethodInterceptor { private final AtomicBoolean pass; - public InnerIterationInterceptor(AtomicBoolean pass) { + public InnerIterationInterceptor(AtomicBoolean pass, Class[] expectedExceptions) { + super(expectedExceptions); this.pass = pass; } @@ -36,6 +41,12 @@ public void intercept(IMethodInvocation invocation) throws Throwable { invocation.proceed(); } catch (AssertionError e) { pass.set(true); + } catch (Throwable e) { + if (isExpected(e)) { + pass.set(true); + } else { + throw e; + } } } } diff --git a/spock-core/src/main/java/spock/lang/PendingFeature.java b/spock-core/src/main/java/spock/lang/PendingFeature.java index 1ac5e54df8..d77280efad 100644 --- a/spock-core/src/main/java/spock/lang/PendingFeature.java +++ b/spock-core/src/main/java/spock/lang/PendingFeature.java @@ -2,7 +2,6 @@ import org.spockframework.runtime.extension.ExtensionAnnotation; -import org.spockframework.runtime.extension.builtin.IgnoreExtension; import org.spockframework.runtime.extension.builtin.PendingFeatureExtension; import org.spockframework.util.Beta; @@ -40,4 +39,12 @@ @Target({ElementType.METHOD}) @ExtensionAnnotation(PendingFeatureExtension.class) public @interface PendingFeature { + /** + * Configures which types of Exceptions are expected in the pending feature. + * + * Subclasses are included if their parent class is listed. + * + * @return array of Exception classes to ignore. + */ + Class[] exceptions() default {Exception.class}; } diff --git a/spock-specs/src/test/groovy/org/spockframework/smoke/extension/PendingFeatureExtensionSpec.groovy b/spock-specs/src/test/groovy/org/spockframework/smoke/extension/PendingFeatureExtensionSpec.groovy index 110ceb9177..29c24ee701 100644 --- a/spock-specs/src/test/groovy/org/spockframework/smoke/extension/PendingFeatureExtensionSpec.groovy +++ b/spock-specs/src/test/groovy/org/spockframework/smoke/extension/PendingFeatureExtensionSpec.groovy @@ -23,6 +23,42 @@ class Foo extends Specification { result.ignoreCount == 0 } + def "@PendingFeature marks feature that fails with exception as skipped"() { + when: + def result = runner.runWithImports(""" + +class Foo extends Specification { + @PendingFeature + def bar() { + expect: + throw new Exception() + } +} + """) + + then: + noExceptionThrown() + result.runCount == 1 + result.failureCount == 0 + result.ignoreCount == 0 + } + def "@PendingFeature rethrows non handled exceptions"() { + when: + def result = runner.runWithImports(""" + +class Foo extends Specification { + @PendingFeature(exceptions=[IndexOutOfBoundsException]) + def bar() { + expect: + throw new IllegalArgumentException() + } +} + """) + + then: + thrown(IllegalArgumentException) + } + def "@PendingFeature marks passing feature as failed"() { when: runner.runWithImports("""