Title: [1007] trunk/jbehave-core/src/java/org/jbehave/scenario/steps: JBEHAVE-117: Throws exception if duplicate candidate steps found.
Revision
1007
Author
mauro
Date
2008-11-02 04:57:28 -0600 (Sun, 02 Nov 2008)

Log Message

JBEHAVE-117:  Throws exception if duplicate candidate steps found.

Modified Paths

Diff

Modified: trunk/jbehave-core/src/behaviour/org/jbehave/scenario/steps/StepsBehaviour.java (1006 => 1007)

--- trunk/jbehave-core/src/behaviour/org/jbehave/scenario/steps/StepsBehaviour.java	2008-11-02 10:18:47 UTC (rev 1006)
+++ trunk/jbehave-core/src/behaviour/org/jbehave/scenario/steps/StepsBehaviour.java	2008-11-02 10:57:28 UTC (rev 1007)
@@ -6,6 +6,7 @@
 import java.util.List;
 
 import org.jbehave.scenario.annotations.AfterScenario;
+import org.jbehave.scenario.steps.Steps.DuplicateCandidateStepFoundException;
 import org.junit.Test;
 
 public class StepsBehaviour {
@@ -54,7 +55,7 @@
     	ensureThat(steps.afterSuccess);
     	
     	executableSteps.get(2).doNotPerform();
-    	ensureThat(steps.afterUnsuccess);
+    	ensureThat(steps.afterFailure);
     }
     
     @Test
@@ -70,9 +71,20 @@
 		
 		
 		executableSteps.get(2).perform();
-		ensureThat(!steps.afterUnsuccess); // @AfterScenario(uponOutcome=FAILURE) is run after unsuccessful scenarios
+		ensureThat(!steps.afterFailure); // @AfterScenario(uponOutcome=FAILURE) is run after unsuccessful scenarios
 	
     }
+
+    @Test(expected=DuplicateCandidateStepFoundException.class)
+    public void shouldFailIfDuplicateStepsAreEncountered() {
+        DuplicateSteps steps = new DuplicateSteps();
+        CandidateStep[] candidateSteps = steps.getSteps();
+
+        ensureThat(candidateSteps.length, equalTo(2));
+        candidateSteps[0].createFrom("Given a given").perform();
+
+    }
+
     
     public static class MySteps extends Steps {
         
@@ -83,14 +95,14 @@
         private boolean before;
         private boolean afterAny;
         private boolean afterSuccess;
-        private boolean afterUnsuccess;
+        private boolean afterFailure;
         
         @org.jbehave.scenario.annotations.Given("a given")
         @org.jbehave.scenario.annotations.Aliases(values={"a given alias", "another given alias"})
         public void given() {
             givens++;
         }
-        
+
         @org.jbehave.scenario.annotations.When("a when")
         @org.jbehave.scenario.annotations.Aliases(values={"a when alias", "another when alias"})
         public void when() {
@@ -120,9 +132,21 @@
         
         @org.jbehave.scenario.annotations.AfterScenario(uponOutcome=AfterScenario.Outcome.FAILURE)
         public void afterUnsuccessfulScenarios() {
-        	afterUnsuccess = true;
+        	afterFailure = true;
         }
         
         
     }
+    
+    public static class DuplicateSteps extends Steps {
+        
+        @org.jbehave.scenario.annotations.Given("a given")
+        public void given() {
+        }
+
+        @org.jbehave.scenario.annotations.Given("a given")
+        public void duplicateGiven() {
+        }
+                
+    }
 }

Modified: trunk/jbehave-core/src/java/org/jbehave/scenario/steps/CandidateStep.java (1006 => 1007)

--- trunk/jbehave-core/src/java/org/jbehave/scenario/steps/CandidateStep.java	2008-11-02 10:18:47 UTC (rev 1006)
+++ trunk/jbehave-core/src/java/org/jbehave/scenario/steps/CandidateStep.java	2008-11-02 10:57:28 UTC (rev 1007)
@@ -17,6 +17,7 @@
  */
 public class CandidateStep {
 
+	private final String stepAsString;
     private final Method method;
     private final CandidateSteps steps;
     private final StepMonitor stepMonitor;
@@ -24,14 +25,15 @@
     private final String[] startingWords;
     private final Pattern pattern;
 
-    public CandidateStep(String matchThis, Method method, CandidateSteps steps, StepPatternBuilder patterBuilder,
+    public CandidateStep(String stepAsString, Method method, CandidateSteps steps, StepPatternBuilder patterBuilder,
             StepMonitor stepMonitor, ParameterConverters parameterConverters, String... startingWords) {
+        this.stepAsString = stepAsString;
         this.method = method;
         this.steps = steps;
         this.stepMonitor = stepMonitor;
         this.parameterConverters = parameterConverters;
         this.startingWords = startingWords;
-        this.pattern = patterBuilder.buildPattern(matchThis);
+        this.pattern = patterBuilder.buildPattern(stepAsString);
     }
 
     public boolean matches(String step) {
@@ -103,9 +105,17 @@
         };
     }
     
+    public String getStepAsString(){
+    	return stepAsString;
+    }
+
+    public Pattern getPattern(){
+    	return pattern;
+    }
+    
     @Override
     public String toString() {
-    	return pattern.pattern();
+    	return stepAsString;
     }
 
 }

Modified: trunk/jbehave-core/src/java/org/jbehave/scenario/steps/Steps.java (1006 => 1007)

--- trunk/jbehave-core/src/java/org/jbehave/scenario/steps/Steps.java	2008-11-02 10:18:47 UTC (rev 1006)
+++ trunk/jbehave-core/src/java/org/jbehave/scenario/steps/Steps.java	2008-11-02 10:57:28 UTC (rev 1007)
@@ -63,81 +63,100 @@
  * </p>
  */
 public class Steps implements CandidateSteps {
-	
-    private final StepsConfiguration configuration;
 
-    /**
-     * Creates Steps with default configuration
-     */
-    public Steps() {
-        this(new StepsConfiguration());
-    }
+	private final StepsConfiguration configuration;
 
-    /**
-     * Creates Steps with all default configuration except for custom starting
-     * keywords
-     * 
-     * @param startingWords the words with which we expect steps in the
-     *            scenarios to start
-     */
-    public Steps(String... startingWords) {
-        this(new StepsConfiguration(startingWords));
-    }
-    
-    /**
-     * Creates Steps with all default dependencies except for custom parameter converters.
-     * 
-     * @param converters a set of converters which can change strings into other objects to pass into executable steps
-     */
-    public Steps(ParameterConverters converters) {
-    	this(new StepsConfiguration(converters));
-    }
+	/**
+	 * Creates Steps with default configuration
+	 */
+	public Steps() {
+		this(new StepsConfiguration());
+	}
 
-    /**
-     * Creates Steps with all custom dependencies
-     * 
-     * @param configuration the StepsConfiguration
-     */
-    public Steps(StepsConfiguration configuration) {
-        this.configuration = configuration;
-    }
+	/**
+	 * Creates Steps with all default configuration except for custom starting
+	 * keywords
+	 * 
+	 * @param startingWords
+	 *            the words with which we expect steps in the scenarios to start
+	 */
+	public Steps(String... startingWords) {
+		this(new StepsConfiguration(startingWords));
+	}
 
-    public CandidateStep[] getSteps() {
-        return getSteps(this.getClass());
-    }
+	/**
+	 * Creates Steps with all default dependencies except for custom parameter
+	 * converters.
+	 * 
+	 * @param converters
+	 *            a set of converters which can change strings into other
+	 *            objects to pass into executable steps
+	 */
+	public Steps(ParameterConverters converters) {
+		this(new StepsConfiguration(converters));
+	}
 
-    public CandidateStep[] getSteps(Class<?> stepsClass) {
-        List<CandidateStep> steps = new ArrayList<CandidateStep>();
-        for (Method method : stepsClass.getMethods()) {
-            if (method.isAnnotationPresent(Given.class)) {
-                createCandidateStep(steps, method, method.getAnnotation(Given.class).value());
-                createCandidateStepsFromAliases(steps, method);
-            }
-            if (method.isAnnotationPresent(When.class)) {
-                createCandidateStep(steps, method, method.getAnnotation(When.class).value());
-                createCandidateStepsFromAliases(steps, method);
-            }
-            if (method.isAnnotationPresent(Then.class)) {
-                createCandidateStep(steps, method, method.getAnnotation(Then.class).value());
-                createCandidateStepsFromAliases(steps, method);
-            }
-        }
-        return steps.toArray(new CandidateStep[steps.size()]);
-    }
+	/**
+	 * Creates Steps with all custom dependencies
+	 * 
+	 * @param configuration
+	 *            the StepsConfiguration
+	 */
+	public Steps(StepsConfiguration configuration) {
+		this.configuration = configuration;
+	}
 
-	void createCandidateStep(List<CandidateStep> steps, Method method, String stepAsString) {
-        steps.add(new CandidateStep(stepAsString, method, this, configuration.getPatternBuilder(), configuration
-                .getMonitor(), configuration.getParameterConverters(), configuration.getStartingWords()));
-    }
+	public CandidateStep[] getSteps() {
+		return getSteps(this.getClass());
+	}
 
-    private void createCandidateStepsFromAliases(List<CandidateStep> steps,
+	public CandidateStep[] getSteps(Class<?> stepsClass) {
+		List<CandidateStep> steps = new ArrayList<CandidateStep>();
+		for (Method method : stepsClass.getMethods()) {
+			if (method.isAnnotationPresent(Given.class)) {
+				String value = method.getAnnotation(Given.class).value();
+				createCandidateStep(steps, method, value);
+				createCandidateStepsFromAliases(steps, method);
+			}
+			if (method.isAnnotationPresent(When.class)) {
+				String value = method.getAnnotation(When.class).value();
+				createCandidateStep(steps, method, value);
+				createCandidateStepsFromAliases(steps, method);
+			}
+			if (method.isAnnotationPresent(Then.class)) {
+				String value = method.getAnnotation(Then.class).value();
+				createCandidateStep(steps, method, value);
+				createCandidateStepsFromAliases(steps, method);
+			}
+		}
+		return steps.toArray(new CandidateStep[steps.size()]);
+	}
+
+	void createCandidateStep(List<CandidateStep> steps, Method method,
+			String stepAsString) {
+		checkForDuplicateCandidateSteps(steps, stepAsString);
+		steps.add(new CandidateStep(stepAsString, method, this, configuration
+				.getPatternBuilder(), configuration.getMonitor(), configuration
+				.getParameterConverters(), configuration.getStartingWords()));
+	}
+
+	private void checkForDuplicateCandidateSteps(List<CandidateStep> steps,
+			String stepAsString) {
+		for (CandidateStep step : steps) {
+			if (step.getStepAsString().equals(stepAsString)) {
+				throw new DuplicateCandidateStepFoundException(stepAsString);
+			}
+		}
+	}
+
+	private void createCandidateStepsFromAliases(List<CandidateStep> steps,
 			Method method) {
-    	if ( method.isAnnotationPresent(Aliases.class) ){
-    		String[] aliases = method.getAnnotation(Aliases.class).values();
-    		for ( String alias : aliases ){
-        		createCandidateStep(steps, method, alias);    			
-    		}
-    	}
+		if (method.isAnnotationPresent(Aliases.class)) {
+			String[] aliases = method.getAnnotation(Aliases.class).values();
+			for (String alias : aliases) {
+				createCandidateStep(steps, method, alias);
+			}
+		}
 	}
 
 	public List<Step> runBeforeScenario() {
@@ -146,16 +165,21 @@
 
 	public List<Step> runAfterScenario() {
 		List<Step> steps = new ArrayList<Step>();
-		steps.addAll(stepsHavingOutcome(AfterScenario.class, ANY, new OkayToRun(), new OkayToRun()));
-		steps.addAll(stepsHavingOutcome(AfterScenario.class, SUCCESS, new OkayToRun(), new DoNotRun()));
-		steps.addAll(stepsHavingOutcome(AfterScenario.class, FAILURE, new DoNotRun(), new OkayToRun()));
+		steps.addAll(stepsHavingOutcome(AfterScenario.class, ANY,
+				new OkayToRun(), new OkayToRun()));
+		steps.addAll(stepsHavingOutcome(AfterScenario.class, SUCCESS,
+				new OkayToRun(), new DoNotRun()));
+		steps.addAll(stepsHavingOutcome(AfterScenario.class, FAILURE,
+				new DoNotRun(), new OkayToRun()));
 		return steps;
 	}
 
-	private List<Step> stepsHaving(final Class<? extends Annotation> annotationClass, final StepPart forScenarios) {
+	private List<Step> stepsHaving(
+			final Class<? extends Annotation> annotationClass,
+			final StepPart forScenarios) {
 		List<Step> steps = new ArrayList<Step>();
-        for (final Method method : this.getClass().getMethods()) {
-			if (method.isAnnotationPresent(annotationClass)) {				
+		for (final Method method : this.getClass().getMethods()) {
+			if (method.isAnnotationPresent(annotationClass)) {
 				steps.add(new Step() {
 					public StepResult doNotPerform() {
 						return forScenarios.run(annotationClass, method);
@@ -164,66 +188,86 @@
 					public StepResult perform() {
 						return forScenarios.run(annotationClass, method);
 					}
-					
+
 				});
 			}
-        }
-        return steps;
+		}
+		return steps;
 	}
-	
-	
-	private List<Step> stepsHavingOutcome(final Class<? extends AfterScenario> annotationClass, final Outcome outcome, final StepPart forSuccessfulScenarios, final StepPart forUnsuccessfulScenarios) {
+
+	private List<Step> stepsHavingOutcome(
+			final Class<? extends AfterScenario> annotationClass,
+			final Outcome outcome, final StepPart forSuccessfulScenarios,
+			final StepPart forUnsuccessfulScenarios) {
 		List<Step> steps = new ArrayList<Step>();
-        for (final Method method : this.getClass().getMethods()) {
-			if (method.isAnnotationPresent(annotationClass) ) {				
-				AfterScenario annotation = method.getAnnotation(annotationClass);
-				if ( outcome.equals(annotation.uponOutcome()) ){
+		for (final Method method : this.getClass().getMethods()) {
+			if (method.isAnnotationPresent(annotationClass)) {
+				AfterScenario annotation = method
+						.getAnnotation(annotationClass);
+				if (outcome.equals(annotation.uponOutcome())) {
 					steps.add(new Step() {
 
 						public StepResult doNotPerform() {
-							return forUnsuccessfulScenarios.run(annotationClass, method);
+							return forUnsuccessfulScenarios.run(
+									annotationClass, method);
 						}
 
 						public StepResult perform() {
-							return forSuccessfulScenarios.run(annotationClass, method);
+							return forSuccessfulScenarios.run(annotationClass,
+									method);
 						}
-						
-					});					
+
+					});
 				}
 			}
-        }
-        return steps;
+		}
+		return steps;
 	}
-	
+
 	private class OkayToRun implements StepPart {
-		public StepResult run(final Class<? extends Annotation> annotation, Method method) {
+		public StepResult run(final Class<? extends Annotation> annotation,
+				Method method) {
 			try {
 				method.invoke(Steps.this);
 			} catch (InvocationTargetException e) {
-				if (e.getCause() != null) { throw new BeforeOrAfterScenarioException(annotation, method, e.getCause()); }
+				if (e.getCause() != null) {
+					throw new BeforeOrAfterScenarioException(annotation,
+							method, e.getCause());
+				}
 			} catch (Throwable t) {
 				throw new RuntimeException(t);
 			}
 			return new SilentStepResult();
 		}
 	}
-	
+
 	private class DoNotRun implements StepPart {
-		public StepResult run(Class<? extends Annotation> annotation, Method method) {
+		public StepResult run(Class<? extends Annotation> annotation,
+				Method method) {
 			return new SilentStepResult();
 		}
 	}
-	
+
 	private interface StepPart {
 		StepResult run(Class<? extends Annotation> annotation, Method method);
 	}
-	
-    public class SilentStepResult extends StepResult {
-    	public SilentStepResult() {
+
+	public class SilentStepResult extends StepResult {
+		public SilentStepResult() {
 			super("");
 		}
-    	
+
 		@Override
-		public void describeTo(ScenarioReporter reporter) {}
+		public void describeTo(ScenarioReporter reporter) {
+		}
 	}
+
+	@SuppressWarnings("serial")
+	public static class DuplicateCandidateStepFoundException extends RuntimeException {
+
+		public DuplicateCandidateStepFoundException(String message) {
+			super(message);
+		}
+
+	}
 }


To unsubscribe from this list please visit:

http://xircles.codehaus.org/manage_email

Reply via email to