Added Rspec and Webrat plugins and started porting Selenium on Rails tests to Rspec Plain Text Stories driving Webrat driving Selenium.

This commit is contained in:
Luke Melia 2008-06-18 02:57:57 -04:00
parent 0600756bbf
commit 0f7d6f7a1d
602 changed files with 47788 additions and 29 deletions

View file

@ -0,0 +1,19 @@
require File.dirname(__FILE__) + '/spec_helper'
# Run spec w/ -fs to see the output of this file
describe "Examples with no descriptions" do
# description is auto-generated as "should equal(5)" based on the last #should
it do
3.should equal(3)
5.should equal(5)
end
it { 3.should be < 5 }
it { ["a"].should include("a") }
it { [1,2,3].should respond_to(:size) }
end

View file

@ -0,0 +1,40 @@
require File.dirname(__FILE__) + '/spec_helper'
$global = 0
describe "State created in before(:all)" do
before :all do
@sideeffect = 1
$global +=1
end
before :each do
@isolated = 1
end
it "should be accessible from example" do
@sideeffect.should == 1
$global.should == 1
@isolated.should == 1
@sideeffect += 1
@isolated += 1
end
it "should not have sideffects" do
@sideeffect.should == 1
$global.should == 2
@isolated.should == 1
@sideeffect += 1
@isolated += 1
end
after :each do
$global += 1
end
after :all do
$global.should == 3
$global = 0
end
end

View file

@ -0,0 +1,45 @@
require File.dirname(__FILE__) + '/spec_helper'
def behave_as_electric_musician
respond_to(:read_notes, :turn_down_amp)
end
def behave_as_musician
respond_to(:read_notes)
end
module BehaveAsExample
class BluesGuitarist
def read_notes; end
def turn_down_amp; end
end
class RockGuitarist
def read_notes; end
def turn_down_amp; end
end
class ClassicGuitarist
def read_notes; end
end
describe BluesGuitarist do
it "should behave as guitarist" do
BluesGuitarist.new.should behave_as_electric_musician
end
end
describe RockGuitarist do
it "should behave as guitarist" do
RockGuitarist.new.should behave_as_electric_musician
end
end
describe ClassicGuitarist do
it "should not behave as guitarist" do
ClassicGuitarist.new.should behave_as_musician
end
end
end

View file

@ -0,0 +1,54 @@
module AnimalSpecHelper
class Eat
def initialize(food)
@food = food
end
def matches?(animal)
@animal = animal
@animal.eats?(@food)
end
def failure_message
"expected #{@animal} to eat #{@food}, but it does not"
end
def negative_failure_message
"expected #{@animal} not to eat #{@food}, but it does"
end
end
def eat(food)
Eat.new(food)
end
end
module Animals
class Animal
def eats?(food)
return foods_i_eat.include?(food)
end
end
class Mouse < Animal
def foods_i_eat
[:cheese]
end
end
describe Mouse do
include AnimalSpecHelper
before(:each) do
@mouse = Animals::Mouse.new
end
it "should eat cheese" do
@mouse.should eat(:cheese)
end
it "should not eat cat" do
@mouse.should_not eat(:cat)
end
end
end

View file

@ -0,0 +1,12 @@
require File.dirname(__FILE__) + '/spec_helper'
require 'spec/runner/formatter/progress_bar_formatter'
# Example of a formatter with custom bactrace printing. Run me with:
# ruby bin/spec failing_examples -r examples/custom_formatter.rb -f CustomFormatter
class CustomFormatter < Spec::Runner::Formatter::ProgressBarFormatter
def backtrace_line(line)
line.gsub(/([^:]*\.rb):(\d*)/) do
"<a href=\"file://#{File.expand_path($1)}\">#{$1}:#{$2}</a> "
end
end
end

View file

@ -0,0 +1,9 @@
require File.dirname(__FILE__) + '/spec_helper'
describe "Some integers" do
(1..10).each do |n|
it "The root of #{n} square should be #{n}" do
Math.sqrt(n*n).should == n
end
end
end

View file

@ -0,0 +1,19 @@
require File.dirname(__FILE__) + '/spec_helper'
class FileAccessor
def open_and_handle_with(pathname, processor)
pathname.open do |io|
processor.process(io)
end
end
end
if __FILE__ == $0
require File.dirname(__FILE__) + '/io_processor'
require 'pathname'
accessor = FileAccessor.new
io_processor = IoProcessor.new
file = Pathname.new ARGV[0]
accessor.open_and_handle_with(file, io_processor)
end

View file

@ -0,0 +1,38 @@
require File.dirname(__FILE__) + '/spec_helper'
require File.dirname(__FILE__) + '/file_accessor'
require 'stringio'
describe "A FileAccessor" do
# This sequence diagram illustrates what this spec specifies.
#
# +--------------+ +----------+ +-------------+
# | FileAccessor | | Pathname | | IoProcessor |
# +--------------+ +----------+ +-------------+
# | | |
# open_and_handle_with | | |
# -------------------->| | open | |
# | |--------------->| | |
# | | io | | |
# | |<...............| | |
# | | | process(io) |
# | |---------------------------------->| |
# | | | | |
# | |<..................................| |
# | | |
#
it "should open a file and pass it to the processor's process method" do
# This is the primary actor
accessor = FileAccessor.new
# These are the primary actor's neighbours, which we mock.
file = mock "Pathname"
io_processor = mock "IoProcessor"
io = StringIO.new "whatever"
file.should_receive(:open).and_yield io
io_processor.should_receive(:process).with(io)
accessor.open_and_handle_with(file, io_processor)
end
end

View file

@ -0,0 +1,31 @@
require File.dirname(__FILE__) + '/spec_helper'
# greeter.rb
#
# Based on http://glu.ttono.us/articles/2006/12/19/tormenting-your-tests-with-heckle
#
# Run with:
#
# spec greeter_spec.rb --heckle Greeter
#
class Greeter
def initialize(person = nil)
@person = person
end
def greet
@person.nil? ? "Hi there!" : "Hi #{@person}!"
end
end
describe "Greeter" do
it "should say Hi to person" do
greeter = Greeter.new("Kevin")
greeter.greet.should == "Hi Kevin!"
end
it "should say Hi to nobody" do
greeter = Greeter.new
# Uncomment the next line to make Heckle happy
#greeter.greet.should == "Hi there!"
end
end

View file

@ -0,0 +1,14 @@
require File.dirname(__FILE__) + '/spec_helper'
module HelperMethodExample
describe "an example group with helper a method" do
def helper_method
"received call"
end
it "should make that method available to specs" do
helper_method.should == "received call"
end
end
end

View file

@ -0,0 +1,8 @@
class DataTooShort < StandardError; end
class IoProcessor
# Does some fancy stuff unless the length of +io+ is shorter than 32
def process(io)
raise DataTooShort if io.read.length < 32
end
end

View file

@ -0,0 +1,21 @@
require File.dirname(__FILE__) + '/spec_helper'
require File.dirname(__FILE__) + '/io_processor'
require 'stringio'
describe "An IoProcessor" do
before(:each) do
@processor = IoProcessor.new
end
it "should raise nothing when the file is exactly 32 bytes" do
lambda {
@processor.process(StringIO.new("z"*32))
}.should_not raise_error
end
it "should raise an exception when the file length is less than 32 bytes" do
lambda {
@processor.process(StringIO.new("z"*31))
}.should raise_error(DataTooShort)
end
end

View file

@ -0,0 +1,11 @@
require File.dirname(__FILE__) + '/spec_helper'
context "A legacy spec" do
setup do
end
specify "should work fine" do
end
teardown do
end
end

View file

@ -0,0 +1,27 @@
require File.dirname(__FILE__) + '/spec_helper'
describe "A consumer of a mock" do
it "should be able to send messages to the mock" do
mock = mock("poke me")
mock.should_receive(:poke)
mock.poke
end
end
describe "a mock" do
it "should be able to mock the same message twice w/ different args" do
mock = mock("mock")
mock.should_receive(:msg).with(:arg1).and_return(:val1)
mock.should_receive(:msg).with(:arg2).and_return(:val2)
mock.msg(:arg1).should eql(:val1)
mock.msg(:arg2).should eql(:val2)
end
it "should be able to mock the same message twice w/ different args in reverse order" do
mock = mock("mock")
mock.should_receive(:msg).with(:arg1).and_return(:val1)
mock.should_receive(:msg).with(:arg2).and_return(:val2)
mock.msg(:arg2).should eql(:val2)
mock.msg(:arg1).should eql(:val1)
end
end

View file

@ -0,0 +1,28 @@
class MultiThreadedExampleGroupRunner < Spec::Runner::ExampleGroupRunner
def initialize(options, arg)
super(options)
# configure these
@thread_count = 4
@thread_wait = 0
end
def run
@threads = []
q = Queue.new
example_groups.each { |b| q << b}
success = true
@thread_count.times do
@threads << Thread.new(q) do |queue|
while not queue.empty?
example_group = queue.pop
success &= example_group.suite.run(nil)
end
end
sleep @thread_wait
end
@threads.each {|t| t.join}
success
end
end
MultiThreadedBehaviourRunner = MultiThreadedExampleGroupRunner

View file

@ -0,0 +1,36 @@
require File.dirname(__FILE__) + '/spec_helper'
require File.dirname(__FILE__) + '/stack'
class StackExamples < Spec::ExampleGroup
describe(Stack)
before(:each) do
@stack = Stack.new
end
end
class EmptyStackExamples < StackExamples
describe("when empty")
it "should be empty" do
@stack.should be_empty
end
end
class AlmostFullStackExamples < StackExamples
describe("when almost full")
before(:each) do
(1..9).each {|n| @stack.push n}
end
it "should be full" do
@stack.should_not be_full
end
end
class FullStackExamples < StackExamples
describe("when full")
before(:each) do
(1..10).each {|n| @stack.push n}
end
it "should be full" do
@stack.should be_full
end
end

View file

@ -0,0 +1,29 @@
require File.dirname(__FILE__) + '/spec_helper'
class MockableClass
def self.find id
return :original_return
end
end
describe "A partial mock" do
it "should work at the class level" do
MockableClass.should_receive(:find).with(1).and_return {:stub_return}
MockableClass.find(1).should equal(:stub_return)
end
it "should revert to the original after each spec" do
MockableClass.find(1).should equal(:original_return)
end
it "can be mocked w/ ordering" do
MockableClass.should_receive(:msg_1).ordered
MockableClass.should_receive(:msg_2).ordered
MockableClass.should_receive(:msg_3).ordered
MockableClass.msg_1
MockableClass.msg_2
MockableClass.msg_3
end
end

View file

@ -0,0 +1,20 @@
require File.dirname(__FILE__) + '/spec_helper'
describe "pending example (using pending method)" do
it %Q|should be reported as "PENDING: for some reason"| do
pending("for some reason")
end
end
describe "pending example (with no block)" do
it %Q|should be reported as "PENDING: Not Yet Implemented"|
end
describe "pending example (with block for pending)" do
it %Q|should have a failing block, passed to pending, reported as "PENDING: for some reason"| do
pending("for some reason") do
raise "some reason"
end
end
end

View file

@ -0,0 +1,27 @@
require File.dirname(__FILE__) + '/spec_helper'
class BddFramework
def intuitive?
true
end
def adopted_quickly?
true
end
end
describe "BDD framework" do
before(:each) do
@bdd_framework = BddFramework.new
end
it "should be adopted quickly" do
@bdd_framework.should be_adopted_quickly
end
it "should be intuitive" do
@bdd_framework.should be_intuitive
end
end

View file

@ -0,0 +1 @@
examples/custom_expectation_matchers.rb

View file

@ -0,0 +1,81 @@
require File.dirname(__FILE__) + '/spec_helper'
module SharedExampleGroupExample
class OneThing
def what_things_do
"stuff"
end
end
class AnotherThing
def what_things_do
"stuff"
end
end
class YetAnotherThing
def what_things_do
"stuff"
end
end
# A SharedExampleGroup is an example group that doesn't get run.
# You can create one like this:
share_examples_for "most things" do
def helper_method
"helper method"
end
it "should do what things do" do
@thing.what_things_do.should == "stuff"
end
end
# A SharedExampleGroup is also module. If you create one like this
# it gets assigned to the constant AllThings
share_as :MostThings do
def helper_method
"helper method"
end
it "should do what things do" do
@thing.what_things_do.should == "stuff"
end
end
describe OneThing do
# Now you can include the shared example group like this, which
# feels more like what you might say ...
it_should_behave_like "most things"
before(:each) { @thing = OneThing.new }
it "should have access to helper methods defined in the shared example group" do
helper_method.should == "helper method"
end
end
describe AnotherThing do
# ... or you can include the example group like this, which
# feels more like the programming language we love.
it_should_behave_like MostThings
before(:each) { @thing = AnotherThing.new }
it "should have access to helper methods defined in the shared example group" do
helper_method.should == "helper method"
end
end
describe YetAnotherThing do
# ... or you can include the example group like this, which
# feels more like the programming language we love.
include MostThings
before(:each) { @thing = AnotherThing.new }
it "should have access to helper methods defined in the shared example group" do
helper_method.should == "helper method"
end
end
end

View file

@ -0,0 +1,38 @@
require File.join(File.dirname(__FILE__), *%w[spec_helper])
shared_examples_for "non-empty Stack" do
it { @stack.should_not be_empty }
it "should return the top item when sent #peek" do
@stack.peek.should == @last_item_added
end
it "should NOT remove the top item when sent #peek" do
@stack.peek.should == @last_item_added
@stack.peek.should == @last_item_added
end
it "should return the top item when sent #pop" do
@stack.pop.should == @last_item_added
end
it "should remove the top item when sent #pop" do
@stack.pop.should == @last_item_added
unless @stack.empty?
@stack.pop.should_not == @last_item_added
end
end
end
shared_examples_for "non-full Stack" do
it { @stack.should_not be_full }
it "should add to the top when sent #push" do
@stack.push "newly added top item"
@stack.peek.should == "newly added top item"
end
end

View file

@ -0,0 +1,3 @@
lib_path = File.expand_path("#{File.dirname(__FILE__)}/../../lib")
$LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
require 'spec'

View file

@ -0,0 +1,36 @@
class StackUnderflowError < RuntimeError
end
class StackOverflowError < RuntimeError
end
class Stack
def initialize
@items = []
end
def push object
raise StackOverflowError if @items.length == 10
@items.push object
end
def pop
raise StackUnderflowError if @items.empty?
@items.delete @items.last
end
def peek
raise StackUnderflowError if @items.empty?
@items.last
end
def empty?
@items.empty?
end
def full?
@items.length == 10
end
end

View file

@ -0,0 +1,63 @@
require File.dirname(__FILE__) + '/spec_helper'
require File.dirname(__FILE__) + "/stack"
require File.dirname(__FILE__) + '/shared_stack_examples'
describe Stack, " (empty)" do
before(:each) do
@stack = Stack.new
end
# NOTE that this one auto-generates the description "should be empty"
it { @stack.should be_empty }
it_should_behave_like "non-full Stack"
it "should complain when sent #peek" do
lambda { @stack.peek }.should raise_error(StackUnderflowError)
end
it "should complain when sent #pop" do
lambda { @stack.pop }.should raise_error(StackUnderflowError)
end
end
describe Stack, " (with one item)" do
before(:each) do
@stack = Stack.new
@stack.push 3
@last_item_added = 3
end
it_should_behave_like "non-empty Stack"
it_should_behave_like "non-full Stack"
end
describe Stack, " (with one item less than capacity)" do
before(:each) do
@stack = Stack.new
(1..9).each { |i| @stack.push i }
@last_item_added = 9
end
it_should_behave_like "non-empty Stack"
it_should_behave_like "non-full Stack"
end
describe Stack, " (full)" do
before(:each) do
@stack = Stack.new
(1..10).each { |i| @stack.push i }
@last_item_added = 10
end
# NOTE that this one auto-generates the description "should be full"
it { @stack.should be_full }
it_should_behave_like "non-empty Stack"
it "should complain on #push" do
lambda { @stack.push Object.new }.should raise_error(StackOverflowError)
end
end

View file

@ -0,0 +1,67 @@
require File.dirname(__FILE__) + '/spec_helper'
require File.dirname(__FILE__) + '/stack'
require File.dirname(__FILE__) + '/shared_stack_examples'
describe Stack do
before(:each) do
@stack = Stack.new
end
describe "(empty)" do
it { @stack.should be_empty }
it_should_behave_like "non-full Stack"
it "should complain when sent #peek" do
lambda { @stack.peek }.should raise_error(StackUnderflowError)
end
it "should complain when sent #pop" do
lambda { @stack.pop }.should raise_error(StackUnderflowError)
end
end
describe "(with one item)" do
before(:each) do
@stack.push 3
@last_item_added = 3
end
it_should_behave_like "non-empty Stack"
it_should_behave_like "non-full Stack"
end
describe "(with one item less than capacity)" do
before(:each) do
(1..9).each { |i| @stack.push i }
@last_item_added = 9
end
it_should_behave_like "non-empty Stack"
it_should_behave_like "non-full Stack"
end
describe "(full)" do
before(:each) do
(1..10).each { |i| @stack.push i }
@last_item_added = 10
end
it { @stack.should be_full }
it_should_behave_like "non-empty Stack"
it "should complain on #push" do
lambda { @stack.push Object.new }.should raise_error(StackOverflowError)
end
end
end

View file

@ -0,0 +1,69 @@
require File.dirname(__FILE__) + '/spec_helper'
describe "A consumer of a stub" do
it "should be able to stub methods on any Object" do
obj = Object.new
obj.stub!(:foobar).and_return {:return_value}
obj.foobar.should equal(:return_value)
end
end
class StubbableClass
def self.find id
return :original_return
end
end
describe "A stubbed method on a class" do
it "should return the stubbed value" do
StubbableClass.stub!(:find).and_return(:stub_return)
StubbableClass.find(1).should equal(:stub_return)
end
it "should revert to the original method after each spec" do
StubbableClass.find(1).should equal(:original_return)
end
it "can stub! and mock the same message" do
StubbableClass.stub!(:msg).and_return(:stub_value)
StubbableClass.should_receive(:msg).with(:arg).and_return(:mock_value)
StubbableClass.msg.should equal(:stub_value)
StubbableClass.msg(:other_arg).should equal(:stub_value)
StubbableClass.msg(:arg).should equal(:mock_value)
StubbableClass.msg(:another_arg).should equal(:stub_value)
StubbableClass.msg(:yet_another_arg).should equal(:stub_value)
StubbableClass.msg.should equal(:stub_value)
end
end
describe "A mock" do
it "can stub!" do
mock = mock("stubbing mock")
mock.stub!(:msg).and_return(:value)
(1..10).each {mock.msg.should equal(:value)}
end
it "can stub! and mock" do
mock = mock("stubbing mock")
mock.stub!(:stub_message).and_return(:stub_value)
mock.should_receive(:mock_message).once.and_return(:mock_value)
(1..10).each {mock.stub_message.should equal(:stub_value)}
mock.mock_message.should equal(:mock_value)
(1..10).each {mock.stub_message.should equal(:stub_value)}
end
it "can stub! and mock the same message" do
mock = mock("stubbing mock")
mock.stub!(:msg).and_return(:stub_value)
mock.should_receive(:msg).with(:arg).and_return(:mock_value)
mock.msg.should equal(:stub_value)
mock.msg(:other_arg).should equal(:stub_value)
mock.msg(:arg).should equal(:mock_value)
mock.msg(:another_arg).should equal(:stub_value)
mock.msg(:yet_another_arg).should equal(:stub_value)
mock.msg.should equal(:stub_value)
end
end

View file

@ -0,0 +1,13 @@
class Adder
def initialize
@addends = []
end
def <<(val)
@addends << val
end
def sum
@addends.inject(0) { |sum_so_far, val| sum_so_far + val }
end
end

View file

@ -0,0 +1,34 @@
This is a story about a calculator. The text up here above the Story: declaration
won't be processed, so you can write whatever you wish!
Story: simple addition
As an accountant
I want to add numbers
So that I can count beans
Scenario: add one plus one
Given an addend of 1
And an addend of 1
When the addends are addeds
Then the sum should be 3
And the corks should be popped
Scenario: add two plus five
Given an addend of 2
And an addend of 5
When the addends are added
Then the sum should be 7
Then it should snow
Scenario: add three more
GivenScenario add two plus five
And an addend of 3
When the addends are added
Then the sum should be 10

View file

@ -0,0 +1,9 @@
require File.join(File.dirname(__FILE__), "helper")
require File.join(File.dirname(__FILE__), "adder")
# with_steps_for :addition, :more_addition do
with_steps_for :addition, :more_addition do
# Then("the corks should be popped") { }
run File.expand_path(__FILE__).gsub(".rb","")
end

View file

@ -0,0 +1,65 @@
$:.push File.join(File.dirname(__FILE__), *%w[.. .. lib])
require 'spec'
class AdditionMatchers < Spec::Story::StepGroup
steps do |add|
add.given("an addend of $addend") do |addend|
@adder ||= Adder.new
@adder << addend.to_i
end
end
end
steps = AdditionMatchers.new do |add|
add.then("the sum should be $sum") do |sum|
@sum.should == sum.to_i
end
end
steps.when("they are added") do
@sum = @adder.sum
end
# This Story uses steps (see above) instead of blocks
# passed to Given, When and Then
Story "addition", %{
As an accountant
I want to add numbers
So that I can count some beans
}, :steps_for => steps do
Scenario "2 + 3" do
Given "an addend of 2"
And "an addend of 3"
When "they are added"
Then "the sum should be 5"
end
# This scenario uses GivenScenario, which silently runs
# all the steps in a previous scenario.
Scenario "add 4 more" do
GivenScenario "2 + 3"
Given "an addend of 4"
When "they are added"
Then "the sum should be 9"
end
end
# And the class that makes the story pass
class Adder
def << addend
addends << addend
end
def sum
@addends.inject(0) do |result, addend|
result + addend.to_i
end
end
def addends
@addends ||= []
end
end

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<loadpath>
<pathentry path="" type="src"/>
<pathentry path="org.rubypeople.rdt.launching.RUBY_CONTAINER" type="con"/>
</loadpath>

View file

@ -0,0 +1,21 @@
John Conway's Game of Life
The Rules
---------
The Game of Life was invented by John Conway (as you might have gathered).
The game is played on a field of cells, each of which has eight neighbors (adjacent cells).
A cell is either occupied (by an organism) or not.
The rules for deriving a generation from the previous one are these:
Survival
--------
If an occupied cell has 2 or 3 neighbors, the organism survives to the next generation.
Death
-----
If an occupied cell has 0, 1, 4, 5, 6, 7, or 8 occupied neighbors, the organism dies
(0, 1: of loneliness; 4 thru 8: of overcrowding).
Birth
-----
If an unoccupied cell has 3 occupied neighbors, it becomes occupied.

View file

@ -0,0 +1,6 @@
$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', 'lib')
$:.unshift File.join(File.dirname(__FILE__), '..')
require 'spec'
require 'behaviour/examples/examples'
require 'behaviour/stories/stories'

View file

@ -0,0 +1,3 @@
require 'spec'
require 'behaviour/examples/game_behaviour'
require 'behaviour/examples/grid_behaviour'

View file

@ -0,0 +1,35 @@
require 'life'
describe Game do
it 'should have a grid' do
# given
game = Game.new(5, 5)
# then
game.grid.should be_kind_of(Grid)
end
it 'should create a cell' do
# given
game = Game.new(2, 2)
expected_grid = Grid.from_string( 'X. ..' )
# when
game.create_at(0, 0)
# then
game.grid.should == expected_grid
end
it 'should destroy a cell' do
# given
game = Game.new(2,2)
game.grid = Grid.from_string('X. ..')
# when
game.destroy_at(0,0)
# then
game.grid.should == Grid.from_string('.. ..')
end
end

View file

@ -0,0 +1,66 @@
describe Grid do
it 'should be empty when created' do
# given
expected_contents = [
[0, 0, 0],
[0, 0, 0]
]
grid = Grid.new(2, 3)
# when
contents = grid.contents
# then
contents.should == expected_contents
end
it 'should compare equal based on its contents' do
# given
grid1 = Grid.new(2, 3)
grid2 = Grid.new(2, 3)
# then
grid1.should == grid2
end
it 'should be able to replace its contents' do
# given
grid = Grid.new(2,2)
new_contents = [[0,1,0], [1,0,1]]
# when
grid.contents = new_contents
# then
grid.contents.should == new_contents
grid.rows.should == 2
grid.columns.should == 3
end
it 'should add an organism' do
# given
grid = Grid.new(2, 2)
expected = Grid.new(2, 2)
expected.contents = [[1,0],[0,0]]
# when
grid.create_at(0,0)
# then
grid.should == expected
end
it 'should create itself from a string' do
# given
expected = Grid.new 3, 3
expected.create_at(0,0)
expected.create_at(1,0)
expected.create_at(2,2)
# when
actual = Grid.from_string "X.. X.. ..X"
# then
actual.should == expected
end
end

View file

@ -0,0 +1,21 @@
Story: cells with less than two neighbours die
As a game producer
I want cells with less than two neighbours to die
So that I can illustrate how the game works to people with money
Scenario: cells with zero or one neighbour die
Given the grid looks like
........
.XX.XX..
.XX.....
....X...
........
When the next step occurs
Then the grid should look like
........
.XX.....
.XX.....
........
........

View file

@ -0,0 +1,21 @@
Story: cells with more than three neighbours die
As a game producer
I want cells with more than three neighbours to die
So that I can show the people with money how we are getting on
Scenario: blink
Given the grid looks like
.....
...XX
...XX
.XX..
.XX..
When the next step occurs
Then the grid should look like
.....
...XX
....X
.X...
.XX..

View file

@ -0,0 +1,42 @@
Story: Empty spaces with three neighbours create a cell
As a game producer
I want empty cells with three neighbours to die
So that I have a minimum feature set to ship
Scenario: the glider
Given the grid looks like
...X..
..X...
..XXX.
......
......
When the next step occurs
Then the grid should look like
......
..X.X.
..XX..
...X..
......
When the next step occurs
Then the grid should look like
......
..X...
..X.X.
..XX..
......
When the next step occurs
Then the grid should look like
......
...X..
.XX...
..XX..
......
When the next step occurs
Then the grid should look like
......
..X...
.X....
.XXX..
......

View file

@ -0,0 +1,42 @@
Story: I can create a cell
As a game producer
I want to create a cell
So that I can show the grid to people
Scenario: nothing to see here
Given a 3 x 3 game
Then the grid should look like
...
...
...
Scenario: all on its lonesome
Given a 3 x 3 game
When I create a cell at 1, 1
Then the grid should look like
...
.X.
...
Scenario: the grid has three cells
Given a 3 x 3 game
When I create a cell at 0, 0
and I create a cell at 0, 1
and I create a cell at 2, 2
Then the grid should look like
XX.
...
..X
Scenario: more cells more more
Given the grid has three cells
When I create a celll at 3, 1
Then the grid should look like
XX.
..X
..X

View file

@ -0,0 +1,17 @@
Story: I can kill a cell
As a game producer
I want to kill a cell
So that when I make a mistake I dont have to start again
Scenario: bang youre dead
Given the grid looks like
XX.
.X.
..X
When I destroy the cell at 0, 1
Then the grid should look like
X..
.X.
..X

View file

@ -0,0 +1,53 @@
Story: The grid wraps
As a game player
I want the grid to wrap
So that untidy stuff at the edges is avoided
Scenario: crowded in the corners
Given the grid looks like
X.X
...
X.X
When the next step is taken
Then the grid should look like
X.X
...
X.X
Scenario: the glider returns
Given the glider
......
..X...
.X....
.XXX..
......
When the next step is taken
and the next step is taken
and the next step is taken
and the next step is taken
Then the grid should look like
......
......
.X....
X.....
XXX...
When the next step is taken
Then the grid should look like
.X....
......
......
X.X...
XX....
When the next step is taken
Then the grid should look like
XX....
......
......
X.....
X.X...

View file

@ -0,0 +1,52 @@
require File.join(File.dirname(__FILE__), *%w[helper])
Story "I can create a cell",
%(As a game producer
I want to create a cell
So that I can show the grid to people), :steps_for => :life do
Scenario "nothing to see here" do
Given "a game with dimensions", 3, 3 do |rows,cols|
@game = Game.new(rows,cols)
end
Then "the grid should look like", %(
...
...
...
)
end
Scenario "all on its lonesome" do
Given "a game with dimensions", 2, 2
When "I create a cell at", 1, 1 do |row,col|
@game.create_at(row,col)
end
Then "the grid should look like", %(
..
.X
)
end
Scenario "the grid has three cells" do
Given "a game with dimensions", 3, 3
When "I create a cell at", 0, 0
When "I create a cell at", 0, 1
When "I create a cell at", 2, 2
Then "the grid should look like", %(
XX.
...
..X
)
end
Scenario "more cells more more" do
GivenScenario "the grid has three cells"
When "I create a cell at", 2, 0
Then "the grid should look like", %(
XX.
...
X.X
)
end
end

View file

@ -0,0 +1,6 @@
dir = File.dirname(__FILE__)
$LOAD_PATH.unshift(File.expand_path("#{dir}/../../../../../../rspec/lib"))
require 'spec'
$LOAD_PATH.unshift(File.expand_path("#{dir}/../../"))
require "#{dir}/../../life"
require File.join(File.dirname(__FILE__), *%w[steps])

View file

@ -0,0 +1,26 @@
require File.join(File.dirname(__FILE__), *%w[helper])
Story 'I can kill a cell',
%(As a game producer
I want to kill a cell
So that when I make a mistake I don't have to start again), :steps_for => :life do
Scenario "bang, you're dead" do
Given 'a game that looks like', %(
XX.
.X.
..X
) do |dots|
@game = Game.from_string dots
end
When 'I destroy the cell at', 0, 1 do |row,col|
@game.destroy_at(row,col)
end
Then 'the grid should look like', %(
X..
.X.
..X
)
end
end

View file

@ -0,0 +1,5 @@
steps_for :life do
Then "the grid should look like" do |dots|
@game.grid.should == Grid.from_string(dots)
end
end

View file

@ -0,0 +1,3 @@
require File.join(File.dirname(__FILE__), *%w[helper])
require 'behaviour/stories/create_a_cell'
require 'behaviour/stories/kill_a_cell'

View file

@ -0,0 +1,22 @@
Story: Show the game field
As a game player
I want to see the field
so that I can observe the progress of the organisms
Scenario: an empty field
Given a new game starts
When the game displays the field
Then the field should be empty
StoryBuilder story = stories.createStory().called("a story")
.asA("person")
.iWant("to do something")
.soThat("I can rule the world");
story.addScenario().called("happy path").as()
.given("some context")
.when("some event happens")
.then("expect some outcome");

View file

@ -0,0 +1,3 @@
$: << File.dirname(__FILE__)
require 'life/game'
require 'life/grid'

View file

@ -0,0 +1,23 @@
class Game
attr_accessor :grid
def initialize(rows,cols)
@grid = Grid.new(rows, cols)
end
def create_at(row,col)
@grid.create_at(row,col)
end
def destroy_at(row,col)
@grid.destroy_at(row, col)
end
def self.from_string(dots)
grid = Grid.from_string(dots)
game = new(grid.rows, grid.columns)
game.instance_eval do
@grid = grid
end
return game
end
end

View file

@ -0,0 +1,43 @@
class Grid
attr_accessor :contents
def initialize(rows, cols)
@contents = []
rows.times do @contents << [0] * cols end
end
def rows
@contents.size
end
def columns
@contents[0].size
end
def ==(other)
self.contents == other.contents
end
def create_at(row,col)
@contents[row][col] = 1
end
def destroy_at(row,col)
@contents[row][col] = 0
end
def self.from_string(str)
row_strings = str.split(' ')
grid = new(row_strings.size, row_strings[0].size)
row_strings.each_with_index do |row, row_index|
row_chars = row.split(//)
row_chars.each_with_index do |col_char, col_index|
grid.create_at(row_index, col_index) if col_char == 'X'
end
end
return grid
end
end

View file

@ -0,0 +1,9 @@
$:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
require 'spec/story'
# won't have to do this once plain_text_story_runner is moved into the library
# require File.join(File.dirname(__FILE__), "plain_text_story_runner")
Dir[File.join(File.dirname(__FILE__), "steps/*.rb")].each do |file|
require file
end

View file

@ -0,0 +1,18 @@
require File.expand_path("#{File.dirname(__FILE__)}/../helper")
# This creates steps for :addition
steps_for(:addition) do
Given("an addend of $addend") do |addend|
@adder ||= Adder.new
@adder << addend.to_i
end
end
# This appends to them
steps_for(:addition) do
When("the addends are added") { @sum = @adder.sum }
end
steps_for(:more_addition) do
Then("the sum should be $sum") { |sum| @sum.should == sum.to_i }
end