Skip to content

Commit

Permalink
Introduce @DoNotIntercept annotation (fixes #103)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan Schäfer committed Sep 11, 2015
1 parent 80f3624 commit 49f723f
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 11 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# v0.8.2

## New Features

* Introduced the annotation `@DoNotIntercept`, to completely circumvent the JGiven interception mechanism of step methods. [#103](https://github.com/TNG/JGiven/issues/103)

# v0.8.1

## New Features
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.tngtech.jgiven.annotation;

import java.lang.annotation.*;

/**
* Methods of stages classes annotated with this annotation will not be intercepted by JGiven.
* <p>
* This is useful for technical helper methods that have to be called even if a previous
* step method has failed. Normally, JGiven will skip all step methods following a failed step,
* including methods with the {@link com.tngtech.jgiven.annotation.Hidden} annotation.
* <p>
* Note that methods annotated with this annotation will not appear in the report.
* <p>
* You should write technical helper methods in camelCase so that the name already indicates that
* the method does not appear in the report.
* <p>
* @see com.tngtech.jgiven.annotation.Hidden
* @since 0.8.2
*/
@Documented
@Retention( RetentionPolicy.RUNTIME )
@Target( ElementType.METHOD )
public @interface DoNotIntercept {

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package com.tngtech.jgiven.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.*;

/**
* Annotates elements that should be hidden in reports.
Expand All @@ -14,6 +10,8 @@
* <p>
* You should write technical helper methods in camelCase so that the name already indicates that
* the method does not appear in the report.
*
* @see com.tngtech.jgiven.annotation.DoNotIntercept
*/
@Documented
@Retention( RetentionPolicy.RUNTIME )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ public enum InvocationMode {
NORMAL,
FAILED,
SKIPPED,
PENDING;
PENDING,
DO_NOT_INTERCEPT;

public StepStatus toStepStatus() {
switch( this ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tngtech.jgiven.annotation.DoNotIntercept;
import com.tngtech.jgiven.annotation.NotImplementedYet;
import com.tngtech.jgiven.annotation.Pending;

Expand Down Expand Up @@ -45,12 +46,17 @@ public final Object doIntercept( final Object receiver, Method method,
long started = System.nanoTime();
InvocationMode mode = getInvocationMode( receiver, method );

if( mode == DO_NOT_INTERCEPT ) {
return invoker.proceed();
}

boolean handleMethod = methodHandlingEnabled && stackDepth.get() == 0 && !method.getDeclaringClass().equals( Object.class );

if( handleMethod ) {
scenarioMethodHandler.handleMethod( receiver, method, parameters, mode );
}

if( mode == SKIPPED || mode == PENDING) {
if( mode == SKIPPED || mode == PENDING ) {
return returnReceiverOrNull( receiver, method );
}

Expand Down Expand Up @@ -95,8 +101,8 @@ protected Object returnReceiverOrNull( Object receiver, Method method ) {
}

protected InvocationMode getInvocationMode( Object receiver, Method method ) {
if( method.getDeclaringClass() == Object.class ) {
return NORMAL;
if( method.getDeclaringClass() == Object.class || method.isAnnotationPresent( DoNotIntercept.class ) ) {
return DO_NOT_INTERCEPT;
}

if( !methodExecutionEnabled ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,16 @@ public void BeforeStage_methods_may_not_have_parameters() {
stage.something();
}

@Test
public void DoNotIntercept_methods_are_executed_even_if_previous_steps_fail() {
ScenarioExecutor executor = new StandaloneScenarioExecutor();
DoNotInterceptClass stage = executor.addStage( DoNotInterceptClass.class );
executor.startScenario( "Test" );
stage.a_failing_step();
int i = stage.returnFive();
assertThat( i ).isEqualTo( 5 );
}

static class TestClass {
@ScenarioStage
TestStep step;
Expand Down Expand Up @@ -219,4 +229,15 @@ public NotImplementedYetTestStepClass something_not_implemented_yet() {
}
}

static class DoNotInterceptClass {
public void a_failing_step() {
assertThat( true ).isFalse();
}

@DoNotIntercept
public int returnFive() {
return 5;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.tngtech.jgiven.GivenTestStep;
import com.tngtech.jgiven.ThenTestStep;
import com.tngtech.jgiven.WhenTestStep;
import com.tngtech.jgiven.annotation.DoNotIntercept;
import com.tngtech.jgiven.annotation.IsTag;
import com.tngtech.jgiven.base.ScenarioTestBase;

Expand Down Expand Up @@ -258,8 +259,8 @@ public void testArrayArguments( Object argument, String expected ) throws Throwa
}

@Test
public void the_Description_annotation_is_evaluated() throws Throwable {
startScenario( "Scenario with a @Description tag" );
public void characters_are_not_dropped_when_using_the_As_annotation() throws Throwable {
startScenario( "Scenario with a @As tag" );
given().a_step_with_a_description();
getScenario().finished();
StepModel step = getScenario().getScenarioCaseModel().getFirstStep();
Expand Down Expand Up @@ -308,4 +309,21 @@ public void abstract_steps_should_appear_in_the_report_model() throws Throwable
assertThat( step.words.get( 0 ).getFormattedValue() ).isEqualTo( "abstract step" );
}

@Test
public void DoNotIntercept_method_are_not_appearin_in_the_report() throws Throwable {
DoNotInterceptClass stage = addStage( DoNotInterceptClass.class );
startScenario( "Test" );
stage.do_not_intercept();
stage.normal_step();
getScenario().finished();
StepModel step = getScenario().getScenarioCaseModel().getFirstStep();
assertThat( step.words.get( 0 ).getFormattedValue() ).isEqualTo( "normal step" );
}

static class DoNotInterceptClass {
@DoNotIntercept
public void do_not_intercept() {}

public void normal_step() {}
}
}

0 comments on commit 49f723f

Please sign in to comment.