From 07b12f8eecd1ae95aaa7fa5d9ec2f0f7ad554681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonard=20Br=C3=BCnings?= Date: Mon, 14 Sep 2015 23:21:12 +0200 Subject: [PATCH] Add support for handling additional Exceptions with PendingFeature ... Add support for handling additional Exception types with the PendingFeature annotation to allow features that are failing with exceptions instead of AssertionErrors. --- .../PendingFeatureBaseInterceptor.java | 30 ++++++++++++++++ .../builtin/PendingFeatureExtension.java | 4 +-- .../builtin/PendingFeatureInterceptor.java | 19 +++++++--- .../PendingFeatureIterationInterceptor.java | 25 +++++++++---- .../main/java/spock/lang/PendingFeature.java | 9 ++++- .../PendingFeatureExtensionSpec.groovy | 36 +++++++++++++++++++ 6 files changed, 109 insertions(+), 14 deletions(-) create mode 100644 spock-core/src/main/java/org/spockframework/runtime/extension/builtin/PendingFeatureBaseInterceptor.java 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("""