added RSpec and RSpec on Rails

This commit is contained in:
Xin Zheng 2008-01-22 16:39:09 +00:00
parent ddd5b4cf19
commit 3f607d565b
316 changed files with 23828 additions and 0 deletions

1028
vendor/gems/rspec-1.1.2/CHANGES vendored Normal file

File diff suppressed because it is too large Load diff

20
vendor/gems/rspec-1.1.2/MIT-LICENSE vendored Normal file
View file

@ -0,0 +1,20 @@
Copyright (c) 2005-2007 The RSpec Development Team
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

71
vendor/gems/rspec-1.1.2/README vendored Normal file
View file

@ -0,0 +1,71 @@
== RSpec
RSpec is a Behaviour Driven Development framework with tools to express User Stories
with Executable Scenarios and Executable Examples at the code level.
RSpec ships with several modules:
Spec::Story provides a framework for expressing User Stories
Spec::Example provides a framework for expressing code Examples
Spec::Matchers provides Expression Matchers for use with Spec::Expectations
and Spec::Mocks.
Spec::Expectations supports setting expectations on your objects so you
can do things like:
result.should equal(expected_result)
Spec::Mocks supports creating Mock Objects, Stubs, and adding Mock/Stub
behaviour to your existing objects.
== Installation
The simplest approach is to install the gem:
gem install -r rspec #mac users must sudo
== Building the RSpec gem
If you prefer to build the gem locally, check out source from svn://rubyforge.org/var/svn/rspec/trunk. Then
do the following:
rake gem
gem install pkg/rspec-0.x.x.gem (you may have to sudo)
== Running RSpec's specs
In order to run RSpec's full suite of specs (rake pre_commit) you must install the following gems:
* rake # Runs the build script
* rcov # Verifies that the code is 100% covered by specs
* webby # Generates the static HTML website
* syntax # Required to highlight ruby code
* diff-lcs # Required if you use the --diff switch
* win32console # Required by the --colour switch if you're on Windows
* meta_project # Required in order to make releases at RubyForge
* heckle # Required if you use the --heckle switch
* hpricot # Used for parsing HTML from the HTML output formatter in RSpec's own specs
Once those are all installed, you should be able to run the suite with the following steps:
* svn co svn://rubyforge.org/var/svn/rspec/trunk rspec
* cd rspec
* rake install_dependencies
* cd example_rails_app
* export RSPEC_RAILS_VERSION=1.2.3
* rake rspec:generate_mysql_config
* mysql -u root < db/mysql_setup.sql
* cd ..
* rake pre_commit
Note that RSpec itself - once built - doesn't have any dependencies outside the Ruby core
and stdlib - with a few exceptions:
* The spec command line uses diff-lcs when --diff is specified.
* The spec command line uses heckle when --heckle is specified.
* The Spec::Rake::SpecTask needs RCov if RCov is enabled in the task.
See http://rspec.rubyforge.org for further documentation.
== Contributing

276
vendor/gems/rspec-1.1.2/Rakefile vendored Normal file
View file

@ -0,0 +1,276 @@
$:.unshift('lib')
require 'rubygems'
require 'rake/gempackagetask'
require 'rake/contrib/rubyforgepublisher'
require 'rake/clean'
require 'rake/rdoctask'
require 'rake/testtask'
require 'spec/version'
dir = File.dirname(__FILE__)
$LOAD_PATH.unshift(File.expand_path("#{dir}/../pre_commit/lib"))
require "pre_commit"
# Some of the tasks are in separate files since they are also part of the website documentation
load File.dirname(__FILE__) + '/rake_tasks/examples.rake'
load File.dirname(__FILE__) + '/rake_tasks/examples_with_rcov.rake'
load File.dirname(__FILE__) + '/rake_tasks/failing_examples_with_html.rake'
load File.dirname(__FILE__) + '/rake_tasks/verify_rcov.rake'
PKG_NAME = "rspec"
PKG_VERSION = Spec::VERSION::STRING
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
PKG_FILES = FileList[
'[A-Z]*',
'lib/**/*.rb',
'spec/**/*.rb',
'examples/**/*',
'plugins/**/*',
'stories/**/*'
]
task :default => [:verify_rcov]
task :verify_rcov => [:spec, :stories]
desc "Run all specs"
Spec::Rake::SpecTask.new do |t|
t.spec_files = FileList['spec/**/*_spec.rb']
t.spec_opts = ['--options', 'spec.opts']
unless ENV['NO_RCOV']
t.rcov = true
t.rcov_dir = '../doc/output/coverage'
t.rcov_opts = ['--exclude', 'spec\/spec,bin\/spec,examples,\/var\/lib\/gems,\/Library\/Ruby,\.autotest']
end
end
desc "Run all stories"
task :stories do
html = 'story_server/prototype/rspec_stories.html'
ruby "stories/all.rb --colour --format plain --format html:#{html}"
unless IO.read(html) =~ /<span class="param">/m
raise 'highlighted parameters are broken in story HTML'
end
end
desc "Run all specs and store html output in doc/output/report.html"
Spec::Rake::SpecTask.new('spec_html') do |t|
t.spec_files = FileList['spec/**/*_spec.rb', '../../RSpec.tmbundle/Support/spec/*_spec.rb']
t.spec_opts = ['--format html:../doc/output/report.html','--backtrace']
end
desc "Run all failing examples"
Spec::Rake::SpecTask.new('failing_examples') do |t|
t.spec_files = FileList['failing_examples/**/*_spec.rb']
end
desc 'Generate RDoc'
rd = Rake::RDocTask.new do |rdoc|
rdoc.rdoc_dir = '../doc/output/rdoc'
rdoc.options << '--title' << 'RSpec' << '--line-numbers' << '--inline-source' << '--main' << 'README'
rdoc.rdoc_files.include('README', 'CHANGES', 'MIT-LICENSE', 'UPGRADE', 'lib/**/*.rb')
end
spec = Gem::Specification.new do |s|
s.name = PKG_NAME
s.version = PKG_VERSION
s.summary = Spec::VERSION::DESCRIPTION
s.description = <<-EOF
RSpec is a behaviour driven development (BDD) framework for Ruby. RSpec was
created in response to Dave Astels' article _A New Look at Test Driven Development_
which can be read at: http://daveastels.com/index.php?p=5 RSpec is intended to
provide the features discussed in Dave's article.
EOF
s.files = PKG_FILES.to_a
s.require_path = 'lib'
s.has_rdoc = true
s.rdoc_options = rd.options
s.extra_rdoc_files = rd.rdoc_files.reject { |fn| fn =~ /\.rb$|^EXAMPLES.rd$/ }.to_a
s.bindir = 'bin'
s.executables = ['spec', 'spec_translator']
s.default_executable = 'spec'
s.author = "RSpec Development Team"
s.email = "rspec-devel@rubyforge.org"
s.homepage = "http://rspec.rubyforge.org"
s.platform = Gem::Platform::RUBY
s.rubyforge_project = "rspec"
end
Rake::GemPackageTask.new(spec) do |pkg|
pkg.need_zip = true
pkg.need_tar = true
end
def egrep(pattern)
Dir['**/*.rb'].each do |fn|
count = 0
open(fn) do |f|
while line = f.gets
count += 1
if line =~ pattern
puts "#{fn}:#{count}:#{line}"
end
end
end
end
end
desc "Look for TODO and FIXME tags in the code"
task :todo do
egrep /(FIXME|TODO|TBD)/
end
task :clobber do
core.clobber
end
task :release => [:clobber, :verify_committed, :verify_user, :spec, :publish_packages, :tag, :publish_news]
desc "Verifies that there is no uncommitted code"
task :verify_committed do
IO.popen('svn stat') do |io|
io.each_line do |line|
raise "\n!!! Do a svn commit first !!!\n\n" if line =~ /^\s*M\s*/
end
end
end
desc "Creates a tag in svn"
task :tag do
from = `svn info #{File.dirname(__FILE__)}`.match(/URL: (.*)\/rspec/n)[1]
to = from.gsub(/trunk/, "tags/#{Spec::VERSION::TAG}")
current = from.gsub(/trunk/, "tags/CURRENT")
puts "Creating tag in SVN"
tag_cmd = "svn cp #{from} #{to} -m \"Tag release #{Spec::VERSION::FULL_VERSION}\""
`#{tag_cmd}` ; raise "ERROR: #{tag_cmd}" unless $? == 0
puts "Removing CURRENT"
remove_current_cmd = "svn rm #{current} -m \"Remove tags/CURRENT\""
`#{remove_current_cmd}` ; raise "ERROR: #{remove_current_cmd}" unless $? == 0
puts "Re-Creating CURRENT"
create_current_cmd = "svn cp #{to} #{current} -m \"Copy #{Spec::VERSION::TAG} to tags/CURRENT\""
`#{create_current_cmd}` ; "ERROR: #{create_current_cmd}" unless $? == 0
end
desc "Run this task before you commit. You should see 'OK TO COMMIT'"
task(:pre_commit) {core.pre_commit}
desc "Build the website, but do not publish it"
task(:website) {core.website}
task(:rdoc_rails) {core.rdoc_rails}
task :verify_user do
raise "RUBYFORGE_USER environment variable not set!" unless ENV['RUBYFORGE_USER']
end
desc "Upload Website to RubyForge"
task :publish_website => [:verify_user, :website] do
unless Spec::VERSION::RELEASE_CANDIDATE
publisher = Rake::SshDirPublisher.new(
"rspec-website@rubyforge.org",
"/var/www/gforge-projects/#{PKG_NAME}",
"../doc/output"
)
publisher.upload
else
puts "** Not publishing packages to RubyForge - this is a prerelease"
end
end
desc "Upload Website archive to RubyForge"
task :archive_website => [:verify_user, :website] do
publisher = Rake::SshDirPublisher.new(
"rspec-website@rubyforge.org",
"/var/www/gforge-projects/#{PKG_NAME}/#{Spec::VERSION::TAG}",
"../doc/output"
)
publisher.upload
end
desc "Package the Rails plugin"
task :package_rspec_on_rails do
mkdir 'pkg' rescue nil
rm_rf 'pkg/rspec_on_rails' rescue nil
`svn export ../rspec_on_rails pkg/rspec_on_rails-#{PKG_VERSION}`
Dir.chdir 'pkg' do
`tar cvzf rspec_on_rails-#{PKG_VERSION}.tgz rspec_on_rails-#{PKG_VERSION}`
end
end
task :pkg => :package_rspec_on_rails
desc "Package the RSpec.tmbundle"
task :package_tmbundle do
mkdir 'pkg' rescue nil
rm_rf 'pkg/RSpec.tmbundle' rescue nil
`svn export ../RSpec.tmbundle pkg/RSpec.tmbundle`
Dir.chdir 'pkg' do
`tar cvzf RSpec-#{PKG_VERSION}.tmbundle.tgz RSpec.tmbundle`
end
end
task :pkg => :package_tmbundle
desc "Publish gem+tgz+zip on RubyForge. You must make sure lib/version.rb is aligned with the CHANGELOG file"
task :publish_packages => [:verify_user, :package] do
release_files = FileList[
"pkg/#{PKG_FILE_NAME}.gem",
"pkg/#{PKG_FILE_NAME}.tgz",
"pkg/rspec_on_rails-#{PKG_VERSION}.tgz",
"pkg/#{PKG_FILE_NAME}.zip",
"pkg/RSpec-#{PKG_VERSION}.tmbundle.tgz"
]
unless Spec::VERSION::RELEASE_CANDIDATE
require 'meta_project'
require 'rake/contrib/xforge'
Rake::XForge::Release.new(MetaProject::Project::XForge::RubyForge.new(PKG_NAME)) do |xf|
# Never hardcode user name and password in the Rakefile!
xf.user_name = ENV['RUBYFORGE_USER']
xf.files = release_files.to_a
xf.release_name = "RSpec #{PKG_VERSION}"
end
else
puts "SINCE THIS IS A PRERELEASE, FILES ARE UPLOADED WITH SSH, NOT TO THE RUBYFORGE FILE SECTION"
puts "YOU MUST TYPE THE PASSWORD #{release_files.length} TIMES..."
host = "rspec-website@rubyforge.org"
remote_dir = "/var/www/gforge-projects/#{PKG_NAME}"
publisher = Rake::SshFilePublisher.new(
host,
remote_dir,
File.dirname(__FILE__),
*release_files
)
publisher.upload
puts "UPLADED THE FOLLOWING FILES:"
release_files.each do |file|
name = file.match(/pkg\/(.*)/)[1]
puts "* http://rspec.rubyforge.org/#{name}"
end
puts "They are not linked to anywhere, so don't forget to tell people!"
end
end
desc "Publish news on RubyForge"
task :publish_news => [:verify_user] do
unless Spec::VERSION::RELEASE_CANDIDATE
require 'meta_project'
require 'rake/contrib/xforge'
Rake::XForge::NewsPublisher.new(MetaProject::Project::XForge::RubyForge.new(PKG_NAME)) do |news|
# Never hardcode user name and password in the Rakefile!
news.user_name = ENV['RUBYFORGE_USER']
end
else
puts "** Not publishing news to RubyForge - this is a prerelease"
end
end
def core
PreCommit::Core.new(self)
end

2
vendor/gems/rspec-1.1.2/TODO vendored Normal file
View file

@ -0,0 +1,2 @@
=== Before releasing 1.1.0:

31
vendor/gems/rspec-1.1.2/UPGRADE vendored Normal file
View file

@ -0,0 +1,31 @@
= Upgrading existing code to RSpec-0.9
== General (see below for Spec::Rails specifics)
=== New Syntax for should and should_not
* Use translator (should get 90% of your code)
* Manually fix "parenthesis" warnings
=== Change before_context_eval to before_eval
before_context_eval is an un-published hook used by
Spec::Rails to create specialized behaviour contexts.
Most of you don't need to change this, but for those
who have exploited it, you'll need to change it to
before_eval.
== Spec::Rails
=== spec_helper.rb
We've added a new way to configure Spec::Runner to do
things like use_transactional_fixtures and use_instantiated_fixtures.
You'll need to update spec/spec_helper.rb accordingly. You can either
just re-generate it:
script/generate rspec
Or modify spec_helper.rb based on the template, which can be found at:
vendor/plugins/rspec_on_rails/generators/rspec/templates/spec_helper.rb

4
vendor/gems/rspec-1.1.2/bin/spec vendored Normal file
View file

@ -0,0 +1,4 @@
#!/usr/bin/env ruby
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
require 'spec'
exit ::Spec::Runner::CommandLine.run(rspec_options)

View file

@ -0,0 +1,8 @@
#!/usr/bin/env ruby
raise "\n\nUsage: spec_translator from_dir to_dir\n\n" if ARGV.size != 2
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
require 'spec/translator'
t = ::Spec::Translator.new
from = ARGV[0]
to = ARGV[1]
t.translate(from, to)

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,28 @@
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 => 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,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

View file

@ -0,0 +1,3 @@
Autotest.add_discovery do
"rspec" if File.exist?('spec')
end

View file

@ -0,0 +1,88 @@
require 'autotest'
Autotest.add_hook :initialize do |at|
at.clear_mappings
# watch out: Ruby bug (1.8.6):
# %r(/) != /\//
at.add_mapping(%r%^spec/.*\.rb$%) { |filename, _|
filename
}
at.add_mapping(%r%^lib/(.*)\.rb$%) { |_, m|
["spec/#{m[1]}_spec.rb"]
}
at.add_mapping(%r%^spec/(spec_helper|shared/.*)\.rb$%) {
at.files_matching %r%^spec/.*_spec\.rb$%
}
end
class RspecCommandError < StandardError; end
class Autotest::Rspec < Autotest
def tests_for_file(filename)
super.select { |f| @files.has_key? f }
end
alias :specs_for_file :tests_for_file
def failed_results(results)
results.scan(/^\d+\)\n(?:\e\[\d*m)?(?:.*?Error in )?'([^\n]*)'(?: FAILED)?(?:\e\[\d*m)?\n(.*?)\n\n/m)
end
def handle_results(results)
@files_to_test = consolidate_failures failed_results(results)
unless @files_to_test.empty? then
hook :red
else
hook :green
end unless $TESTING
@tainted = true unless @files_to_test.empty?
end
def consolidate_failures(failed)
filters = Hash.new { |h,k| h[k] = [] }
failed.each do |spec, failed_trace|
@files.keys.select{|f| f =~ /spec\//}.each do |f|
if failed_trace =~ Regexp.new(f)
filters[f] << spec
break
end
end
end
return filters
end
def make_test_cmd(files_to_test)
return "#{ruby} -S #{spec_command} #{add_options_if_present} #{files_to_test.keys.flatten.join(' ')}"
end
def add_options_if_present
File.exist?("spec/spec.opts") ? "-O spec/spec.opts " : ""
end
# Finds the proper spec command to use. Precendence
# is set in the lazily-evaluated method spec_commands. Alias + Override
# that in ~/.autotest to provide a different spec command
# then the default paths provided.
def spec_command
@spec_command ||= spec_commands.each do |command|
if File.exists?(command)
return @alt_separator ? (command.gsub @separator, @alt_separator) : command
end
end
raise RspecCommandError, "No spec command could be found!"
end
# Autotest will look for spec commands in the following
# locations, in this order:
#
# * bin/spec
# * default spec bin/loader installed in Rubygems
def spec_commands
[
File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'bin', 'spec')),
File.join(Config::CONFIG['bindir'], 'spec')
]
end
end

37
vendor/gems/rspec-1.1.2/lib/spec.rb vendored Normal file
View file

@ -0,0 +1,37 @@
require 'spec/version'
require 'spec/matchers'
require 'spec/expectations'
require 'spec/example'
require 'spec/extensions'
require 'spec/runner'
if Object.const_defined?(:Test); \
require 'spec/interop/test'; \
end
module Spec
class << self
def run?
@run || rspec_options.examples_run?
end
def run; \
return true if run?; \
result = rspec_options.run_examples; \
@run = true; \
result; \
end
attr_writer :run
def exit?; \
!Object.const_defined?(:Test) || Test::Unit.run?; \
end
end
end
at_exit do \
unless $! || Spec.run?; \
success = Spec.run; \
exit success if Spec.exit?; \
end \
end

View file

@ -0,0 +1,12 @@
require 'timeout'
require 'forwardable'
require 'spec/example/pending'
require 'spec/example/module_reopening_fix'
require 'spec/example/example_group_methods'
require 'spec/example/example_methods'
require 'spec/example/example_group'
require 'spec/example/shared_example_group'
require 'spec/example/example_group_factory'
require 'spec/example/errors'
require 'spec/example/configuration'
require 'spec/example/example_matcher'

View file

@ -0,0 +1,144 @@
module Spec
module Example
class Configuration
# Chooses what mock framework to use. Example:
#
# Spec::Runner.configure do |config|
# config.mock_with :rspec, :mocha, :flexmock, or :rr
# end
#
# To use any other mock framework, you'll have to provide
# your own adapter. This is simply a module that responds to
# setup_mocks_for_rspec, verify_mocks_for_rspec and teardown_mocks_for_rspec.
# These are your hooks into the lifecycle of a given example. RSpec will
# call setup_mocks_for_rspec before running anything else in each Example.
# After executing the #after methods, RSpec will then call verify_mocks_for_rspec
# and teardown_mocks_for_rspec (this is guaranteed to run even if there are
# failures in verify_mocks_for_rspec).
#
# Once you've defined this module, you can pass that to mock_with:
#
# Spec::Runner.configure do |config|
# config.mock_with MyMockFrameworkAdapter
# end
#
def mock_with(mock_framework)
@mock_framework = case mock_framework
when Symbol
mock_framework_path(mock_framework.to_s)
else
mock_framework
end
end
def mock_framework # :nodoc:
@mock_framework ||= mock_framework_path("rspec")
end
# Declares modules to be included in all example groups (<tt>describe</tt> blocks).
#
# config.include(My::Bottle, My::Cup)
#
# If you want to restrict the inclusion to a subset of all the example groups then
# specify this in a Hash as the last argument:
#
# config.include(My::Pony, My::Horse, :type => :farm)
#
# Only example groups that have that type will get the modules included:
#
# describe "Downtown", :type => :city do
# # Will *not* get My::Pony and My::Horse included
# end
#
# describe "Old Mac Donald", :type => :farm do
# # *Will* get My::Pony and My::Horse included
# end
#
def include(*args)
args << {} unless Hash === args.last
modules, options = args_and_options(*args)
required_example_group = get_type_from_options(options)
required_example_group = required_example_group.to_sym if required_example_group
modules.each do |mod|
ExampleGroupFactory.get(required_example_group).send(:include, mod)
end
end
# Defines global predicate matchers. Example:
#
# config.predicate_matchers[:swim] = :can_swim?
#
# This makes it possible to say:
#
# person.should swim # passes if person.should_swim? returns true
#
def predicate_matchers
@predicate_matchers ||= {}
end
# Prepends a global <tt>before</tt> block to all example groups.
# See #append_before for filtering semantics.
def prepend_before(*args, &proc)
scope, options = scope_and_options(*args)
example_group = ExampleGroupFactory.get(
get_type_from_options(options)
)
example_group.prepend_before(scope, &proc)
end
# Appends a global <tt>before</tt> block to all example groups.
#
# If you want to restrict the block to a subset of all the example groups then
# specify this in a Hash as the last argument:
#
# config.prepend_before(:all, :type => :farm)
#
# or
#
# config.prepend_before(:type => :farm)
#
def append_before(*args, &proc)
scope, options = scope_and_options(*args)
example_group = ExampleGroupFactory.get(
get_type_from_options(options)
)
example_group.append_before(scope, &proc)
end
alias_method :before, :append_before
# Prepends a global <tt>after</tt> block to all example groups.
# See #append_before for filtering semantics.
def prepend_after(*args, &proc)
scope, options = scope_and_options(*args)
example_group = ExampleGroupFactory.get(
get_type_from_options(options)
)
example_group.prepend_after(scope, &proc)
end
alias_method :after, :prepend_after
# Appends a global <tt>after</tt> block to all example groups.
# See #append_before for filtering semantics.
def append_after(*args, &proc)
scope, options = scope_and_options(*args)
example_group = ExampleGroupFactory.get(
get_type_from_options(options)
)
example_group.append_after(scope, &proc)
end
private
def scope_and_options(*args)
args, options = args_and_options(*args)
scope = (args[0] || :each), options
end
def get_type_from_options(options)
options[:type] || options[:behaviour_type]
end
def mock_framework_path(framework_name)
File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "plugins", "mock_frameworks", framework_name))
end
end
end
end

View file

@ -0,0 +1,9 @@
module Spec
module Example
class ExamplePendingError < StandardError
end
class PendingExampleFixedError < StandardError
end
end
end

View file

@ -0,0 +1,16 @@
module Spec
module Example
# The superclass for all regular RSpec examples.
class ExampleGroup
extend Spec::Example::ExampleGroupMethods
include Spec::Example::ExampleMethods
def initialize(defined_description, &implementation)
@_defined_description = defined_description
@_implementation = implementation
end
end
end
end
Spec::ExampleGroup = Spec::Example::ExampleGroup

View file

@ -0,0 +1,62 @@
module Spec
module Example
class ExampleGroupFactory
class << self
def reset
@example_group_types = nil
default(ExampleGroup)
end
# Registers an example group class +klass+ with the symbol
# +type+. For example:
#
# Spec::Example::ExampleGroupFactory.register(:farm, Spec::Farm::Example::FarmExampleGroup)
#
# This will cause Main#describe from a file living in
# <tt>spec/farm</tt> to create example group instances of type
# Spec::Farm::Example::FarmExampleGroup.
def register(id, example_group_class)
@example_group_types[id] = example_group_class
end
# Sets the default ExampleGroup class
def default(example_group_class)
old = @example_group_types
@example_group_types = Hash.new(example_group_class)
@example_group_types.merge(old) if old
end
def get(id=nil)
if @example_group_types.values.include?(id)
id
else
@example_group_types[id]
end
end
def create_example_group(*args, &block)
opts = Hash === args.last ? args.last : {}
if opts[:shared]
SharedExampleGroup.new(*args, &block)
else
superclass = determine_superclass(opts)
superclass.describe(*args, &block)
end
end
protected
def determine_superclass(opts)
id = if opts[:type]
opts[:type]
elsif opts[:spec_path] =~ /spec(\\|\/)(#{@example_group_types.keys.join('|')})/
$2 == '' ? nil : $2.to_sym
end
get(id)
end
end
self.reset
end
end
end

View file

@ -0,0 +1,418 @@
module Spec
module Example
module ExampleGroupMethods
class << self
def description_text(*args)
args.inject("") do |result, arg|
result << " " unless (result == "" || arg.to_s =~ /^(\s|\.|#)/)
result << arg.to_s
end
end
end
attr_reader :description_text, :description_args, :description_options, :spec_path
def inherited(klass)
super
klass.register
end
# Makes the describe/it syntax available from a class. For example:
#
# class StackSpec < Spec::ExampleGroup
# describe Stack, "with no elements"
#
# before
# @stack = Stack.new
# end
#
# it "should raise on pop" do
# lambda{ @stack.pop }.should raise_error
# end
# end
#
def describe(*args, &example_group_block)
if example_group_block
self.subclass("Subclass") do
describe(*args)
module_eval(&example_group_block)
end
else
set_description(*args)
before_eval
self
end
end
# Use this to pull in examples from shared example groups.
# See Spec::Runner for information about shared example groups.
def it_should_behave_like(shared_example_group)
case shared_example_group
when SharedExampleGroup
include shared_example_group
else
example_group = SharedExampleGroup.find_shared_example_group(shared_example_group)
unless example_group
raise RuntimeError.new("Shared Example Group '#{shared_example_group}' can not be found")
end
include(example_group)
end
end
# :call-seq:
# predicate_matchers[matcher_name] = method_on_object
# predicate_matchers[matcher_name] = [method1_on_object, method2_on_object]
#
# Dynamically generates a custom matcher that will match
# a predicate on your class. RSpec provides a couple of these
# out of the box:
#
# exist (or state expectations)
# File.should exist("path/to/file")
#
# an_instance_of (for mock argument constraints)
# mock.should_receive(:message).with(an_instance_of(String))
#
# == Examples
#
# class Fish
# def can_swim?
# true
# end
# end
#
# describe Fish do
# predicate_matchers[:swim] = :can_swim?
# it "should swim" do
# Fish.new.should swim
# end
# end
def predicate_matchers
@predicate_matchers ||= {:an_instance_of => :is_a?}
end
# Creates an instance of Spec::Example::Example and adds
# it to a collection of examples of the current example group.
def it(description=nil, &implementation)
e = new(description, &implementation)
example_objects << e
e
end
alias_method :specify, :it
# Use this to temporarily disable an example.
def xit(description=nil, opts={}, &block)
Kernel.warn("Example disabled: #{description}")
end
def run
examples = examples_to_run
return true if examples.empty?
reporter.add_example_group(self)
return dry_run(examples) if dry_run?
plugin_mock_framework
define_methods_from_predicate_matchers
success, before_all_instance_variables = run_before_all
success, after_all_instance_variables = execute_examples(success, before_all_instance_variables, examples)
success = run_after_all(success, after_all_instance_variables)
end
def description
result = ExampleGroupMethods.description_text(*description_parts)
if result.nil? || result == ""
return to_s
else
result
end
end
def described_type
description_parts.find {|part| part.is_a?(Module)}
end
def description_parts #:nodoc:
parts = []
execute_in_class_hierarchy do |example_group|
parts << example_group.description_args
end
parts.flatten.compact
end
def set_description(*args)
args, options = args_and_options(*args)
@description_args = args
@description_options = options
@description_text = ExampleGroupMethods.description_text(*args)
@spec_path = File.expand_path(options[:spec_path]) if options[:spec_path]
if described_type.class == Module
include described_type
end
self
end
def examples #:nodoc:
examples = example_objects.dup
add_method_examples(examples)
rspec_options.reverse ? examples.reverse : examples
end
def number_of_examples #:nodoc:
examples.length
end
# Registers a block to be executed before each example.
# This method prepends +block+ to existing before blocks.
def prepend_before(*args, &block)
scope, options = scope_and_options(*args)
parts = before_parts_from_scope(scope)
parts.unshift(block)
end
# Registers a block to be executed before each example.
# This method appends +block+ to existing before blocks.
def append_before(*args, &block)
scope, options = scope_and_options(*args)
parts = before_parts_from_scope(scope)
parts << block
end
alias_method :before, :append_before
# Registers a block to be executed after each example.
# This method prepends +block+ to existing after blocks.
def prepend_after(*args, &block)
scope, options = scope_and_options(*args)
parts = after_parts_from_scope(scope)
parts.unshift(block)
end
alias_method :after, :prepend_after
# Registers a block to be executed after each example.
# This method appends +block+ to existing after blocks.
def append_after(*args, &block)
scope, options = scope_and_options(*args)
parts = after_parts_from_scope(scope)
parts << block
end
def remove_after(scope, &block)
after_each_parts.delete(block)
end
# Deprecated. Use before(:each)
def setup(&block)
before(:each, &block)
end
# Deprecated. Use after(:each)
def teardown(&block)
after(:each, &block)
end
def before_all_parts # :nodoc:
@before_all_parts ||= []
end
def after_all_parts # :nodoc:
@after_all_parts ||= []
end
def before_each_parts # :nodoc:
@before_each_parts ||= []
end
def after_each_parts # :nodoc:
@after_each_parts ||= []
end
# Only used from RSpec's own examples
def reset # :nodoc:
@before_all_parts = nil
@after_all_parts = nil
@before_each_parts = nil
@after_each_parts = nil
end
def register
rspec_options.add_example_group self
end
def unregister #:nodoc:
rspec_options.remove_example_group self
end
def run_before_each(example)
execute_in_class_hierarchy do |example_group|
example.eval_each_fail_fast(example_group.before_each_parts)
end
end
def run_after_each(example)
execute_in_class_hierarchy(:superclass_first) do |example_group|
example.eval_each_fail_slow(example_group.after_each_parts)
end
end
private
def dry_run(examples)
examples.each do |example|
rspec_options.reporter.example_started(example)
rspec_options.reporter.example_finished(example)
end
return true
end
def run_before_all
before_all = new("before(:all)")
begin
execute_in_class_hierarchy do |example_group|
before_all.eval_each_fail_fast(example_group.before_all_parts)
end
return [true, before_all.instance_variable_hash]
rescue Exception => e
reporter.failure(before_all, e)
return [false, before_all.instance_variable_hash]
end
end
def execute_examples(success, instance_variables, examples)
return [success, instance_variables] unless success
after_all_instance_variables = instance_variables
examples.each do |example_group_instance|
success &= example_group_instance.execute(rspec_options, instance_variables)
after_all_instance_variables = example_group_instance.instance_variable_hash
end
return [success, after_all_instance_variables]
end
def run_after_all(success, instance_variables)
after_all = new("after(:all)")
after_all.set_instance_variables_from_hash(instance_variables)
execute_in_class_hierarchy(:superclass_first) do |example_group|
after_all.eval_each_fail_slow(example_group.after_all_parts)
end
return success
rescue Exception => e
reporter.failure(after_all, e)
return false
end
def examples_to_run
all_examples = examples
return all_examples unless specified_examples?
all_examples.reject do |example|
matcher = ExampleMatcher.new(description.to_s, example.description)
!matcher.matches?(specified_examples)
end
end
def specified_examples?
specified_examples && !specified_examples.empty?
end
def specified_examples
rspec_options.examples
end
def reporter
rspec_options.reporter
end
def dry_run?
rspec_options.dry_run
end
def example_objects
@example_objects ||= []
end
def execute_in_class_hierarchy(superclass_last=false)
classes = []
current_class = self
while is_example_group?(current_class)
superclass_last ? classes << current_class : classes.unshift(current_class)
current_class = current_class.superclass
end
superclass_last ? classes << ExampleMethods : classes.unshift(ExampleMethods)
classes.each do |example_group|
yield example_group
end
end
def is_example_group?(klass)
Module === klass && klass.kind_of?(ExampleGroupMethods)
end
def plugin_mock_framework
case mock_framework = Spec::Runner.configuration.mock_framework
when Module
include mock_framework
else
require Spec::Runner.configuration.mock_framework
include Spec::Plugins::MockFramework
end
end
def define_methods_from_predicate_matchers # :nodoc:
all_predicate_matchers = predicate_matchers.merge(
Spec::Runner.configuration.predicate_matchers
)
all_predicate_matchers.each_pair do |matcher_method, method_on_object|
define_method matcher_method do |*args|
eval("be_#{method_on_object.to_s.gsub('?','')}(*args)")
end
end
end
def scope_and_options(*args)
args, options = args_and_options(*args)
scope = (args[0] || :each), options
end
def before_parts_from_scope(scope)
case scope
when :each; before_each_parts
when :all; before_all_parts
end
end
def after_parts_from_scope(scope)
case scope
when :each; after_each_parts
when :all; after_all_parts
end
end
def before_eval
end
def add_method_examples(examples)
instance_methods.sort.each do |method_name|
if example_method?(method_name)
examples << new(method_name) do
__send__(method_name)
end
end
end
end
def example_method?(method_name)
should_method?(method_name)
end
def should_method?(method_name)
!(method_name =~ /^should(_not)?$/) &&
method_name =~ /^should/ && (
instance_method(method_name).arity == 0 ||
instance_method(method_name).arity == -1
)
end
end
end
end

View file

@ -0,0 +1,42 @@
module Spec
module Example
class ExampleMatcher
def initialize(example_group_description, example_name)
@example_group_description = example_group_description
@example_name = example_name
end
def matches?(specified_examples)
specified_examples.each do |specified_example|
return true if matches_literal_example?(specified_example) || matches_example_not_considering_modules?(specified_example)
end
false
end
protected
def matches_literal_example?(specified_example)
specified_example =~ /(^#{example_group_regex} #{example_regexp}$|^#{example_group_regex}$|^#{example_group_with_before_all_regexp}$|^#{example_regexp}$)/
end
def matches_example_not_considering_modules?(specified_example)
specified_example =~ /(^#{example_group_regex_not_considering_modules} #{example_regexp}$|^#{example_group_regex_not_considering_modules}$|^#{example_regexp}$)/
end
def example_group_regex
Regexp.escape(@example_group_description)
end
def example_group_with_before_all_regexp
Regexp.escape("#{@example_group_description} before(:all)")
end
def example_group_regex_not_considering_modules
Regexp.escape(@example_group_description.split('::').last)
end
def example_regexp
Regexp.escape(@example_name)
end
end
end
end

View file

@ -0,0 +1,102 @@
module Spec
module Example
module ExampleMethods
extend ExampleGroupMethods
extend ModuleReopeningFix
PENDING_EXAMPLE_BLOCK = lambda {
raise Spec::Example::ExamplePendingError.new("Not Yet Implemented")
}
def execute(options, instance_variables)
options.reporter.example_started(self)
set_instance_variables_from_hash(instance_variables)
execution_error = nil
Timeout.timeout(options.timeout) do
begin
before_example
run_with_description_capturing
rescue Exception => e
execution_error ||= e
end
begin
after_example
rescue Exception => e
execution_error ||= e
end
end
options.reporter.example_finished(self, execution_error)
success = execution_error.nil? || ExamplePendingError === execution_error
end
def instance_variable_hash
instance_variables.inject({}) do |variable_hash, variable_name|
variable_hash[variable_name] = instance_variable_get(variable_name)
variable_hash
end
end
def violated(message="")
raise Spec::Expectations::ExpectationNotMetError.new(message)
end
def eval_each_fail_fast(procs) #:nodoc:
procs.each do |proc|
instance_eval(&proc)
end
end
def eval_each_fail_slow(procs) #:nodoc:
first_exception = nil
procs.each do |proc|
begin
instance_eval(&proc)
rescue Exception => e
first_exception ||= e
end
end
raise first_exception if first_exception
end
def description
@_defined_description || @_matcher_description || "NO NAME"
end
def set_instance_variables_from_hash(ivars)
ivars.each do |variable_name, value|
# Ruby 1.9 requires variable.to_s on the next line
unless ['@_implementation', '@_defined_description', '@_matcher_description', '@method_name'].include?(variable_name.to_s)
instance_variable_set variable_name, value
end
end
end
def run_with_description_capturing
begin
return instance_eval(&(@_implementation || PENDING_EXAMPLE_BLOCK))
ensure
@_matcher_description = Spec::Matchers.generated_description
Spec::Matchers.clear_generated_description
end
end
protected
include Matchers
include Pending
def before_example
setup_mocks_for_rspec
self.class.run_before_each(self)
end
def after_example
self.class.run_after_each(self)
verify_mocks_for_rspec
ensure
teardown_mocks_for_rspec
end
end
end
end

View file

@ -0,0 +1,21 @@
module Spec
module Example
# This is a fix for ...Something in Ruby 1.8.6??... (Someone fill in here please - Aslak)
module ModuleReopeningFix
def child_modules
@child_modules ||= []
end
def included(mod)
child_modules << mod
end
def include(mod)
super
child_modules.each do |child_module|
child_module.__send__(:include, mod)
end
end
end
end
end

View file

@ -0,0 +1,18 @@
module Spec
module Example
module Pending
def pending(message = "TODO")
if block_given?
begin
yield
rescue Exception => e
raise Spec::Example::ExamplePendingError.new(message)
end
raise Spec::Example::PendingExampleFixedError.new("Expected pending '#{message}' to fail. No Error was raised.")
else
raise Spec::Example::ExamplePendingError.new(message)
end
end
end
end
end

View file

@ -0,0 +1,58 @@
module Spec
module Example
class SharedExampleGroup < Module
class << self
def add_shared_example_group(new_example_group)
guard_against_redefining_existing_example_group(new_example_group)
shared_example_groups << new_example_group
end
def find_shared_example_group(example_group_description)
shared_example_groups.find do |b|
b.description == example_group_description
end
end
def shared_example_groups
# TODO - this needs to be global, or at least accessible from
# from subclasses of Example in a centralized place. I'm not loving
# this as a solution, but it works for now.
$shared_example_groups ||= []
end
private
def guard_against_redefining_existing_example_group(new_example_group)
existing_example_group = find_shared_example_group(new_example_group.description)
return unless existing_example_group
return if new_example_group.equal?(existing_example_group)
return if spec_path(new_example_group) == spec_path(existing_example_group)
raise ArgumentError.new("Shared Example '#{existing_example_group.description}' already exists")
end
def spec_path(example_group)
File.expand_path(example_group.spec_path)
end
end
include ExampleGroupMethods
public :include
def initialize(*args, &example_group_block)
describe(*args)
@example_group_block = example_group_block
self.class.add_shared_example_group(self)
end
def included(mod) # :nodoc:
mod.module_eval(&@example_group_block)
end
def execute_in_class_hierarchy(superclass_last=false)
classes = [self]
superclass_last ? classes << ExampleMethods : classes.unshift(ExampleMethods)
classes.each do |example_group|
yield example_group
end
end
end
end
end

View file

@ -0,0 +1,56 @@
require 'spec/matchers'
require 'spec/expectations/errors'
require 'spec/expectations/extensions'
require 'spec/expectations/handler'
module Spec
# Spec::Expectations lets you set expectations on your objects.
#
# result.should == 37
# team.should have(11).players_on_the_field
#
# == How Expectations work.
#
# Spec::Expectations adds two methods to Object:
#
# should(matcher=nil)
# should_not(matcher=nil)
#
# Both methods take an optional Expression Matcher (See Spec::Matchers).
#
# When +should+ receives an Expression Matcher, it calls <tt>matches?(self)</tt>. If
# it returns +true+, the spec passes and execution continues. If it returns
# +false+, then the spec fails with the message returned by <tt>matcher.failure_message</tt>.
#
# Similarly, when +should_not+ receives a matcher, it calls <tt>matches?(self)</tt>. If
# it returns +false+, the spec passes and execution continues. If it returns
# +true+, then the spec fails with the message returned by <tt>matcher.negative_failure_message</tt>.
#
# RSpec ships with a standard set of useful matchers, and writing your own
# matchers is quite simple. See Spec::Matchers for details.
module Expectations
class << self
attr_accessor :differ
# raises a Spec::Expectations::ExpectationNotMetError with message
#
# When a differ has been assigned and fail_with is passed
# <code>expected</code> and <code>target</code>, passes them
# to the differ to append a diff message to the failure message.
def fail_with(message, expected=nil, target=nil) # :nodoc:
if Array === message && message.length == 3
message, expected, target = message[0], message[1], message[2]
end
unless (differ.nil? || expected.nil? || target.nil?)
if expected.is_a?(String)
message << "\nDiff:" << self.differ.diff_as_string(target.to_s, expected)
elsif !target.is_a?(Proc)
message << "\nDiff:" << self.differ.diff_as_object(target, expected)
end
end
Kernel::raise(Spec::Expectations::ExpectationNotMetError.new(message))
end
end
end
end

View file

@ -0,0 +1,66 @@
begin
require 'rubygems'
require 'diff/lcs' #necessary due to loading bug on some machines - not sure why - DaC
require 'diff/lcs/hunk'
rescue LoadError ; raise "You must gem install diff-lcs to use diffing" ; end
require 'pp'
module Spec
module Expectations
module Differs
# TODO add some rdoc
class Default
def initialize(options)
@options = options
end
# This is snagged from diff/lcs/ldiff.rb (which is a commandline tool)
def diff_as_string(data_old, data_new)
data_old = data_old.split(/\n/).map! { |e| e.chomp }
data_new = data_new.split(/\n/).map! { |e| e.chomp }
output = ""
diffs = Diff::LCS.diff(data_old, data_new)
return output if diffs.empty?
oldhunk = hunk = nil
file_length_difference = 0
diffs.each do |piece|
begin
hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, context_lines,
file_length_difference)
file_length_difference = hunk.file_length_difference
next unless oldhunk
# Hunks may overlap, which is why we need to be careful when our
# diff includes lines of context. Otherwise, we might print
# redundant lines.
if (context_lines > 0) and hunk.overlaps?(oldhunk)
hunk.unshift(oldhunk)
else
output << oldhunk.diff(format)
end
ensure
oldhunk = hunk
output << "\n"
end
end
#Handle the last remaining hunk
output << oldhunk.diff(format) << "\n"
end
def diff_as_object(target,expected)
diff_as_string(PP.pp(target,""), PP.pp(expected,""))
end
protected
def format
@options.diff_format
end
def context_lines
@options.context_lines
end
end
end
end
end

View file

@ -0,0 +1,12 @@
module Spec
module Expectations
# If Test::Unit is loaed, we'll use its error as baseclass, so that Test::Unit
# will report unmet RSpec expectations as failures rather than errors.
superclass = ['Test::Unit::AssertionFailedError', '::StandardError'].map do |c|
eval(c) rescue nil
end.compact.first
class ExpectationNotMetError < superclass
end
end
end

View file

@ -0,0 +1,2 @@
require 'spec/expectations/extensions/object'
require 'spec/expectations/extensions/string_and_symbol'

View file

@ -0,0 +1,71 @@
module Spec
module Expectations
# rspec adds #should and #should_not to every Object (and,
# implicitly, every Class).
module ObjectExpectations
# :call-seq:
# should(matcher)
# should == expected
# should === expected
# should =~ expected
#
# receiver.should(matcher)
# => Passes if matcher.matches?(receiver)
#
# receiver.should == expected #any value
# => Passes if (receiver == expected)
#
# receiver.should === expected #any value
# => Passes if (receiver === expected)
#
# receiver.should =~ regexp
# => Passes if (receiver =~ regexp)
#
# See Spec::Matchers for more information about matchers
#
# == Warning
#
# NOTE that this does NOT support receiver.should != expected.
# Instead, use receiver.should_not == expected
def should(matcher = :default_parameter, &block)
if :default_parameter == matcher
Spec::Matchers::PositiveOperatorMatcher.new(self)
else
ExpectationMatcherHandler.handle_matcher(self, matcher, &block)
end
end
# :call-seq:
# should_not(matcher)
# should_not == expected
# should_not === expected
# should_not =~ expected
#
# receiver.should_not(matcher)
# => Passes unless matcher.matches?(receiver)
#
# receiver.should_not == expected
# => Passes unless (receiver == expected)
#
# receiver.should_not === expected
# => Passes unless (receiver === expected)
#
# receiver.should_not =~ regexp
# => Passes unless (receiver =~ regexp)
#
# See Spec::Matchers for more information about matchers
def should_not(matcher = :default_parameter, &block)
if :default_parameter == matcher
Spec::Matchers::NegativeOperatorMatcher.new(self)
else
NegativeExpectationMatcherHandler.handle_matcher(self, matcher, &block)
end
end
end
end
end
class Object
include Spec::Expectations::ObjectExpectations
end

View file

@ -0,0 +1,17 @@
module Spec
module Expectations
module StringHelpers
def starts_with?(prefix)
to_s[0..(prefix.to_s.length - 1)] == prefix.to_s
end
end
end
end
class String
include Spec::Expectations::StringHelpers
end
class Symbol
include Spec::Expectations::StringHelpers
end

View file

@ -0,0 +1,52 @@
module Spec
module Expectations
class InvalidMatcherError < ArgumentError; end
module MatcherHandlerHelper
def describe_matcher(matcher)
matcher.respond_to?(:description) ? matcher.description : "[#{matcher.class.name} does not provide a description]"
end
end
class ExpectationMatcherHandler
class << self
include MatcherHandlerHelper
def handle_matcher(actual, matcher, &block)
unless matcher.respond_to?(:matches?)
raise InvalidMatcherError, "Expected a matcher, got #{matcher.inspect}."
end
match = matcher.matches?(actual, &block)
::Spec::Matchers.generated_description = "should #{describe_matcher(matcher)}"
Spec::Expectations.fail_with(matcher.failure_message) unless match
end
end
end
class NegativeExpectationMatcherHandler
class << self
include MatcherHandlerHelper
def handle_matcher(actual, matcher, &block)
unless matcher.respond_to?(:matches?)
raise InvalidMatcherError, "Expected a matcher, got #{matcher.inspect}."
end
unless matcher.respond_to?(:negative_failure_message)
Spec::Expectations.fail_with(
<<-EOF
Matcher does not support should_not.
See Spec::Matchers for more information
about matchers.
EOF
)
end
match = matcher.matches?(actual, &block)
::Spec::Matchers.generated_description = "should not #{describe_matcher(matcher)}"
Spec::Expectations.fail_with(matcher.negative_failure_message) if match
end
end
end
end
end

View file

@ -0,0 +1,3 @@
require 'spec/extensions/object'
require 'spec/extensions/class'
require 'spec/extensions/main'

View file

@ -0,0 +1,24 @@
class Class
# Creates a new subclass of self, with a name "under" our own name.
# Example:
#
# x = Foo::Bar.subclass('Zap'){}
# x.name # => Foo::Bar::Zap_1
# x.superclass.name # => Foo::Bar
def subclass(base_name, &body)
klass = Class.new(self)
class_name = "#{base_name}_#{class_count!}"
instance_eval do
const_set(class_name, klass)
end
klass.instance_eval(&body)
klass
end
private
def class_count!
@class_count ||= 0
@class_count += 1
@class_count
end
end

View file

@ -0,0 +1,102 @@
module Spec
module Extensions
module Main
# Creates and returns a class that includes the ExampleGroupMethods
# module. Which ExampleGroup type is created depends on the directory of the file
# calling this method. For example, Spec::Rails will use different
# classes for specs living in <tt>spec/models</tt>,
# <tt>spec/helpers</tt>, <tt>spec/views</tt> and
# <tt>spec/controllers</tt>.
#
# It is also possible to override autodiscovery of the example group
# type with an options Hash as the last argument:
#
# describe "name", :type => :something_special do ...
#
# The reason for using different behaviour classes is to have different
# matcher methods available from within the <tt>describe</tt> block.
#
# See Spec::Example::ExampleFactory#register for details about how to
# register special implementations.
#
def describe(*args, &block)
raise ArgumentError if args.empty?
raise ArgumentError unless block
args << {} unless Hash === args.last
args.last[:spec_path] = caller(0)[1]
Spec::Example::ExampleGroupFactory.create_example_group(*args, &block)
end
alias :context :describe
# Creates an example group that can be shared by other example groups
#
# == Examples
#
# share_examples_for "All Editions" do
# it "all editions behaviour" ...
# end
#
# describe SmallEdition do
# it_should_behave_like "All Editions"
#
# it "should do small edition stuff" do
# ...
# end
# end
def share_examples_for(name, &block)
describe(name, :shared => true, &block)
end
alias :shared_examples_for :share_examples_for
# Creates a Shared Example Group and assigns it to a constant
#
# share_as :AllEditions do
# it "should do all editions stuff" ...
# end
#
# describe SmallEdition do
# it_should_behave_like AllEditions
#
# it "should do small edition stuff" do
# ...
# end
# end
#
# And, for those of you who prefer to use something more like Ruby, you
# can just include the module directly
#
# describe SmallEdition do
# include AllEditions
#
# it "should do small edition stuff" do
# ...
# end
# end
def share_as(name, &block)
begin
Object.const_set(name, share_examples_for(name, &block))
rescue NameError => e
raise NameError.new(e.message + "\nThe first argument to share_as must be a legal name for a constant\n")
end
end
private
def rspec_options
$rspec_options ||= begin; \
parser = ::Spec::Runner::OptionParser.new(STDERR, STDOUT); \
parser.order!(ARGV); \
$rspec_options = parser.options; \
end
$rspec_options
end
def init_rspec_options(options)
$rspec_options = options if $rspec_options.nil?
end
end
end
end
include Spec::Extensions::Main

View file

@ -0,0 +1,10 @@
class Object
def args_and_options(*args)
options = Hash === args.last ? args.pop : {}
return args, options
end
def metaclass
class << self; self; end
end
end

View file

@ -0,0 +1,10 @@
require 'test/unit'
require 'test/unit/testresult'
require 'spec/interop/test/unit/testcase'
require 'spec/interop/test/unit/testsuite_adapter'
require 'spec/interop/test/unit/autorunner'
require 'spec/interop/test/unit/testresult'
require 'spec/interop/test/unit/ui/console/testrunner'
Spec::Example::ExampleGroupFactory.default(Test::Unit::TestCase)

View file

@ -0,0 +1,6 @@
class Test::Unit::AutoRunner
remove_method :process_args
def process_args(argv)
true
end
end

View file

@ -0,0 +1,61 @@
require 'test/unit/testcase'
module Test
module Unit
# This extension of the standard Test::Unit::TestCase makes RSpec
# available from within, so that you can do things like:
#
# require 'test/unit'
# require 'spec'
#
# class MyTest < Test::Unit::TestCase
# it "should work with Test::Unit assertions" do
# assert_equal 4, 2+1
# end
#
# def test_should_work_with_rspec_expectations
# (3+1).should == 5
# end
# end
#
# See also Spec::Example::ExampleGroup
class TestCase
extend Spec::Example::ExampleGroupMethods
include Spec::Example::ExampleMethods
before(:each) {setup}
after(:each) {teardown}
class << self
def suite
Test::Unit::TestSuiteAdapter.new(self)
end
def example_method?(method_name)
should_method?(method_name) || test_method?(method_name)
end
def test_method?(method_name)
method_name =~ /^test[_A-Z]./ && (
instance_method(method_name).arity == 0 ||
instance_method(method_name).arity == -1
)
end
end
def initialize(defined_description, &implementation)
@_defined_description = defined_description
@_implementation = implementation
@_result = ::Test::Unit::TestResult.new
# @method_name is important to set here because it "complies" with Test::Unit's interface.
# Some Test::Unit extensions depend on @method_name being present.
@method_name = @_defined_description
end
def run(ignore_this_argument=nil)
super()
end
end
end
end

View file

@ -0,0 +1,6 @@
class Test::Unit::TestResult
alias_method :tu_passed?, :passed?
def passed?
return tu_passed? & ::Spec.run
end
end

View file

@ -0,0 +1,34 @@
module Test
module Unit
class TestSuiteAdapter < TestSuite
attr_reader :example_group, :examples
alias_method :tests, :examples
def initialize(example_group)
@example_group = example_group
@examples = example_group.examples
end
def name
example_group.description
end
def run(*args)
return true unless args.empty?
example_group.run
end
def size
example_group.number_of_examples
end
def delete(example)
examples.delete example
end
def empty?
examples.empty?
end
end
end
end

View file

@ -0,0 +1,60 @@
require 'test/unit/ui/console/testrunner'
module Test
module Unit
module UI
module Console
class TestRunner
alias_method :started_without_rspec, :started
def started_with_rspec(result)
@result = result
@need_to_output_started = true
end
alias_method :started, :started_with_rspec
alias_method :test_started_without_rspec, :test_started
def test_started_with_rspec(name)
if @need_to_output_started
if @rspec_io
@rspec_io.rewind
output(@rspec_io.read)
end
output("Started")
@need_to_output_started = false
end
test_started_without_rspec(name)
end
alias_method :test_started, :test_started_with_rspec
alias_method :test_finished_without_rspec, :test_finished
def test_finished_with_rspec(name)
test_finished_without_rspec(name)
@ran_test = true
end
alias_method :test_finished, :test_finished_with_rspec
alias_method :finished_without_rspec, :finished
def finished_with_rspec(elapsed_time)
if @ran_test
finished_without_rspec(elapsed_time)
end
end
alias_method :finished, :finished_with_rspec
alias_method :setup_mediator_without_rspec, :setup_mediator
def setup_mediator_with_rspec
orig_io = @io
@io = StringIO.new
setup_mediator_without_rspec
ensure
@rspec_io = @io
@io = orig_io
end
alias_method :setup_mediator, :setup_mediator_with_rspec
end
end
end
end
end

View file

@ -0,0 +1,156 @@
require 'spec/matchers/simple_matcher'
require 'spec/matchers/be'
require 'spec/matchers/be_close'
require 'spec/matchers/change'
require 'spec/matchers/eql'
require 'spec/matchers/equal'
require 'spec/matchers/exist'
require 'spec/matchers/has'
require 'spec/matchers/have'
require 'spec/matchers/include'
require 'spec/matchers/match'
require 'spec/matchers/raise_error'
require 'spec/matchers/respond_to'
require 'spec/matchers/satisfy'
require 'spec/matchers/throw_symbol'
require 'spec/matchers/operator_matcher'
module Spec
# RSpec ships with a number of useful Expression Matchers. An Expression Matcher
# is any object that responds to the following methods:
#
# matches?(actual)
# failure_message
# negative_failure_message #optional
# description #optional
#
# See Spec::Expectations to learn how to use these as Expectation Matchers.
# See Spec::Mocks to learn how to use them as Mock Argument Constraints.
#
# == Predicates
#
# In addition to those Expression Matchers that are defined explicitly, RSpec will
# create custom Matchers on the fly for any arbitrary predicate, giving your specs
# a much more natural language feel.
#
# A Ruby predicate is a method that ends with a "?" and returns true or false.
# Common examples are +empty?+, +nil?+, and +instance_of?+.
#
# All you need to do is write +should be_+ followed by the predicate without
# the question mark, and RSpec will figure it out from there. For example:
#
# [].should be_empty => [].empty? #passes
# [].should_not be_empty => [].empty? #fails
#
# In addtion to prefixing the predicate matchers with "be_", you can also use "be_a_"
# and "be_an_", making your specs read much more naturally:
#
# "a string".should be_an_instance_of(String) =>"a string".instance_of?(String) #passes
#
# 3.should be_a_kind_of(Fixnum) => 3.kind_of?(Numeric) #passes
# 3.should be_a_kind_of(Numeric) => 3.kind_of?(Numeric) #passes
# 3.should be_an_instance_of(Fixnum) => 3.instance_of?(Fixnum) #passes
# 3.should_not be_instance_of(Numeric) => 3.instance_of?(Numeric) #fails
#
# RSpec will also create custom matchers for predicates like +has_key?+. To
# use this feature, just state that the object should have_key(:key) and RSpec will
# call has_key?(:key) on the target. For example:
#
# {:a => "A"}.should have_key(:a) => {:a => "A"}.has_key?(:a) #passes
# {:a => "A"}.should have_key(:b) => {:a => "A"}.has_key?(:b) #fails
#
# You can use this feature to invoke any predicate that begins with "has_", whether it is
# part of the Ruby libraries (like +Hash#has_key?+) or a method you wrote on your own class.
#
# == Custom Expectation Matchers
#
# When you find that none of the stock Expectation Matchers provide a natural
# feeling expectation, you can very easily write your own.
#
# For example, imagine that you are writing a game in which players can
# be in various zones on a virtual board. To specify that bob should
# be in zone 4, you could say:
#
# bob.current_zone.should eql(Zone.new("4"))
#
# But you might find it more expressive to say:
#
# bob.should be_in_zone("4")
#
# and/or
#
# bob.should_not be_in_zone("3")
#
# To do this, you would need to write a class like this:
#
# class BeInZone
# def initialize(expected)
# @expected = expected
# end
# def matches?(target)
# @target = target
# @target.current_zone.eql?(Zone.new(@expected))
# end
# def failure_message
# "expected #{@target.inspect} to be in Zone #{@expected}"
# end
# def negative_failure_message
# "expected #{@target.inspect} not to be in Zone #{@expected}"
# end
# end
#
# ... and a method like this:
#
# def be_in_zone(expected)
# BeInZone.new(expected)
# end
#
# And then expose the method to your specs. This is normally done
# by including the method and the class in a module, which is then
# included in your spec:
#
# module CustomGameMatchers
# class BeInZone
# ...
# end
#
# def be_in_zone(expected)
# ...
# end
# end
#
# describe "Player behaviour" do
# include CustomGameMatchers
# ...
# end
#
# or you can include in globally in a spec_helper.rb file <tt>require</tt>d
# from your spec file(s):
#
# Spec::Runner.configure do |config|
# config.include(CustomGameMatchers)
# end
#
module Matchers
module ModuleMethods
attr_accessor :generated_description
def clear_generated_description
self.generated_description = nil
end
end
extend ModuleMethods
def method_missing(sym, *args, &block) # :nodoc:
return Matchers::Be.new(sym, *args) if sym.starts_with?("be_")
return Matchers::Has.new(sym, *args) if sym.starts_with?("have_")
super
end
class MatcherError < StandardError
end
end
end

View file

@ -0,0 +1,224 @@
module Spec
module Matchers
class Be #:nodoc:
def initialize(*args)
if args.empty?
@expected = :satisfy_if
else
@expected = parse_expected(args.shift)
end
@args = args
@comparison = ""
end
def matches?(actual)
@actual = actual
if handling_predicate?
begin
return @result = actual.__send__(predicate, *@args)
rescue => predicate_error
# This clause should be empty, but rcov will not report it as covered
# unless something (anything) is executed within the clause
rcov_error_report = "http://eigenclass.org/hiki.rb?rcov-0.8.0"
end
# This supports should_exist > target.exists? in the old world.
# We should consider deprecating that ability as in the new world
# you can't write "should exist" unless you have your own custom matcher.
begin
return @result = actual.__send__(present_tense_predicate, *@args)
rescue
raise predicate_error
end
else
return match_or_compare
end
end
def failure_message
return "expected #{@comparison}#{expected}, got #{@actual.inspect}" unless handling_predicate?
return "expected #{predicate}#{args_to_s} to return true, got #{@result.inspect}"
end
def negative_failure_message
return "expected not #{expected}, got #{@actual.inspect}" unless handling_predicate?
return "expected #{predicate}#{args_to_s} to return false, got #{@result.inspect}"
end
def expected
return "if to be satisfied" if @expected == :satisfy_if
return true if @expected == :true
return false if @expected == :false
return "nil" if @expected == :nil
return @expected.inspect
end
def match_or_compare
return @actual ? true : false if @expected == :satisfy_if
return @actual == true if @expected == :true
return @actual == false if @expected == :false
return @actual.nil? if @expected == :nil
return @actual < @expected if @less_than
return @actual <= @expected if @less_than_or_equal
return @actual >= @expected if @greater_than_or_equal
return @actual > @expected if @greater_than
return @actual == @expected if @double_equal
return @actual === @expected if @triple_equal
return @actual.equal?(@expected)
end
def ==(expected)
@prefix = "be "
@double_equal = true
@comparison = "== "
@expected = expected
self
end
def ===(expected)
@prefix = "be "
@triple_equal = true
@comparison = "=== "
@expected = expected
self
end
def <(expected)
@prefix = "be "
@less_than = true
@comparison = "< "
@expected = expected
self
end
def <=(expected)
@prefix = "be "
@less_than_or_equal = true
@comparison = "<= "
@expected = expected
self
end
def >=(expected)
@prefix = "be "
@greater_than_or_equal = true
@comparison = ">= "
@expected = expected
self
end
def >(expected)
@prefix = "be "
@greater_than = true
@comparison = "> "
@expected = expected
self
end
def description
"#{prefix_to_sentence}#{comparison}#{expected_to_sentence}#{args_to_sentence}"
end
private
def parse_expected(expected)
if Symbol === expected
@handling_predicate = true
["be_an_","be_a_","be_"].each do |prefix|
if expected.starts_with?(prefix)
@prefix = prefix
return "#{expected.to_s.sub(@prefix,"")}".to_sym
end
end
end
@prefix = ""
return expected
end
def handling_predicate?
return false if [:true, :false, :nil].include?(@expected)
return @handling_predicate
end
def predicate
"#{@expected.to_s}?".to_sym
end
def present_tense_predicate
"#{@expected.to_s}s?".to_sym
end
def args_to_s
return "" if @args.empty?
inspected_args = @args.collect{|a| a.inspect}
return "(#{inspected_args.join(', ')})"
end
def comparison
@comparison
end
def expected_to_sentence
split_words(@expected)
end
def prefix_to_sentence
split_words(@prefix)
end
def split_words(sym)
sym.to_s.gsub(/_/,' ')
end
def args_to_sentence
case @args.length
when 0
""
when 1
" #{@args[0]}"
else
" #{@args[0...-1].join(', ')} and #{@args[-1]}"
end
end
end
# :call-seq:
# should be
# should be_true
# should be_false
# should be_nil
# should be_arbitrary_predicate(*args)
# should_not be_nil
# should_not be_arbitrary_predicate(*args)
#
# Given true, false, or nil, will pass if actual is
# true, false or nil (respectively). Given no args means
# the caller should satisfy an if condition (to be or not to be).
#
# Predicates are any Ruby method that ends in a "?" and returns true or false.
# Given be_ followed by arbitrary_predicate (without the "?"), RSpec will match
# convert that into a query against the target object.
#
# The arbitrary_predicate feature will handle any predicate
# prefixed with "be_an_" (e.g. be_an_instance_of), "be_a_" (e.g. be_a_kind_of)
# or "be_" (e.g. be_empty), letting you choose the prefix that best suits the predicate.
#
# == Examples
#
# target.should be
# target.should be_true
# target.should be_false
# target.should be_nil
# target.should_not be_nil
#
# collection.should be_empty #passes if target.empty?
# "this string".should be_an_intance_of(String)
#
# target.should_not be_empty #passes unless target.empty?
# target.should_not be_old_enough(16) #passes unless target.old_enough?(16)
def be(*args)
Matchers::Be.new(*args)
end
end
end

View file

@ -0,0 +1,37 @@
module Spec
module Matchers
class BeClose #:nodoc:
def initialize(expected, delta)
@expected = expected
@delta = delta
end
def matches?(actual)
@actual = actual
(@actual - @expected).abs < @delta
end
def failure_message
"expected #{@expected} +/- (< #{@delta}), got #{@actual}"
end
def description
"be close to #{@expected} (within +- #{@delta})"
end
end
# :call-seq:
# should be_close(expected, delta)
# should_not be_close(expected, delta)
#
# Passes if actual == expected +/- delta
#
# == Example
#
# result.should be_close(3.0, 0.5)
def be_close(expected, delta)
Matchers::BeClose.new(expected, delta)
end
end
end

View file

@ -0,0 +1,144 @@
module Spec
module Matchers
#Based on patch from Wilson Bilkovich
class Change #:nodoc:
def initialize(receiver=nil, message=nil, &block)
@receiver = receiver
@message = message
@block = block
end
def matches?(target, &block)
if block
raise MatcherError.new(<<-EOF
block passed to should or should_not change must use {} instead of do/end
EOF
)
end
@target = target
execute_change
return false if @from && (@from != @before)
return false if @to && (@to != @after)
return (@before + @amount == @after) if @amount
return ((@after - @before) >= @minimum) if @minimum
return ((@after - @before) <= @maximum) if @maximum
return @before != @after
end
def execute_change
@before = @block.nil? ? @receiver.send(@message) : @block.call
@target.call
@after = @block.nil? ? @receiver.send(@message) : @block.call
end
def failure_message
if @to
"#{result} should have been changed to #{@to.inspect}, but is now #{@after.inspect}"
elsif @from
"#{result} should have initially been #{@from.inspect}, but was #{@before.inspect}"
elsif @amount
"#{result} should have been changed by #{@amount.inspect}, but was changed by #{actual_delta.inspect}"
elsif @minimum
"#{result} should have been changed by at least #{@minimum.inspect}, but was changed by #{actual_delta.inspect}"
elsif @maximum
"#{result} should have been changed by at most #{@maximum.inspect}, but was changed by #{actual_delta.inspect}"
else
"#{result} should have changed, but is still #{@before.inspect}"
end
end
def result
@message || "result"
end
def actual_delta
@after - @before
end
def negative_failure_message
"#{result} should not have changed, but did change from #{@before.inspect} to #{@after.inspect}"
end
def by(amount)
@amount = amount
self
end
def by_at_least(minimum)
@minimum = minimum
self
end
def by_at_most(maximum)
@maximum = maximum
self
end
def to(to)
@to = to
self
end
def from (from)
@from = from
self
end
end
# :call-seq:
# should change(receiver, message, &block)
# should change(receiver, message, &block).by(value)
# should change(receiver, message, &block).from(old).to(new)
# should_not change(receiver, message, &block)
#
# Allows you to specify that a Proc will cause some value to change.
#
# == Examples
#
# lambda {
# team.add_player(player)
# }.should change(roster, :count)
#
# lambda {
# team.add_player(player)
# }.should change(roster, :count).by(1)
#
# lambda {
# team.add_player(player)
# }.should change(roster, :count).by_at_least(1)
#
# lambda {
# team.add_player(player)
# }.should change(roster, :count).by_at_most(1)
#
# string = "string"
# lambda {
# string.reverse
# }.should change { string }.from("string").to("gnirts")
#
# lambda {
# person.happy_birthday
# }.should change(person, :birthday).from(32).to(33)
#
# lambda {
# employee.develop_great_new_social_networking_app
# }.should change(employee, :title).from("Mail Clerk").to("CEO")
#
# Evaluates +receiver.message+ or +block+ before and
# after it evaluates the c object (generated by the lambdas in the examples above).
#
# Then compares the values before and after the +receiver.message+ and
# evaluates the difference compared to the expected difference.
#
# == Warning
# +should_not+ +change+ only supports the form with no subsequent calls to
# +by+, +by_at_least+, +by_at_most+, +to+ or +from+.
#
# blocks passed to +should+ +change+ and +should_not+ +change+
# must use the <tt>{}</tt> form (<tt>do/end</tt> is not supported)
def change(target=nil, message=nil, &block)
Matchers::Change.new(target, message, &block)
end
end
end

View file

@ -0,0 +1,43 @@
module Spec
module Matchers
class Eql #:nodoc:
def initialize(expected)
@expected = expected
end
def matches?(actual)
@actual = actual
@actual.eql?(@expected)
end
def failure_message
return "expected #{@expected.inspect}, got #{@actual.inspect} (using .eql?)", @expected, @actual
end
def negative_failure_message
return "expected #{@actual.inspect} not to equal #{@expected.inspect} (using .eql?)", @expected, @actual
end
def description
"eql #{@expected.inspect}"
end
end
# :call-seq:
# should eql(expected)
# should_not eql(expected)
#
# Passes if actual and expected are of equal value, but not necessarily the same object.
#
# See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more information about equality in Ruby.
#
# == Examples
#
# 5.should eql(5)
# 5.should_not eql(3)
def eql(expected)
Matchers::Eql.new(expected)
end
end
end

View file

@ -0,0 +1,43 @@
module Spec
module Matchers
class Equal #:nodoc:
def initialize(expected)
@expected = expected
end
def matches?(actual)
@actual = actual
@actual.equal?(@expected)
end
def failure_message
return "expected #{@expected.inspect}, got #{@actual.inspect} (using .equal?)", @expected, @actual
end
def negative_failure_message
return "expected #{@actual.inspect} not to equal #{@expected.inspect} (using .equal?)", @expected, @actual
end
def description
"equal #{@expected.inspect}"
end
end
# :call-seq:
# should equal(expected)
# should_not equal(expected)
#
# Passes if actual and expected are the same object (object identity).
#
# See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more information about equality in Ruby.
#
# == Examples
#
# 5.should equal(5) #Fixnums are equal
# "5".should_not equal("5") #Strings that look the same are not the same object
def equal(expected)
Matchers::Equal.new(expected)
end
end
end

View file

@ -0,0 +1,17 @@
module Spec
module Matchers
class Exist
def matches? actual
@actual = actual
@actual.exist?
end
def failure_message
"expected #{@actual.inspect} to exist, but it doesn't."
end
def negative_failure_message
"expected #{@actual.inspect} to not exist, but it does."
end
end
def exist; Exist.new; end
end
end

View file

@ -0,0 +1,44 @@
module Spec
module Matchers
class Has #:nodoc:
def initialize(sym, *args)
@sym = sym
@args = args
end
def matches?(target)
@target = target
begin
return target.send(predicate, *@args)
rescue => @error
# This clause should be empty, but rcov will not report it as covered
# unless something (anything) is executed within the clause
rcov_error_report = "http://eigenclass.org/hiki.rb?rcov-0.8.0"
end
return false
end
def failure_message
raise @error if @error
"expected ##{predicate}(#{@args[0].inspect}) to return true, got false"
end
def negative_failure_message
raise @error if @error
"expected ##{predicate}(#{@args[0].inspect}) to return false, got true"
end
def description
"have key #{@args[0].inspect}"
end
private
def predicate
"#{@sym.to_s.sub("have_","has_")}?".to_sym
end
end
end
end

Some files were not shown because too many files have changed in this diff Show more