-
Notifications
You must be signed in to change notification settings - Fork 469
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #87 from leonard84/pending-feature
Add @PendingFeature
- Loading branch information
Showing
6 changed files
with
328 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
...e/src/main/java/org/spockframework/runtime/extension/builtin/PendingFeatureExtension.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package org.spockframework.runtime.extension.builtin; | ||
|
||
import org.spockframework.runtime.extension.AbstractAnnotationDrivenExtension; | ||
import org.spockframework.runtime.model.FeatureInfo; | ||
import spock.lang.PendingFeature; | ||
|
||
/** | ||
* @author Leonard Brünings | ||
*/ | ||
public class PendingFeatureExtension extends AbstractAnnotationDrivenExtension<PendingFeature> { | ||
@Override | ||
public void visitFeatureAnnotation(PendingFeature annotation, FeatureInfo feature) { | ||
if (feature.isParameterized()) { | ||
feature.addInterceptor(new PendingFeatureIterationInterceptor()); | ||
} else { | ||
feature.getFeatureMethod().addInterceptor(new PendingFeatureInterceptor()); | ||
} | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
...src/main/java/org/spockframework/runtime/extension/builtin/PendingFeatureInterceptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.spockframework.runtime.extension.builtin; | ||
|
||
import org.junit.AssumptionViolatedException; | ||
import org.spockframework.runtime.extension.IMethodInterceptor; | ||
import org.spockframework.runtime.extension.IMethodInvocation; | ||
|
||
/** | ||
* @author Leonard Brünings | ||
*/ | ||
class PendingFeatureInterceptor implements IMethodInterceptor { | ||
@Override | ||
public void intercept(IMethodInvocation invocation) throws Throwable { | ||
try { | ||
invocation.proceed(); | ||
} catch (AssertionError e) { | ||
throw new AssumptionViolatedException("Feature not yet implemented correctly."); | ||
} | ||
throw new AssertionError("Feature is marked with @PendingFeature but passes unexpectedly"); | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
...java/org/spockframework/runtime/extension/builtin/PendingFeatureIterationInterceptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package org.spockframework.runtime.extension.builtin; | ||
|
||
import org.junit.AssumptionViolatedException; | ||
import org.spockframework.runtime.extension.IMethodInterceptor; | ||
import org.spockframework.runtime.extension.IMethodInvocation; | ||
|
||
import java.util.concurrent.atomic.AtomicBoolean; | ||
|
||
/** | ||
* @author Leonard Brünings | ||
*/ | ||
class PendingFeatureIterationInterceptor implements IMethodInterceptor { | ||
@Override | ||
public void intercept(IMethodInvocation invocation) throws Throwable { | ||
|
||
AtomicBoolean pass = new AtomicBoolean(false); | ||
invocation.getFeature().getFeatureMethod().addInterceptor(new InnerIterationInterceptor(pass)); | ||
invocation.proceed(); | ||
if (pass.get()) { | ||
throw new AssumptionViolatedException("Feature not yet implemented correctly."); | ||
} else { | ||
throw new AssertionError("Feature is marked with @PendingFeature but passes unexpectedly"); | ||
} | ||
} | ||
|
||
private static class InnerIterationInterceptor implements IMethodInterceptor { | ||
private final AtomicBoolean pass; | ||
|
||
public InnerIterationInterceptor(AtomicBoolean pass) { | ||
this.pass = pass; | ||
} | ||
|
||
@Override | ||
public void intercept(IMethodInvocation invocation) throws Throwable { | ||
try { | ||
invocation.proceed(); | ||
} catch (AssertionError e) { | ||
pass.set(true); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package spock.lang; | ||
|
||
|
||
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; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* Indicates that the feature is not fully implemented yet and should not be reported as error. | ||
* <p> | ||
* The use case is to annotate tests that can not yet run but should already be committed. | ||
* The main difference to {@link Ignore} is that the test are executed, but test failures are ignored. | ||
* If the test passes without an error, then it will be reported as failure since the {@link PendingFeature} | ||
* annotation should be removed. This way the tests will become part of the normal tests | ||
* instead of being ignored forever. | ||
* </p> | ||
* <p> | ||
* Groovy has the {@link groovy.transform.NotYetImplemented} annotation which is similar but behaves a differently. | ||
* <ul> | ||
* <li>it will mark failing tests as passed</li> | ||
* <li>if at least one iteration of a data-driven test passes it will be reported as error</li> | ||
* </ul> | ||
* {@link PendingFeature}: | ||
* <ul> | ||
* <li>it will mark failing tests as skipped</li> | ||
* <li>if at least one iteration of a data-driven test fails it will be reported as skipped</li> | ||
* <li>if every iteration of a data-driven test passes it will be reported as error</li> | ||
* </ul> | ||
*</p> | ||
* @author Leonard Brünings | ||
*/ | ||
@Beta | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target({ElementType.METHOD}) | ||
@ExtensionAnnotation(PendingFeatureExtension.class) | ||
public @interface PendingFeature { | ||
} |
175 changes: 175 additions & 0 deletions
175
...ecs/src/test/groovy/org/spockframework/smoke/extension/PendingFeatureExtensionSpec.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
package org.spockframework.smoke.extension | ||
|
||
import org.spockframework.EmbeddedSpecification | ||
|
||
class PendingFeatureExtensionSpec extends EmbeddedSpecification { | ||
|
||
def "@PendingFeature marks failing feature as skipped"() { | ||
when: | ||
def result = runner.runWithImports(""" | ||
class Foo extends Specification { | ||
@PendingFeature | ||
def bar() { | ||
expect: false | ||
} | ||
} | ||
""") | ||
|
||
then: | ||
notThrown(AssertionError) | ||
result.runCount == 1 | ||
result.failureCount == 0 | ||
result.ignoreCount == 0 | ||
} | ||
|
||
def "@PendingFeature marks passing feature as failed"() { | ||
when: | ||
runner.runWithImports(""" | ||
class Foo extends Specification { | ||
@PendingFeature | ||
def bar() { | ||
expect: true | ||
} | ||
} | ||
""") | ||
|
||
then: | ||
AssertionError e = thrown(AssertionError) | ||
e.message == "Feature is marked with @PendingFeature but passes unexpectedly" | ||
} | ||
|
||
def "@PendingFeature marks data driven feature where every iteration fails as skipped"() { | ||
when: | ||
def result = runner.runWithImports(""" | ||
class Foo extends Specification { | ||
@PendingFeature | ||
def bar() { | ||
expect: test | ||
where: | ||
test << [false, false, false] | ||
} | ||
} | ||
""") | ||
|
||
then: | ||
notThrown(AssertionError) | ||
result.runCount == 1 | ||
result.failureCount == 0 | ||
result.ignoreCount == 0 | ||
} | ||
|
||
def "@PendingFeature marks @Unroll'ed data driven feature where every iteration fails as skipped"() { | ||
when: | ||
def result = runner.runWithImports(""" | ||
class Foo extends Specification { | ||
@Unroll | ||
@PendingFeature | ||
def bar() { | ||
expect: test | ||
where: | ||
test << [false, false, false] | ||
} | ||
} | ||
""") | ||
|
||
then: | ||
notThrown(AssertionError) | ||
result.runCount == 3 | ||
result.failureCount == 0 | ||
result.ignoreCount == 0 | ||
} | ||
|
||
def "@PendingFeature marks data driven feature where at least one iteration fails as skipped"() { | ||
when: | ||
def result = runner.runWithImports(""" | ||
class Foo extends Specification { | ||
@PendingFeature | ||
def bar() { | ||
expect: test | ||
where: | ||
test << [true, false, true] | ||
} | ||
} | ||
""") | ||
|
||
then: | ||
notThrown(AssertionError) | ||
result.runCount == 1 | ||
result.failureCount == 0 | ||
result.ignoreCount == 0 | ||
} | ||
|
||
|
||
def "@PendingFeature marks @Unroll'ed data driven feature where at least one iteration fails as skipped"() { | ||
when: | ||
def result = runner.runWithImports(""" | ||
class Foo extends Specification { | ||
@Unroll | ||
@PendingFeature | ||
def bar() { | ||
expect: test | ||
where: | ||
test << [true, false, true] | ||
} | ||
} | ||
""") | ||
|
||
then: | ||
notThrown(AssertionError) | ||
result.runCount == 3 | ||
result.failureCount == 0 | ||
result.ignoreCount == 0 | ||
} | ||
|
||
def "@PendingFeature marks data driven feature where all iterations pass as failed"() { | ||
when: | ||
runner.runWithImports(""" | ||
class Foo extends Specification { | ||
@PendingFeature | ||
def bar() { | ||
expect: test | ||
where: | ||
test << [true, true, true] | ||
} | ||
} | ||
""") | ||
|
||
then: | ||
AssertionError e = thrown(AssertionError) | ||
e.message == "Feature is marked with @PendingFeature but passes unexpectedly" | ||
} | ||
|
||
|
||
def "@PendingFeature marks @Unroll'ed data driven feature where all iterations pass as failed"() { | ||
when: | ||
runner.runWithImports(""" | ||
class Foo extends Specification { | ||
@Unroll | ||
@PendingFeature | ||
def bar() { | ||
expect: test | ||
where: | ||
test << [true, true, true] | ||
} | ||
} | ||
""") | ||
|
||
then: | ||
AssertionError e = thrown(AssertionError) | ||
e.message == "Feature is marked with @PendingFeature but passes unexpectedly" | ||
} | ||
} |