Title: [881] trunk/examples: [Liz] Multiple scenarios in the same file work independently; noughtsandcrosses provides examples (but not in build yet)
Revision
881
Author
sirenian
Date
2008-07-28 14:31:08 -0500 (Mon, 28 Jul 2008)

Log Message

[Liz] Multiple scenarios in the same file work independently; noughtsandcrosses provides examples (but not in build yet)

Modified Paths

Added Paths

Diff

Added: trunk/examples/noughtsandcrosses/lib/tyburn-0.1.jar

(Binary files differ)
Property changes on: trunk/examples/noughtsandcrosses/lib/tyburn-0.1.jar ___________________________________________________________________ Name: svn:mime-type + application/octet-stream

Added: trunk/examples/noughtsandcrosses/src/behaviour/com/lunivore/noughtsandcrosses/game/GameModelBehaviour.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/behaviour/com/lunivore/noughtsandcrosses/game/GameModelBehaviour.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/behaviour/com/lunivore/noughtsandcrosses/game/GameModelBehaviour.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,79 @@
+package com.lunivore.noughtsandcrosses.game;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.jbehave.Ensure.ensureThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Test;
+
+
+
+public class GameModelBehaviour {
+
+	@Test
+	public void shouldStartEmptyAndTellObserver() {
+		GameModel game = new GameModel();
+		GameObserver observer = mock(GameObserver.class);
+		game.addObserver(observer);
+		
+		verify(observer).gameChanged(game);
+		
+		for (int row = 0; row < 3; row++) {
+			for (int column = 0; column < 3; column++) {
+				ensureThat(game.playerAt(column, row), equalTo(Player.NONE));
+			}
+		}
+	}
+	
+	@Test
+	public void shouldPlaceTokenForCurrentPlayerInTheGivenColumnAndRowStartingWithX() {
+		GameModel game = new GameModel();
+		GameObserver observer = mock(GameObserver.class);
+		game.addObserver(observer);
+		
+		game.playerActsAt(0, 1);
+		game.playerActsAt(0, 2);
+		
+		verify(observer, times(3)).gameChanged(game);
+		
+		ensureThat(game.playerAt(0, 0), equalTo(Player.NONE));
+		ensureThat(game.playerAt(0, 1), equalTo(Player.X));
+		ensureThat(game.playerAt(0, 2), equalTo(Player.O));
+	}
+	
+	@Test
+	public void shouldNotifyObserverWhenTheCurrentPlayerWins() {
+		// Given a game which X is about to win
+		GameModel game = new GameModel();
+		game.playerActsAt(0, 0);
+		game.playerActsAt(1, 0);
+		game.playerActsAt(0, 1);
+		game.playerActsAt(2, 0);
+		
+
+		MyGameObserver observer = new MyGameObserver();
+		game.addObserver(observer);
+		
+		// When X wins the game
+		game.playerActsAt(0, 2);
+		
+		// Then we should see X is the current player and the game is over
+		ensureThat(observer.game.currentPlayer(), equalTo(Player.X));
+	}
+	
+	private static class MyGameObserver implements GameObserver {
+
+		private Game game;
+
+		public void gameChanged(Game game) {
+		}
+
+		public void gameWon(Game game) {
+			this.game = game;
+		}
+		
+	}
+
+}

Added: trunk/examples/noughtsandcrosses/src/behaviour/com/lunivore/noughtsandcrosses/game/WinningScenarioBehaviour.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/behaviour/com/lunivore/noughtsandcrosses/game/WinningScenarioBehaviour.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/behaviour/com/lunivore/noughtsandcrosses/game/WinningScenarioBehaviour.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,26 @@
+package com.lunivore.noughtsandcrosses.game;
+
+import static org.jbehave.Ensure.ensureThat;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+
+public class WinningScenarioBehaviour {
+
+	@Test
+	public void shouldFindWinningGameWhenCoordsAreAllTheSamePlayer() {
+		Map<Coord, Player> game = new HashMap<Coord, Player>();
+		game.put(new Coord(0,0), Player.X);
+		game.put(new Coord(1,0), Player.X);
+		game.put(new Coord(1,1), Player.O);
+		game.put(new Coord(2,2), Player.O);
+		ensureThat(!WinningScenario.ROW1.isAchievedIn(game));
+		game.put(new Coord(2,0), Player.X);
+		ensureThat(WinningScenario.ROW1.isAchievedIn(game));
+		ensureThat(!WinningScenario.COL1.isAchievedIn(game));
+		ensureThat(!WinningScenario.NORTH_WEST.isAchievedIn(game));
+	}
+}

Added: trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/NoughtsAndCrosses.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/NoughtsAndCrosses.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/NoughtsAndCrosses.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,15 @@
+package com.lunivore.noughtsandcrosses;
+
+import com.lunivore.noughtsandcrosses.game.GameModel;
+import com.lunivore.noughtsandcrosses.view.NoughtsAndCrossesFrame;
+
+public class NoughtsAndCrosses {
+
+	public NoughtsAndCrosses() {
+		new NoughtsAndCrossesFrame(new GameModel());
+	}
+	
+	public static void main(String[] args) {
+		new NoughtsAndCrosses();
+	}
+}

Added: trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/Coord.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/Coord.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/Coord.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,29 @@
+/**
+ * 
+ */
+package com.lunivore.noughtsandcrosses.game;
+
+class Coord {
+	private final int column;
+	private final int row;
+
+	public Coord(int column, int row) {
+		this.column = column;
+		this.row = row;
+	}
+
+	@Override
+	public int hashCode() {
+		int result = 1;
+		result = 31 * result + column;
+		result = 31 * result + row;
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		final Coord other = (Coord) obj;
+		return column == other.column && row == other.row;
+	}
+
+}
\ No newline at end of file

Added: trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/Game.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/Game.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/Game.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,13 @@
+package com.lunivore.noughtsandcrosses.game;
+
+
+public interface Game {
+
+	public void addObserver(GameObserver observer);
+
+	public void playerActsAt(int row, int column);
+
+	public Player playerAt(int column, int row);
+
+	public Player currentPlayer();
+}

Added: trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/GameModel.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/GameModel.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/GameModel.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,62 @@
+package com.lunivore.noughtsandcrosses.game;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class GameModel implements Game {
+
+	private Map<Coord, Player> map = new HashMap<Coord, Player>();
+	private Player currentPlayer = Player.X;
+	private List<GameObserver> observers = new ArrayList<GameObserver>();
+
+	public void addObserver(GameObserver observer) {
+		observers.add(observer);
+		observer.gameChanged(this);
+	}
+
+	public void playerActsAt(int column, int row) {
+		map.put(new Coord(column, row), currentPlayer);
+		if (gameWon()) {
+			notifyObserversGameWon();
+		} else {
+			nextPlayer();
+			notifyObserversGameChanged();
+		}
+	}
+
+	private void notifyObserversGameWon() {
+		for (GameObserver observer : observers) {
+			observer.gameWon(this);
+		}
+	}
+
+	private boolean gameWon() {
+		for (WinningScenario scenario : WinningScenario.values()) {
+			if(scenario.isAchievedIn(map)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	private void notifyObserversGameChanged() {
+		for (GameObserver observer : observers) {
+			observer.gameChanged(this);
+		}
+	}
+
+	private void nextPlayer() {
+		currentPlayer = currentPlayer == Player.X ? Player.O : Player.X;
+	}
+
+	public Player playerAt(int column, int row) {
+		Player player = map.get(new Coord(column, row));
+		return player == null ? Player.NONE : player;
+	}
+
+	public Player currentPlayer() {
+		return currentPlayer;
+	}
+}

Added: trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/GameObserver.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/GameObserver.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/GameObserver.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,8 @@
+package com.lunivore.noughtsandcrosses.game;
+
+public interface GameObserver {
+
+	void gameChanged(Game game);
+
+	void gameWon(Game game);
+}

Added: trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/Player.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/Player.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/Player.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,16 @@
+package com.lunivore.noughtsandcrosses.game;
+
+public enum Player {
+
+	O("O"), X("X"), NONE("");
+	
+	private final String rendered;
+
+	private Player(String rendered) {
+		this.rendered = rendered;
+	}
+
+	public String asString() {
+		return rendered;
+	}
+}

Added: trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/WinningScenario.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/WinningScenario.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/game/WinningScenario.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,36 @@
+package com.lunivore.noughtsandcrosses.game;
+
+import java.util.Map;
+
+
+public enum WinningScenario {
+	ROW1(new Coord(0, 0), new Coord(1, 0), new Coord(2, 0)),
+	ROW2(new Coord(0, 1), new Coord(1, 1), new Coord(2, 1)),
+	ROW3(new Coord(0, 2), new Coord(1, 2), new Coord(2, 2)),
+	COL1(new Coord(0, 0), new Coord(0, 1), new Coord(0, 2)),
+	COL2(new Coord(1, 0), new Coord(1, 1), new Coord(1, 2)),
+	COL3(new Coord(2, 0), new Coord(2, 1), new Coord(2, 2)),
+	NORTH_WEST(new Coord(0, 0), new Coord(1, 1), new Coord(2, 2)),
+	NORTH_EAST(new Coord(2, 0), new Coord(1, 1), new Coord(0, 2));
+
+	private final Coord[] coords;
+
+	private WinningScenario(Coord... coords) {
+		this.coords = coords;
+	}
+	
+	public boolean isAchievedIn(Map<Coord, Player> map) {
+		Player candidate = null;
+		for (Coord coord : coords) {
+			if (map.get(coord) == null) {
+				return false;
+			} else if (candidate == null){
+				candidate = map.get(coord);
+			} else if (candidate != map.get(coord)){
+				return false;
+			}
+		}
+		return true;
+	}
+
+}

Added: trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/view/ComponentNames.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/view/ComponentNames.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/view/ComponentNames.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,9 @@
+package com.lunivore.noughtsandcrosses.view;
+
+public class ComponentNames {
+
+	public static final String NOUGHTSANDCROSSES = "noughtsandcrosses";
+	public static final String MESSAGE = "message";
+	public static String GRID = "grid";
+
+}

Added: trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/view/GridPanel.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/view/GridPanel.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/view/GridPanel.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,81 @@
+package com.lunivore.noughtsandcrosses.view;
+
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JPanel;
+
+import com.lunivore.noughtsandcrosses.game.Game;
+import com.lunivore.noughtsandcrosses.game.GameObserver;
+
[EMAIL PROTECTED]("serial")
+public class GridPanel extends JPanel implements GameObserver {
+	public static class OXButton extends JButton {
+		private final int row;
+		private final int column;
+
+		public OXButton(String string, int row, int column) {
+			this.row = row;
+			this.column = column;
+			setPreferredSize(new Dimension(50, 50));
+			setName(string);
+		}
+	}
+
+	private static final String NL = System.getProperty("line.separator");
+	
+	private OXButton[][] gridButtons = new OXButton[][] {
+			new OXButton[] {new OXButton("a1", 0, 0), new OXButton("a2", 0, 1), new OXButton("a3", 0, 2)},
+			new OXButton[] {new OXButton("b1", 1, 0), new OXButton("b2", 1, 1), new OXButton("b3", 1, 2)},
+			new OXButton[] {new OXButton("c1", 2, 0), new OXButton("c2", 2, 1), new OXButton("c3", 2, 2)}
+	};
+
+	public GridPanel(final Game game) {
+		setName(ComponentNames.GRID);
+		setLayout(new GridLayout(3, 3));
+		
+		for (OXButton[] row : gridButtons) {
+			for (final OXButton button : row) {
+				add(button);
+				button.addActionListener(new ActionListener(){
+					public void actionPerformed(ActionEvent e) {
+						game.playerActsAt(button.column, button.row);
+					}
+				});
+			}
+		}
+		
+		game.addObserver(this);
+	}
+	
+	@Override
+	public String toString() {
+		StringBuilder builder = new StringBuilder();
+		for (int row = 0; row < gridButtons.length; row++) {
+			for (OXButton button : gridButtons[row]) {
+				builder.append(text(button));
+			}
+			if (row < gridButtons.length - 1) { builder.append(NL); }
+		}
+		return builder.toString();
+	}
+
+	private String text(JButton button) {
+		return button.getText() == "" ? "." : button.getText();
+	}
+
+	public void gameChanged(Game game) {
+		for (OXButton[] row : gridButtons) {
+			for (OXButton button : row) {
+				button.setText(game.playerAt(button.column, button.row).asString());
+			}
+		}
+	}
+
+	public void gameWon(Game game) {
+		gameChanged(game);
+	}
+}

Added: trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/view/MessageLabel.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/view/MessageLabel.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/view/MessageLabel.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,27 @@
+package com.lunivore.noughtsandcrosses.view;
+
+import java.awt.Dimension;
+
+import javax.swing.JLabel;
+
+import com.lunivore.noughtsandcrosses.game.Game;
+import com.lunivore.noughtsandcrosses.game.GameObserver;
+
[EMAIL PROTECTED]("serial")
+public class MessageLabel extends JLabel implements GameObserver {
+
+	public MessageLabel(Game game) {
+		setName(ComponentNames.MESSAGE);
+		setText("X's turn");
+		setPreferredSize(new Dimension(150, 50));
+		game.addObserver(this);
+	}
+
+	public void gameChanged(Game game) {
+		setText(game.currentPlayer().asString() + "'s turn");
+	}
+	
+	public void gameWon(Game game) {
+		setText(game.currentPlayer().asString() + " wins!");
+	}
+}

Added: trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/view/NoughtsAndCrossesFrame.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/view/NoughtsAndCrossesFrame.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/java/com/lunivore/noughtsandcrosses/view/NoughtsAndCrossesFrame.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,24 @@
+package com.lunivore.noughtsandcrosses.view;
+
+import java.awt.BorderLayout;
+
+import javax.swing.JFrame;
+import javax.swing.WindowConstants;
+
+import com.lunivore.noughtsandcrosses.game.Game;
+
[EMAIL PROTECTED]("serial")
+public class NoughtsAndCrossesFrame extends JFrame {
+
+	public NoughtsAndCrossesFrame(Game game) {
+		setName(ComponentNames.NOUGHTSANDCROSSES);
+		
+		this.getContentPane().setLayout(new BorderLayout());
+		this.getContentPane().add(new GridPanel(game), BorderLayout.NORTH);
+		this.getContentPane().add(new MessageLabel(game), BorderLayout.CENTER);
+		
+		setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+		pack();
+		setVisible(true);
+	}
+}

Added: trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/PlayersCanTakeTurns.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/PlayersCanTakeTurns.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/PlayersCanTakeTurns.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,13 @@
+package com.lunivore.noughtsandcrosses;
+
+import org.jbehave.scenario.Scenario;
+
+import com.lunivore.noughtsandcrosses.steps.GridSteps;
+
+public class PlayersCanTakeTurns extends Scenario {
+
+	public PlayersCanTakeTurns() {
+		super(new GridSteps());
+	}
+
+}

Added: trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/TheGridStartsEmpty.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/TheGridStartsEmpty.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/TheGridStartsEmpty.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,12 @@
+package com.lunivore.noughtsandcrosses;
+
+import org.jbehave.scenario.Scenario;
+
+import com.lunivore.noughtsandcrosses.steps.GridSteps;
+
+
+public class TheGridStartsEmpty extends Scenario {
+	public TheGridStartsEmpty() {
+		super(new GridSteps());
+	}
+}

Added: trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/ThreeInARowWins.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/ThreeInARowWins.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/ThreeInARowWins.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,13 @@
+package com.lunivore.noughtsandcrosses;
+
+import org.jbehave.scenario.Scenario;
+
+import com.lunivore.noughtsandcrosses.steps.GridSteps;
+
+public class ThreeInARowWins extends Scenario {
+	
+	public ThreeInARowWins() {
+		super(new GridSteps());
+	}
+
+}

Added: trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/players_can_take_turns (0 => 881)

--- trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/players_can_take_turns	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/players_can_take_turns	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,20 @@
+Scenario: X takes a turn
+
+Given the game is running
+When the player clicks a1
+Then the grid should look like
+X..
+...
+...
+
+Scenario: O takes a turn
+
+Given a grid that looks like
+X..
+...
+...
+When the player clicks a2
+Then the grid should look like
+XO.
+...
+...

Added: trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/steps/GridSteps.java (0 => 881)

--- trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/steps/GridSteps.java	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/steps/GridSteps.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,83 @@
+package com.lunivore.noughtsandcrosses.steps;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.jbehave.Ensure.ensureThat;
+
+import java.awt.Component;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.swing.JLabel;
+
+import org.jbehave.scenario.annotations.Given;
+import org.jbehave.scenario.annotations.Then;
+import org.jbehave.scenario.annotations.When;
+import org.jbehave.scenario.steps.Steps;
+import org.lunivore.tyburn.WindowControl;
+
+import com.lunivore.noughtsandcrosses.NoughtsAndCrosses;
+import com.lunivore.noughtsandcrosses.view.ComponentNames;
+
+public class GridSteps extends Steps {
+
+	public static String ROWS = "abc";
+	public static String COLUMNS = "123";
+	protected static final String NL = System.getProperty("line.separator");
+	protected WindowControl windowControl;
+
+	@Given("the game is running")
+	public void givenTheGameIsRunning() {
+		windowControl = new WindowControl(ComponentNames.NOUGHTSANDCROSSES);
+		new NoughtsAndCrosses();
+	}
+	
+	@Given("a grid that looks like $grid")
+	public void givenThatTheGridLooksLike(String grid) throws Exception {
+		givenTheGameIsRunning();
+		ArrayList<String> oTurns = new ArrayList<String>();
+		ArrayList<String> xTurns = new ArrayList<String>();
+		
+		captureMoves(oTurns, xTurns, grid);	
+		performMoves(oTurns, xTurns);
+	}
+	
+	@Then("the message should read \"$message\"")
+	public void thenTheMessageShouldRead(String message) throws Exception {
+		JLabel messageLabel = (JLabel) windowControl.findComponent(ComponentNames.MESSAGE);
+		ensureThat(messageLabel.getText(), equalTo(message));
+	}
+
+	@Then("the grid should look like $grid")
+	public void thenTheGridShouldLookLike(String grid) throws Exception {
+		Component gridPanel = windowControl.findComponent(ComponentNames.GRID);
+		ensureThat(gridPanel.toString(), equalTo(grid));
+	}
+
+	@When("the player clicks $space")
+	public void whenPlayerClicksInSpace(String space) throws Exception {
+		windowControl.clickButton(space);
+	}
+	
+	private void performMoves(List<String> oTurns, List<String> xTurns) throws Exception {
+		while (xTurns.size() > 0) {
+			whenPlayerClicksInSpace(xTurns.remove(0));
+			if (oTurns.size() >0) {
+				whenPlayerClicksInSpace(oTurns.remove(0));
+			}
+		}
+	}
+
+	private void captureMoves(List<String> oTurns, List<String> xTurns, String grid) {
+
+		List<String> lines = Arrays.asList(grid.split(NL));
+		for(int row=0;row<3;row++) {
+			for(int col=0;col<3;col++) {
+				char player = lines.get(row).charAt(col);
+				String spaceLabel = "" + ROWS.charAt(row) + COLUMNS.charAt(col);
+				if(player == 'O') {oTurns.add(spaceLabel);}
+				if(player == 'X') {xTurns.add(spaceLabel);}
+			}
+		}
+	}
+}

Added: trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/the_grid_starts_empty (0 => 881)

--- trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/the_grid_starts_empty	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/the_grid_starts_empty	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,6 @@
+Given the game is running
+Then the grid should look like
+...
+...
+...
+Then the message should read "X's turn"
\ No newline at end of file

Added: trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/three_in_a_row_wins (0 => 881)

--- trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/three_in_a_row_wins	                        (rev 0)
+++ trunk/examples/noughtsandcrosses/src/scenario/com/lunivore/noughtsandcrosses/three_in_a_row_wins	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,10 @@
+Given the grid looks like
+OO.
+XX.
+X..
+When the player clicks a3
+Then the grid should look like
+OOO
+XX.
+X..
+Then the message should read "O wins!" 
\ No newline at end of file

Modified: trunk/jbehave-core/src/behaviour/org/jbehave/scenario/ScenarioBehaviour.java (880 => 881)

--- trunk/jbehave-core/src/behaviour/org/jbehave/scenario/ScenarioBehaviour.java	2008-07-27 21:53:10 UTC (rev 880)
+++ trunk/jbehave-core/src/behaviour/org/jbehave/scenario/ScenarioBehaviour.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -42,7 +42,8 @@
 		PrintStreamScenarioReporter reporter = new PrintStreamScenarioReporter(new PrintStream(output));
 		MySteps steps = new MySteps();
 		
- 		stub(fileLoader.loadStepsFor(MyScenario.class)).toReturn(new ScenarioDefinition(stepParser, "my_scenario"));
+ 		stub(fileLoader.loadStepsFor(MyScenario.class)).toReturn(Arrays.asList(
+ 				new ScenarioDefinition(stepParser, "my_scenario")));
 		stub(stepParser.findSteps("my_scenario")).toReturn(Arrays.asList(new String[] {
 				"Given I have 2 cows",
 				"When I leave them over the winter",
@@ -66,7 +67,8 @@
         ScenarioReporter reporter = new BufferScenarioReporter(buffer);
         MySteps steps = new MySteps();
         
-        stub(fileLoader.loadStepsFor(MyScenario.class)).toReturn(new ScenarioDefinition(stepParser, "my_scenario"));
+        stub(fileLoader.loadStepsFor(MyScenario.class)).toReturn(Arrays.asList(
+        		new ScenarioDefinition(stepParser, "my_scenario")));
         stub(stepParser.findSteps("my_scenario")).toReturn(Arrays.asList(new String[] {
                 "Given I have 2 cows",
                 "When I leave them over the winter",
@@ -95,7 +97,8 @@
 		ScenarioReporter reporter = new PrintStreamScenarioReporter(new PrintStream(output));
 		MySteps steps = new MySteps();
 		
-        stub(scenarioDefiner.loadStepsFor(MyScenario.class)).toReturn(new ScenarioDefinition(stepParser, "my_scenario"));
+        stub(scenarioDefiner.loadStepsFor(MyScenario.class)).toReturn(Arrays.asList(
+        		new ScenarioDefinition(stepParser, "my_scenario")));
 		stub(stepParser.findSteps("my_scenario")).toReturn(Arrays.asList(new String[] {
 				"Given I have 2 cows",
 				"When I put them in a field",

Modified: trunk/jbehave-core/src/behaviour/org/jbehave/scenario/ScenarioRunnerBehaviour.java (880 => 881)

--- trunk/jbehave-core/src/behaviour/org/jbehave/scenario/ScenarioRunnerBehaviour.java	2008-07-27 21:53:10 UTC (rev 880)
+++ trunk/jbehave-core/src/behaviour/org/jbehave/scenario/ScenarioRunnerBehaviour.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -5,6 +5,7 @@
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.stub;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
 import org.jbehave.scenario.steps.Step;
@@ -104,4 +105,23 @@
 		
 	}
 	
+	@Test
+	public void shouldResetStateForEachSetOfSteps() throws Throwable {
+
+		ScenarioReporter reporter = mock(ScenarioReporter.class);
+		Step pendingStep = mock(Step.class);
+		Step secondStep = mock(Step.class);
+		stub(pendingStep.perform()).toReturn(StepResult.pending("pendingStep"));
+		stub(secondStep.perform()).toReturn(StepResult.success("secondStep"));
+		
+		ScenarioRunner runner = new ScenarioRunner(reporter);
+		
+		runner.run(pendingStep);
+		runner.run(secondStep); // should reset state for this one
+		
+		verify(pendingStep).perform();
+		verify(secondStep).perform();
+		verify(secondStep, never()).doNotPerform();
+	}
+	
 }

Modified: trunk/jbehave-core/src/behaviour/org/jbehave/scenario/parser/PatternStepParserBehaviour.java (880 => 881)

--- trunk/jbehave-core/src/behaviour/org/jbehave/scenario/parser/PatternStepParserBehaviour.java	2008-07-27 21:53:10 UTC (rev 880)
+++ trunk/jbehave-core/src/behaviour/org/jbehave/scenario/parser/PatternStepParserBehaviour.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -5,7 +5,6 @@
 
 import java.util.List;
 
-import org.jbehave.scenario.parser.PatternStepParser;
 import org.junit.Test;
 
 

Modified: trunk/jbehave-core/src/behaviour/org/jbehave/scenario/parser/ScenarioFileLoaderBehaviour.java (880 => 881)

--- trunk/jbehave-core/src/behaviour/org/jbehave/scenario/parser/ScenarioFileLoaderBehaviour.java	2008-07-27 21:53:10 UTC (rev 880)
+++ trunk/jbehave-core/src/behaviour/org/jbehave/scenario/parser/ScenarioFileLoaderBehaviour.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -8,17 +8,20 @@
 import java.util.List;
 
 import org.jbehave.scenario.Scenario;
+import org.jbehave.scenario.parser.scenarios.MyMultipleScenario;
 import org.jbehave.scenario.parser.scenarios.MyPendingScenario;
 import org.junit.Test;
 
 public class ScenarioFileLoaderBehaviour {
 
-    @Test
+    private static final String NL = System.getProperty("line.separator");
+
+	@Test
     public void canLoadScenario() {
     	StepParser parser = mock(StepParser.class);
         ScenarioFileLoader loader = new ScenarioFileLoader(parser);
-        ScenarioDefinition definition = loader.loadStepsFor(MyPendingScenario.class);
-        definition.getSteps();
+        List<ScenarioDefinition> definitions = loader.loadStepsFor(MyPendingScenario.class);
+        definitions.get(0).getSteps();
         verify(parser).findSteps("Given my scenario");
     }
 
@@ -26,7 +29,7 @@
     public void canLoadScenarioWithCustomFilenameResolver() {
     	StepParser parser = mock(StepParser.class);
         ScenarioFileLoader loader = new ScenarioFileLoader(new CasePreservingResolver(".scenario"), parser);
-        loader.loadStepsFor(MyPendingScenario.class).getSteps();
+        loader.loadStepsFor(MyPendingScenario.class).get(0).getSteps();
         verify(parser).findSteps("Given my scenario");
     }
     
@@ -41,6 +44,15 @@
         ScenarioFileLoader loader = new ScenarioFileLoader(new InvalidClassLoader());
         loader.loadStepsFor(MyPendingScenario.class);
     }
+    
+    @Test
+    public void canLoadMultipleScenariosInTheSameFile() {
+    	StepParser parser = mock(StepParser.class);
+        ScenarioFileLoader loader = new ScenarioFileLoader(parser);
+        List<ScenarioDefinition> definitions = loader.loadStepsFor(MyMultipleScenario.class);
+        definitions.get(1).getSteps();
+        verify(parser).findSteps("Scenario: the second scenario" + NL + NL + "Given my second scenario");
+    }
 
     static class InexistentScenario extends Scenario {
 

Added: trunk/jbehave-core/src/behaviour/org/jbehave/scenario/parser/scenarios/MyMultipleScenario.java (0 => 881)

--- trunk/jbehave-core/src/behaviour/org/jbehave/scenario/parser/scenarios/MyMultipleScenario.java	                        (rev 0)
+++ trunk/jbehave-core/src/behaviour/org/jbehave/scenario/parser/scenarios/MyMultipleScenario.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,20 @@
+package org.jbehave.scenario.parser.scenarios;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import org.jbehave.OurTechnique;
+import org.jbehave.scenario.Scenario;
+import org.jbehave.scenario.reporters.PrintStreamScenarioReporter;
+
+public class MyMultipleScenario extends Scenario {
+	public MyMultipleScenario() {
+		// Making sure this doesn't output to the build while it's running
+		super(new OurTechnique() {
+			@Override
+			public PrintStreamScenarioReporter forReportingScenarios() {
+				return new PrintStreamScenarioReporter(new PrintStream(new ByteArrayOutputStream()));
+			}
+		});
+	}
+}

Added: trunk/jbehave-core/src/behaviour/org/jbehave/scenario/parser/scenarios/my_multiple_scenario (0 => 881)

--- trunk/jbehave-core/src/behaviour/org/jbehave/scenario/parser/scenarios/my_multiple_scenario	                        (rev 0)
+++ trunk/jbehave-core/src/behaviour/org/jbehave/scenario/parser/scenarios/my_multiple_scenario	2008-07-28 19:31:08 UTC (rev 881)
@@ -0,0 +1,7 @@
+Scenario: the first scenario
+
+Given my scenario
+
+Scenario: the second scenario
+
+Given my second scenario
\ No newline at end of file

Modified: trunk/jbehave-core/src/behaviour/org/jbehave/scenario/steps/StepResultBehaviour.java (880 => 881)

--- trunk/jbehave-core/src/behaviour/org/jbehave/scenario/steps/StepResultBehaviour.java	2008-07-27 21:53:10 UTC (rev 880)
+++ trunk/jbehave-core/src/behaviour/org/jbehave/scenario/steps/StepResultBehaviour.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -1,11 +1,10 @@
 package org.jbehave.scenario.steps;
 
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
 import static org.jbehave.Ensure.ensureThat;
 import static org.jbehave.Ensure.not;
 import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 import org.jbehave.scenario.ScenarioReporter;
 import org.junit.Test;

Modified: trunk/jbehave-core/src/java/org/jbehave/scenario/Scenario.java (880 => 881)

--- trunk/jbehave-core/src/java/org/jbehave/scenario/Scenario.java	2008-07-27 21:53:10 UTC (rev 880)
+++ trunk/jbehave-core/src/java/org/jbehave/scenario/Scenario.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -39,9 +39,11 @@
 
     @Test
     public void runUsingSteps() throws Throwable {
-        ScenarioDefinition definition = scenarioDefiner.loadStepsFor(this.getClass());
-        Step[] steps = createRealStepsFromCandidates(definition.getSteps());
-        scenarioRunner.run(steps);
+        List<ScenarioDefinition> definitions = scenarioDefiner.loadStepsFor(this.getClass());
+        for (ScenarioDefinition definition : definitions) {
+            Step[] steps = createRealStepsFromCandidates(definition.getSteps());
+            scenarioRunner.run(steps);
+		}
     }
 
 	private Step[] createRealStepsFromCandidates(List<String> stringSteps) {

Modified: trunk/jbehave-core/src/java/org/jbehave/scenario/ScenarioRunner.java (880 => 881)

--- trunk/jbehave-core/src/java/org/jbehave/scenario/ScenarioRunner.java	2008-07-27 21:53:10 UTC (rev 880)
+++ trunk/jbehave-core/src/java/org/jbehave/scenario/ScenarioRunner.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -11,7 +11,7 @@
  */
 public class ScenarioRunner {
 
-    private State state = new FineSoFar();
+    private State state;
     private final ScenarioReporter reporter;
 
     public ScenarioRunner(ScenarioReporter reporter) {
@@ -19,6 +19,7 @@
     }
 
     public void run(Step... steps) throws Throwable {
+    	state = new FineSoFar();
         for (Step step : steps) {
             state.run(step);
         }

Modified: trunk/jbehave-core/src/java/org/jbehave/scenario/parser/PatternStepParser.java (880 => 881)

--- trunk/jbehave-core/src/java/org/jbehave/scenario/parser/PatternStepParser.java	2008-07-27 21:53:10 UTC (rev 880)
+++ trunk/jbehave-core/src/java/org/jbehave/scenario/parser/PatternStepParser.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -7,7 +7,7 @@
 
 public class PatternStepParser implements StepParser {
 
-    public static final String DEFAULT_PARSE_REGEX = "((Given|When|Then) (.|\\s)*?)\\s*(\\Z|Given|When|Then)";
+    public static final String DEFAULT_PARSE_REGEX = "((Given|When|Then) (.|\\s)*?)\\s*(\\Z|Given|When|Then|Scenario:)";
 
     private final Pattern pattern;
 

Modified: trunk/jbehave-core/src/java/org/jbehave/scenario/parser/ScenarioDefiner.java (880 => 881)

--- trunk/jbehave-core/src/java/org/jbehave/scenario/parser/ScenarioDefiner.java	2008-07-27 21:53:10 UTC (rev 880)
+++ trunk/jbehave-core/src/java/org/jbehave/scenario/parser/ScenarioDefiner.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -1,9 +1,11 @@
 package org.jbehave.scenario.parser;
 
+import java.util.List;
+
 import org.jbehave.scenario.Scenario;
 
 public interface ScenarioDefiner {
 
-	ScenarioDefinition loadStepsFor(Class<? extends Scenario> clazz);
+	List<ScenarioDefinition> loadStepsFor(Class<? extends Scenario> clazz);
 
 }
\ No newline at end of file

Modified: trunk/jbehave-core/src/java/org/jbehave/scenario/parser/ScenarioFileLoader.java (880 => 881)

--- trunk/jbehave-core/src/java/org/jbehave/scenario/parser/ScenarioFileLoader.java	2008-07-27 21:53:10 UTC (rev 880)
+++ trunk/jbehave-core/src/java/org/jbehave/scenario/parser/ScenarioFileLoader.java	2008-07-28 19:31:08 UTC (rev 881)
@@ -3,6 +3,10 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import org.jbehave.scenario.Scenario;
 
@@ -43,20 +47,43 @@
         return stream;
     }
 
-    public ScenarioDefinition loadStepsFor(Class<? extends Scenario> scenarioClass) {
-        return new ScenarioDefinition(stepParser, asString(loadStepsAsStreamFor(scenarioClass)));
+    public List<ScenarioDefinition>loadStepsFor(Class<? extends Scenario> scenarioClass) {
+    	List<String> scenarios = asString(loadStepsAsStreamFor(scenarioClass));
+    	List<ScenarioDefinition> scenarioDefinitions = new ArrayList<ScenarioDefinition>();
+    	for (String string : scenarios) {
+			scenarioDefinitions.add(new ScenarioDefinition(stepParser, string));
+		}
+        return scenarioDefinitions;
     }
 
-    private String asString(InputStream stream) {
+    private List<String> asString(InputStream stream) {
         try {            
             byte[] bytes = new byte[stream.available()];
             stream.read(bytes);
             ByteArrayOutputStream output = new ByteArrayOutputStream();
             output.write(bytes);
-            return output.toString();
+            String allScenariosInFile = output.toString();
+    		return splitScenarios(allScenariosInFile);
         } catch (IOException e) {
             throw new InvalidScenarioResourceException("Failed to convert scenario resouce to string", e);
         }
     }
 
+	private List<String> splitScenarios(String allScenariosInFile) {
+    	Pattern scenarioSplitter = Pattern.compile("((Scenario:) (.|\\s)*?)\\s*(\\Z|Scenario:).*", Pattern.DOTALL);
+    	Matcher matcher = scenarioSplitter.matcher(allScenariosInFile);
+    	int startAt = 0;
+    	List<String> scenarios = new ArrayList<String>();
+    	if (matcher.matches()) {
+			while(matcher.find(startAt)) {
+				scenarios.add(matcher.group(1));
+				startAt = matcher.start(4);
+			}
+    	} else {
+    		String loneScenario = allScenariosInFile;
+			scenarios.add(loneScenario);
+    	}
+    	return scenarios;
+	}
+
 }


To unsubscribe from this list please visit:

http://xircles.codehaus.org/manage_email

Reply via email to