1
0
Fork 0
mirror of https://github.com/thoughtbot/shoulda-matchers.git synced 2022-11-09 12:01:38 -05:00

Extracted the context framework, switched to rspec

This commit is contained in:
Joe Ferris 2010-12-13 17:28:59 -05:00
parent 2320a8c539
commit 6aca71765a
200 changed files with 1735 additions and 3531 deletions

2
.bundle/config Normal file
View file

@ -0,0 +1,2 @@
---
BUNDLE_DISABLE_SHARED_GEMS: "1"

9
Gemfile Normal file
View file

@ -0,0 +1,9 @@
source 'http://rubygems.org'
gem 'rails', '3.0.0.beta4'
gem 'sqlite3-ruby', :require => 'sqlite3'
gem 'mocha'
gem 'rspec-rails', '2.0.0.beta.12'
gem 'ruby-debug'
gem 'cucumber'

115
Gemfile.lock Normal file
View file

@ -0,0 +1,115 @@
GEM
remote: http://rubygems.org/
specs:
abstract (1.0.0)
actionmailer (3.0.0.beta4)
actionpack (= 3.0.0.beta4)
mail (~> 2.2.3)
actionpack (3.0.0.beta4)
activemodel (= 3.0.0.beta4)
activesupport (= 3.0.0.beta4)
builder (~> 2.1.2)
erubis (~> 2.6.5)
i18n (~> 0.4.1)
rack (~> 1.1.0)
rack-mount (~> 0.6.3)
rack-test (~> 0.5.4)
tzinfo (~> 0.3.16)
activemodel (3.0.0.beta4)
activesupport (= 3.0.0.beta4)
builder (~> 2.1.2)
i18n (~> 0.4.1)
activerecord (3.0.0.beta4)
activemodel (= 3.0.0.beta4)
activesupport (= 3.0.0.beta4)
arel (~> 0.4.0)
tzinfo (~> 0.3.16)
activeresource (3.0.0.beta4)
activemodel (= 3.0.0.beta4)
activesupport (= 3.0.0.beta4)
activesupport (3.0.0.beta4)
arel (0.4.0)
activesupport (>= 3.0.0.beta)
builder (2.1.2)
columnize (0.3.1)
cucumber (0.9.4)
builder (~> 2.1.2)
diff-lcs (~> 1.1.2)
gherkin (~> 2.2.9)
json (~> 1.4.6)
term-ansicolor (~> 1.0.5)
diff-lcs (1.1.2)
erubis (2.6.6)
abstract (>= 1.0.0)
gherkin (2.2.9)
json (~> 1.4.6)
term-ansicolor (~> 1.0.5)
i18n (0.4.1)
json (1.4.6)
linecache (0.43)
mail (2.2.12)
activesupport (>= 2.3.6)
i18n (>= 0.4.0)
mime-types (~> 1.16)
treetop (~> 1.4.8)
mime-types (1.16)
mocha (0.9.10)
rake
nokogiri (1.4.4)
polyglot (0.3.1)
rack (1.1.0)
rack-mount (0.6.13)
rack (>= 1.0.0)
rack-test (0.5.6)
rack (>= 1.0)
rails (3.0.0.beta4)
actionmailer (= 3.0.0.beta4)
actionpack (= 3.0.0.beta4)
activerecord (= 3.0.0.beta4)
activeresource (= 3.0.0.beta4)
activesupport (= 3.0.0.beta4)
bundler (>= 0.9.26)
railties (= 3.0.0.beta4)
railties (3.0.0.beta4)
actionpack (= 3.0.0.beta4)
activesupport (= 3.0.0.beta4)
rake (>= 0.8.3)
thor (~> 0.13.6)
rake (0.8.7)
rspec (2.0.0.beta.12)
rspec-core (= 2.0.0.beta.12)
rspec-expectations (= 2.0.0.beta.12)
rspec-mocks (= 2.0.0.beta.12)
rspec-core (2.0.0.beta.12)
rspec-expectations (2.0.0.beta.12)
diff-lcs (>= 1.1.2)
rspec-mocks (2.0.0.beta.12)
rspec-rails (2.0.0.beta.12)
rspec (= 2.0.0.beta.12)
webrat (>= 0.7.0)
ruby-debug (0.10.3)
columnize (>= 0.1)
ruby-debug-base (~> 0.10.3.0)
ruby-debug-base (0.10.3)
linecache (>= 0.3)
sqlite3-ruby (1.3.2)
term-ansicolor (1.0.5)
thor (0.13.8)
treetop (1.4.9)
polyglot (>= 0.3.1)
tzinfo (0.3.23)
webrat (0.7.2)
nokogiri (>= 1.2.0)
rack (>= 1.0)
rack-test (>= 0.5.3)
PLATFORMS
ruby
DEPENDENCIES
cucumber
mocha
rails (= 3.0.0.beta4)
rspec-rails (= 2.0.0.beta.12)
ruby-debug
sqlite3-ruby

View file

@ -1,25 +1,13 @@
require 'rubygems'
require 'bundler/setup'
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
require 'rake/gempackagetask'
begin
require 'cucumber/rake/task'
rescue LoadError
warn "couldn't load cucumber, skipping"
end
require 'rspec/core/rake_task'
require 'cucumber/rake/task'
$LOAD_PATH.unshift("lib")
require 'shoulda/version'
load 'tasks/shoulda.rake'
# Test::Unit::UI::VERBOSE
test_files_pattern = 'test/{unit,functional,other,matchers}/**/*_test.rb'
Rake::TestTask.new do |t|
t.libs << 'lib' << 'test'
t.pattern = test_files_pattern
t.verbose = false
end
Rake::RDocTask.new { |rdoc|
rdoc.rdoc_dir = 'doc'
@ -29,11 +17,15 @@ Rake::RDocTask.new { |rdoc|
rdoc.rdoc_files.include('README.rdoc', 'CONTRIBUTION_GUIDELINES.rdoc', 'lib/**/*.rb')
}
RSpec::Core::RakeTask.new do |t|
t.pattern = "spec/**/*_spec.rb"
end
desc "Run code-coverage analysis using rcov"
task :coverage do
rm_rf "coverage"
files = Dir[test_files_pattern]
system "rcov --rails --sort coverage -Ilib #{files.join(' ')}"
RSpec::Core::RakeTask.new(:coverage) do |t|
t.rcov = true
t.rcov_opts = %{--exclude osx\/objc,spec,gems\/ --failure-threshold 100}
t.pattern = "spec/**/*_spec.rb"
end
eval("$specification = begin; #{IO.read('shoulda.gemspec')}; end")
@ -51,6 +43,6 @@ Cucumber::Rake::Task.new do |t|
t.profile = 'default'
end
desc 'Default: run test and cucumber features for support versions'
task :default => [:test, :cucumber]
desc 'Default: run specs and cucumber features'
task :default => [:spec, :cucumber]

View file

@ -1,42 +0,0 @@
#!/usr/bin/env ruby
require 'fileutils'
require 'tmpdir'
TMP = Dir::tmpdir
def usage(msg = nil)
puts "Error: #{msg}" if msg
puts if msg
puts "Usage: #{File.basename(__FILE__)} normal_test_file.rb"
puts
puts "Will convert an existing test file with names like "
puts
puts " def test_should_do_stuff"
puts " ..."
puts " end"
puts
puts "to one using the new syntax: "
puts
puts " should \"be super cool\" do"
puts " ..."
puts " end"
puts
puts "A copy of the old file will be left under #{TMP} in case\nthis script just seriously screws up"
puts
exit (msg ? 2 : 0)
end
usage("Wrong number of arguments.") unless ARGV.size == 1
usage("Temp directory '#{TMP}' is not valid. Set TMPDIR environment variable to a writeable directory.") unless File.directory?(TMP) && File.writable?(TMP)
file = ARGV.shift
tmpfile = File.join(TMP, File.basename(file))
usage("File '#{file}' doesn't exist") unless File.exists?(file)
FileUtils.cp(file, tmpfile)
contents = File.read(tmpfile)
contents.gsub!(/def test_should_(\S+)/) {|line| "should \"#{$1.tr('_', ' ')}\" do"}
contents.gsub!(/def test_(\S+)/) {|line| "should \"RENAME ME: test #{$1.tr('_', ' ')}\" do"}
File.open(file, 'w') { |f| f.write(contents) }
puts "File '#{file}' has been converted to 'should' syntax. Old version has been stored in '#{tmpfile}'"

View file

@ -29,7 +29,7 @@ When /^I run the rspec generator$/ do
end
When /^I configure the application to use rspec\-rails$/ do
append_to_gemfile "gem 'rspec-rails', '>= 2.0.0.beta.12'"
append_to_gemfile "gem 'rspec-rails', '= 2.0.0.beta.12'"
steps %{And I run "bundle install"}
end

View file

@ -1 +0,0 @@
require File.join(File.dirname(__FILE__), 'rails', 'init')

View file

@ -5,3 +5,4 @@ if defined?(RSpec)
else
require 'shoulda/integrations/test_unit'
end

View file

@ -1,19 +1,39 @@
require 'shoulda'
require 'shoulda/action_controller/matchers'
require 'shoulda/action_controller/assign_to_matcher'
require 'shoulda/action_controller/filter_param_matcher'
require 'shoulda/action_controller/set_the_flash_matcher'
require 'shoulda/action_controller/render_with_layout_matcher'
require 'shoulda/action_controller/respond_with_matcher'
require 'shoulda/action_controller/respond_with_content_type_matcher'
require 'shoulda/action_controller/set_session_matcher'
require 'shoulda/action_controller/route_matcher'
require 'shoulda/action_controller/redirect_to_matcher'
require 'shoulda/action_controller/render_template_matcher'
module Test # :nodoc: all
module Unit
class TestCase
include Shoulda::ActionController::Matchers
extend Shoulda::ActionController::Matchers
end
end
end
if defined?(ActionController::TestCase)
class ActionController::TestCase
def subject
@controller
module Shoulda # :nodoc:
module ActionController # :nodoc:
# By using the matchers you can quickly and easily create concise and
# easy to read test suites.
#
# This code segment:
#
# describe UsersController, "on GET to show with a valid id" do
# before(:each) do
# get :show, :id => User.first.to_param
# end
#
# it { should assign_to(:user) }
# it { should respond_with(:success) }
# it { should render_template(:show) }
# it { should not_set_the_flash) }
#
# it "should do something else really cool" do
# assigns[:user].id.should == 1
# end
# end
#
# Would produce 5 tests for the show action
module Matchers
end
end
end

View file

@ -0,0 +1,50 @@
module Shoulda # :nodoc:
module ActionController # :nodoc:
module Matchers
# Ensures that filter_parameter_logging is set for the specified key.
#
# Example:
#
# it { should filter_param(:password) }
def filter_param(key)
FilterParamMatcher.new(key)
end
class FilterParamMatcher # :nodoc:
def initialize(key)
@key = key.to_s
end
def matches?(controller)
@controller = controller
filters_key?
end
def failure_message
"Expected #{@key} to be filtered; filtered keys: #{filtered_keys.join(', ')}"
end
def negative_failure_message
"Did not expect #{@key} to be filtered"
end
def description
"filter #{@key}"
end
private
def filters_key?
filtered_keys.include?(@key)
end
def filtered_keys
Rails.application.config.filter_parameters.map { |filter| filter.to_s }
end
end
end
end
end

View file

@ -1,39 +0,0 @@
require 'shoulda/action_controller/matchers/assign_to_matcher'
require 'shoulda/action_controller/matchers/filter_param_matcher'
require 'shoulda/action_controller/matchers/set_the_flash_matcher'
require 'shoulda/action_controller/matchers/render_with_layout_matcher'
require 'shoulda/action_controller/matchers/respond_with_matcher'
require 'shoulda/action_controller/matchers/respond_with_content_type_matcher'
require 'shoulda/action_controller/matchers/set_session_matcher'
require 'shoulda/action_controller/matchers/route_matcher'
require 'shoulda/action_controller/matchers/redirect_to_matcher'
require 'shoulda/action_controller/matchers/render_template_matcher'
module Shoulda # :nodoc:
module ActionController # :nodoc:
# By using the matchers you can quickly and easily create concise and
# easy to read test suites.
#
# This code segment:
#
# describe UsersController, "on GET to show with a valid id" do
# before(:each) do
# get :show, :id => User.first.to_param
# end
#
# it { should assign_to(:user) }
# it { should respond_with(:success) }
# it { should render_template(:show) }
# it { should not_set_the_flash) }
#
# it "should do something else really cool" do
# assigns[:user].id.should == 1
# end
# end
#
# Would produce 5 tests for the show action
module Matchers
end
end
end

View file

@ -1,74 +0,0 @@
module Shoulda # :nodoc:
module ActionController # :nodoc:
module Matchers
# Ensures that filter_parameter_logging is set for the specified key.
#
# Example:
#
# it { should filter_param(:password) }
def filter_param(key)
FilterParamMatcher.new(key)
end
class FilterParamMatcher # :nodoc:
def initialize(key)
@key = key.to_s
end
def matches?(controller)
@controller = controller
filters_params? && filters_key?
end
def failure_message
"Expected #{@key} to be filtered"
end
def negative_failure_message
"Did not expect #{@key} to be filtered"
end
def description
"filter #{@key}"
end
private
def filters_params?
@controller.respond_to?(:filter_parameters) ||
request.respond_to?(:filtered_parameters)
end
def filters_key?
filtered_value == '[FILTERED]'
end
def filtered_value
if request.respond_to?(:filtered_parameters)
filtered_request_value
else
filtered_controller_value
end
end
def filtered_controller_value
filtered = @controller.send(:filter_parameters,
@key.to_s => @key.to_s)
filtered[@key.to_s]
end
def filtered_request_value
request.env['action_dispatch.request.parameters'] = { @key.to_s => 'value' }
request.filtered_parameters[@key.to_s]
end
def request
@request ||= ::ActionController::TestRequest.new
end
end
end
end
end

View file

@ -10,10 +10,10 @@ module Shoulda # :nodoc:
# it { should render_with_layout(:special) }
# it { should_not render_with_layout }
def render_with_layout(expected_layout = nil)
RenderWithLayout.new(expected_layout)
RenderWithLayoutMatcher.new(expected_layout).in_context(self)
end
class RenderWithLayout # :nodoc:
class RenderWithLayoutMatcher # :nodoc:
def initialize(expected_layout)
@expected_layout = expected_layout.to_s unless expected_layout.nil?

View file

@ -67,15 +67,9 @@ module Shoulda # :nodoc:
def flash
return @flash if @flash
flash_and_now = @controller.request.session["flash"].dup if @controller.request.session["flash"]
flash = @controller.send(:flash)
@flash = if @now
flash.keys.each {|key| flash_and_now.delete(key) }
flash_and_now
else
flash
end
@flash = @controller.flash.dup
@flash.sweep unless @now
@flash
end
def expectation

View file

@ -1,11 +1,22 @@
require 'shoulda'
require 'shoulda/action_mailer/matchers'
require 'shoulda/action_mailer/have_sent_email'
module Test # :nodoc: all
module Unit
class TestCase
include Shoulda::ActionMailer::Matchers
extend Shoulda::ActionMailer::Matchers
module Shoulda # :nodoc:
module ActionMailer # :nodoc:
# = Matchers for your mailers
#
# This matcher will test that email is sent properly
#
# describe User do
# it { should have_sent_email.with_subject(/is spam$/) }
# it { should have_sent_email.from('do-not-reply@example.com') }
# it { should have_sent_email.with_body(/is spam\./) }
# it { should have_sent_email.to('myself@me.com') }
# it { should have_sent_email.with_subject(/spam/).
# from('do-not-reply@example.com').
# with_body(/spam/).
# to('myself@me.com') }
# end
module Matchers
end
end
end

View file

@ -1,22 +0,0 @@
require 'shoulda/action_mailer/matchers/have_sent_email'
module Shoulda # :nodoc:
module ActionMailer # :nodoc:
# = Matchers for your mailers
#
# This matcher will test that email is sent properly
#
# describe User do
# it { should have_sent_email.with_subject(/is spam$/) }
# it { should have_sent_email.from('do-not-reply@example.com') }
# it { should have_sent_email.with_body(/is spam\./) }
# it { should have_sent_email.to('myself@me.com') }
# it { should have_sent_email.with_subject(/spam/).
# from('do-not-reply@example.com').
# with_body(/spam/).
# to('myself@me.com') }
# end
module Matchers
end
end
end

View file

@ -1,12 +1,42 @@
require 'shoulda'
require 'shoulda/active_record/helpers'
require 'shoulda/active_record/matchers'
require 'shoulda/active_record/validation_matcher'
require 'shoulda/active_record/allow_value_matcher'
require 'shoulda/active_record/ensure_length_of_matcher'
require 'shoulda/active_record/ensure_inclusion_of_matcher'
require 'shoulda/active_record/validate_presence_of_matcher'
require 'shoulda/active_record/validate_format_of_matcher'
require 'shoulda/active_record/validate_uniqueness_of_matcher'
require 'shoulda/active_record/validate_acceptance_of_matcher'
require 'shoulda/active_record/validate_numericality_of_matcher'
require 'shoulda/active_record/association_matcher'
require 'shoulda/active_record/have_db_column_matcher'
require 'shoulda/active_record/have_db_index_matcher'
require 'shoulda/active_record/have_readonly_attribute_matcher'
require 'shoulda/active_record/allow_mass_assignment_of_matcher'
module Test # :nodoc: all
module Unit
class TestCase
include Shoulda::ActiveRecord::Matchers
extend Shoulda::ActiveRecord::Matchers
module Shoulda # :nodoc:
module ActiveRecord # :nodoc:
# = Matchers for your active record models
#
# These matchers will test most of the validations and associations for your
# ActiveRecord models.
#
# describe User do
# it { should validate_presence_of(:name) }
# it { should validate_presence_of(:phone_number) }
# %w(abcd 1234).each do |value|
# it { should_not allow_value(value).for(:phone_number) }
# end
# it { should allow_value("(123) 456-7890").for(:phone_number) }
# it { should_not allow_mass_assignment_of(:password) }
# it { should have_one(:profile) }
# it { should have_many(:dogs) }
# it { should have_many(:messes).through(:dogs) }
# it { should belong_to(:lover) }
# end
#
module Matchers
end
end
end

View file

@ -1,42 +0,0 @@
require 'shoulda/active_record/helpers'
require 'shoulda/active_record/matchers/validation_matcher'
require 'shoulda/active_record/matchers/allow_value_matcher'
require 'shoulda/active_record/matchers/ensure_length_of_matcher'
require 'shoulda/active_record/matchers/ensure_inclusion_of_matcher'
require 'shoulda/active_record/matchers/validate_presence_of_matcher'
require 'shoulda/active_record/matchers/validate_format_of_matcher'
require 'shoulda/active_record/matchers/validate_uniqueness_of_matcher'
require 'shoulda/active_record/matchers/validate_acceptance_of_matcher'
require 'shoulda/active_record/matchers/validate_numericality_of_matcher'
require 'shoulda/active_record/matchers/association_matcher'
require 'shoulda/active_record/matchers/have_db_column_matcher'
require 'shoulda/active_record/matchers/have_db_index_matcher'
require 'shoulda/active_record/matchers/have_readonly_attribute_matcher'
require 'shoulda/active_record/matchers/allow_mass_assignment_of_matcher'
module Shoulda # :nodoc:
module ActiveRecord # :nodoc:
# = Matchers for your active record models
#
# These matchers will test most of the validations and associations for your
# ActiveRecord models.
#
# describe User do
# it { should validate_presence_of(:name) }
# it { should validate_presence_of(:phone_number) }
# %w(abcd 1234).each do |value|
# it { should_not allow_value(value).for(:phone_number) }
# end
# it { should allow_value("(123) 456-7890").for(:phone_number) }
# it { should_not allow_mass_assignment_of(:password) }
# it { should have_one(:profile) }
# it { should have_many(:dogs) }
# it { should have_many(:messes).through(:dogs) }
# it { should belong_to(:lover) }
# end
#
module Matchers
end
end
end

View file

@ -1,79 +0,0 @@
module Shoulda # :nodoc:
module Assertions
# Asserts that two arrays contain the same elements, the same number of times. Essentially ==, but unordered.
#
# assert_same_elements([:a, :b, :c], [:c, :a, :b]) => passes
def assert_same_elements(a1, a2, msg = nil)
[:select, :inject, :size].each do |m|
[a1, a2].each {|a| assert_respond_to(a, m, "Are you sure that #{a.inspect} is an array? It doesn't respond to #{m}.") }
end
assert a1h = a1.inject({}) { |h,e| h[e] = a1.select { |i| i == e }.size; h }
assert a2h = a2.inject({}) { |h,e| h[e] = a2.select { |i| i == e }.size; h }
assert_equal(a1h, a2h, msg)
end
# Asserts that the given collection contains item x. If x is a regular expression, ensure that
# at least one element from the collection matches x. +extra_msg+ is appended to the error message if the assertion fails.
#
# assert_contains(['a', '1'], /\d/) => passes
# assert_contains(['a', '1'], 'a') => passes
# assert_contains(['a', '1'], /not there/) => fails
def assert_contains(collection, x, extra_msg = "")
collection = [collection] unless collection.is_a?(Array)
msg = "#{x.inspect} not found in #{collection.to_a.inspect} #{extra_msg}"
case x
when Regexp
assert(collection.detect { |e| e =~ x }, msg)
else
assert(collection.include?(x), msg)
end
end
# Asserts that the given collection does not contain item x. If x is a regular expression, ensure that
# none of the elements from the collection match x.
def assert_does_not_contain(collection, x, extra_msg = "")
collection = [collection] unless collection.is_a?(Array)
msg = "#{x.inspect} found in #{collection.to_a.inspect} " + extra_msg
case x
when Regexp
assert(!collection.detect { |e| e =~ x }, msg)
else
assert(!collection.include?(x), msg)
end
end
# Asserts that the given matcher returns true when +target+ is passed to #matches?
def assert_accepts(matcher, target, options = {})
if matcher.respond_to?(:in_context)
matcher.in_context(self)
end
if matcher.matches?(target)
assert_block { true }
if options[:message]
assert_match options[:message], matcher.negative_failure_message
end
else
assert_block(matcher.failure_message) { false }
end
end
# Asserts that the given matcher returns false when +target+ is passed to #matches?
def assert_rejects(matcher, target, options = {})
if matcher.respond_to?(:in_context)
matcher.in_context(self)
end
unless matcher.matches?(target)
assert_block { true }
if options[:message]
assert_match options[:message], matcher.failure_message
end
else
assert_block(matcher.negative_failure_message) { false }
end
end
end
end

View file

@ -1,46 +0,0 @@
module Shoulda # :nodoc:
# Call autoload_macros when you want to load test macros automatically in a non-Rails
# project (it's done automatically for Rails projects).
# You don't need to specify ROOT/test/shoulda_macros explicitly. Your custom macros
# are loaded automatically when you call autoload_macros.
#
# The first argument is the path to you application's root directory.
# All following arguments are directories relative to your root, which contain
# shoulda_macros subdirectories. These directories support the same kinds of globs as the
# Dir class.
#
# Basic usage (from a test_helper):
# Shoulda.autoload_macros(File.dirname(__FILE__) + '/..')
# will load everything in
# - your_app/test/shoulda_macros
#
# To load vendored macros as well:
# Shoulda.autoload_macros(APP_ROOT, 'vendor/*')
# will load everything in
# - APP_ROOT/vendor/*/shoulda_macros
# - APP_ROOT/test/shoulda_macros
#
# To load macros in an app with a vendor directory laid out like Rails':
# Shoulda.autoload_macros(APP_ROOT, 'vendor/{plugins,gems}/*')
# or
# Shoulda.autoload_macros(APP_ROOT, 'vendor/plugins/*', 'vendor/gems/*')
# will load everything in
# - APP_ROOT/vendor/plugins/*/shoulda_macros
# - APP_ROOT/vendor/gems/*/shoulda_macros
# - APP_ROOT/test/shoulda_macros
#
# If you prefer to stick testing dependencies away from your production dependencies:
# Shoulda.autoload_macros(APP_ROOT, 'vendor/*', 'test/vendor/*')
# will load everything in
# - APP_ROOT/vendor/*/shoulda_macros
# - APP_ROOT/test/vendor/*/shoulda_macros
# - APP_ROOT/test/shoulda_macros
def self.autoload_macros(root, *dirs)
dirs << File.join('test')
complete_dirs = dirs.map{|d| File.join(root, d, 'shoulda_macros')}
all_files = complete_dirs.inject([]){ |files, dir| files + Dir[File.join(dir, '*.rb')] }
all_files.each do |file|
require file
end
end
end

View file

@ -1,441 +0,0 @@
module Shoulda
class << self
attr_accessor :contexts
def contexts # :nodoc:
@contexts ||= []
end
def current_context # :nodoc:
self.contexts.last
end
def add_context(context) # :nodoc:
self.contexts.push(context)
end
def remove_context # :nodoc:
self.contexts.pop
end
end
module ClassMethods
# == Should statements
#
# Should statements are just syntactic sugar over normal Test::Unit test
# methods. A should block contains all the normal code and assertions
# you're used to seeing, with the added benefit that they can be wrapped
# inside context blocks (see below).
#
# === Example:
#
# class UserTest < Test::Unit::TestCase
#
# def setup
# @user = User.new("John", "Doe")
# end
#
# should "return its full name"
# assert_equal 'John Doe', @user.full_name
# end
#
# end
#
# ...will produce the following test:
# * <tt>"test: User should return its full name. "</tt>
#
# Note: The part before <tt>should</tt> in the test name is gleamed from the name of the Test::Unit class.
#
# Should statements can also take a Proc as a <tt>:before </tt>option. This proc runs after any
# parent context's setups but before the current context's setup.
#
# === Example:
#
# context "Some context" do
# setup { puts("I run after the :before proc") }
#
# should "run a :before proc", :before => lambda { puts("I run before the setup") } do
# assert true
# end
# end
#
# Should statements can also wrap matchers, making virtually any matcher
# usable in a macro style. The matcher's description is used to generate a
# test name and failure message, and the test will pass if the matcher
# matches the subject.
#
# === Example:
#
# should validate_presence_of(:first_name).with_message(/gotta be there/)
#
def should(name_or_matcher, options = {}, &blk)
if Shoulda.current_context
Shoulda.current_context.should(name_or_matcher, options, &blk)
else
context_name = self.name.gsub(/Test/, "")
context = Shoulda::Context.new(context_name, self) do
should(name_or_matcher, options, &blk)
end
context.build
end
end
# Allows negative tests using matchers. The matcher's description is used
# to generate a test name and negative failure message, and the test will
# pass unless the matcher matches the subject.
#
# === Example:
#
# should_not set_the_flash
def should_not(matcher)
if Shoulda.current_context
Shoulda.current_context.should_not(matcher)
else
context_name = self.name.gsub(/Test/, "")
context = Shoulda::Context.new(context_name, self) do
should_not(matcher)
end
context.build
end
end
# == Before statements
#
# Before statements are should statements that run before the current
# context's setup. These are especially useful when setting expectations.
#
# === Example:
#
# class UserControllerTest < Test::Unit::TestCase
# context "the index action" do
# setup do
# @users = [Factory(:user)]
# User.stubs(:find).returns(@users)
# end
#
# context "on GET" do
# setup { get :index }
#
# should respond_with(:success)
#
# # runs before "get :index"
# before_should "find all users" do
# User.expects(:find).with(:all).returns(@users)
# end
# end
# end
# end
def before_should(name, &blk)
should(name, :before => blk) { assert true }
end
# Just like should, but never runs, and instead prints an 'X' in the Test::Unit output.
def should_eventually(name, options = {}, &blk)
context_name = self.name.gsub(/Test/, "")
context = Shoulda::Context.new(context_name, self) do
should_eventually(name, &blk)
end
context.build
end
# == Contexts
#
# A context block groups should statements under a common set of setup/teardown methods.
# Context blocks can be arbitrarily nested, and can do wonders for improving the maintainability
# and readability of your test code.
#
# A context block can contain setup, should, should_eventually, and teardown blocks.
#
# class UserTest < Test::Unit::TestCase
# context "A User instance" do
# setup do
# @user = User.find(:first)
# end
#
# should "return its full name"
# assert_equal 'John Doe', @user.full_name
# end
# end
# end
#
# This code will produce the method <tt>"test: A User instance should return its full name. "</tt>.
#
# Contexts may be nested. Nested contexts run their setup blocks from out to in before each
# should statement. They then run their teardown blocks from in to out after each should statement.
#
# class UserTest < Test::Unit::TestCase
# context "A User instance" do
# setup do
# @user = User.find(:first)
# end
#
# should "return its full name"
# assert_equal 'John Doe', @user.full_name
# end
#
# context "with a profile" do
# setup do
# @user.profile = Profile.find(:first)
# end
#
# should "return true when sent :has_profile?"
# assert @user.has_profile?
# end
# end
# end
# end
#
# This code will produce the following methods
# * <tt>"test: A User instance should return its full name. "</tt>
# * <tt>"test: A User instance with a profile should return true when sent :has_profile?. "</tt>
#
# <b>Just like should statements, a context block can exist next to normal <tt>def test_the_old_way; end</tt>
# tests</b>. This means you do not have to fully commit to the context/should syntax in a test file.
def context(name, &blk)
if Shoulda.current_context
Shoulda.current_context.context(name, &blk)
else
context = Shoulda::Context.new(name, self, &blk)
context.build
end
end
# Returns the class being tested, as determined by the test class name.
#
# class UserTest; described_type; end
# # => User
def described_type
self.name.gsub(/Test$/, '').constantize
end
# Sets the return value of the subject instance method:
#
# class UserTest < Test::Unit::TestCase
# subject { User.first }
#
# # uses the existing user
# should validate_uniqueness_of(:email)
# end
def subject(&block)
@subject_block = block
end
def subject_block # :nodoc:
@subject_block
end
end
module InstanceMethods
# Returns an instance of the class under test.
#
# class UserTest
# should "be a user" do
# assert_kind_of User, subject # passes
# end
# end
#
# The subject can be explicitly set using the subject class method:
#
# class UserTest
# subject { User.first }
# should "be an existing user" do
# assert !subject.new_record? # uses the first user
# end
# end
#
# The subject is used by all macros that require an instance of the class
# being tested.
def subject
@shoulda_subject ||= construct_subject
end
def subject_block # :nodoc:
(@shoulda_context && @shoulda_context.subject_block) || self.class.subject_block
end
def get_instance_of(object_or_klass) # :nodoc:
if object_or_klass.is_a?(Class)
object_or_klass.new
else
object_or_klass
end
end
def instance_variable_name_for(klass) # :nodoc:
klass.to_s.split('::').last.underscore
end
private
def construct_subject
if subject_block
instance_eval(&subject_block)
else
get_instance_of(self.class.described_type)
end
end
end
class Context # :nodoc:
attr_accessor :name # my name
attr_accessor :parent # may be another context, or the original test::unit class.
attr_accessor :subcontexts # array of contexts nested under myself
attr_accessor :setup_blocks # blocks given via setup methods
attr_accessor :teardown_blocks # blocks given via teardown methods
attr_accessor :shoulds # array of hashes representing the should statements
attr_accessor :should_eventuallys # array of hashes representing the should eventually statements
attr_accessor :subject_block
def initialize(name, parent, &blk)
Shoulda.add_context(self)
self.name = name
self.parent = parent
self.setup_blocks = []
self.teardown_blocks = []
self.shoulds = []
self.should_eventuallys = []
self.subcontexts = []
merge_block(&blk)
Shoulda.remove_context
end
def merge_block(&blk)
blk.bind(self).call
end
def context(name, &blk)
self.subcontexts << Context.new(name, self, &blk)
end
def setup(&blk)
self.setup_blocks << blk
end
def teardown(&blk)
self.teardown_blocks << blk
end
def should(name_or_matcher, options = {}, &blk)
if name_or_matcher.respond_to?(:description) && name_or_matcher.respond_to?(:matches?)
name = name_or_matcher.description
blk = lambda { assert_accepts name_or_matcher, subject }
else
name = name_or_matcher
end
if blk
self.shoulds << { :name => name, :before => options[:before], :block => blk }
else
self.should_eventuallys << { :name => name }
end
end
def should_not(matcher)
name = matcher.description
blk = lambda { assert_rejects matcher, subject }
self.shoulds << { :name => "not #{name}", :block => blk }
end
def should_eventually(name, &blk)
self.should_eventuallys << { :name => name, :block => blk }
end
def subject(&block)
self.subject_block = block
end
def subject_block
return @subject_block if @subject_block
parent.subject_block
end
def full_name
parent_name = parent.full_name if am_subcontext?
return [parent_name, name].join(" ").strip
end
def am_subcontext?
parent.is_a?(self.class) # my parent is the same class as myself.
end
def test_unit_class
am_subcontext? ? parent.test_unit_class : parent
end
def test_methods
@test_methods ||= Hash.new { |h,k|
h[k] = Hash[k.instance_methods.map { |n| [n, true] }]
}
end
def create_test_from_should_hash(should)
test_name = ["test:", full_name, "should", "#{should[:name]}. "].flatten.join(' ').to_sym
if test_methods[test_unit_class][test_name.to_s] then
warn " * WARNING: '#{test_name}' is already defined"
end
test_methods[test_unit_class][test_name.to_s] = true
context = self
test_unit_class.send(:define_method, test_name) do
@shoulda_context = context
begin
context.run_parent_setup_blocks(self)
should[:before].bind(self).call if should[:before]
context.run_current_setup_blocks(self)
should[:block].bind(self).call
ensure
context.run_all_teardown_blocks(self)
end
end
end
def run_all_setup_blocks(binding)
run_parent_setup_blocks(binding)
run_current_setup_blocks(binding)
end
def run_parent_setup_blocks(binding)
self.parent.run_all_setup_blocks(binding) if am_subcontext?
end
def run_current_setup_blocks(binding)
setup_blocks.each do |setup_block|
setup_block.bind(binding).call
end
end
def run_all_teardown_blocks(binding)
teardown_blocks.reverse.each do |teardown_block|
teardown_block.bind(binding).call
end
self.parent.run_all_teardown_blocks(binding) if am_subcontext?
end
def print_should_eventuallys
should_eventuallys.each do |should|
test_name = [full_name, "should", "#{should[:name]}. "].flatten.join(' ')
puts " * DEFERRED: " + test_name
end
end
def build
shoulds.each do |should|
create_test_from_should_hash(should)
end
subcontexts.each { |context| context.build }
print_should_eventuallys
end
def method_missing(method, *args, &blk)
test_unit_class.send(method, *args, &blk)
end
end
end

View file

@ -1,22 +1,23 @@
require 'shoulda/active_record/matchers'
require 'shoulda/action_controller/matchers'
require 'shoulda/action_mailer/matchers'
# :enddoc:
module RSpec
module Matchers
if defined?(::ActiveRecord)
require 'shoulda/active_record'
module RSpec::Matchers
include Shoulda::ActiveRecord::Matchers
end
module Rails
module ControllerExampleGroup
include Shoulda::ActionController::Matchers
end
module MailerExampleGroup
include Shoulda::ActionMailer::Matchers
end
end
end
if defined?(::ActionController)
require 'shoulda/action_controller'
module Rails::ControllerExampleGroup
include Shoulda::ActionController::Matchers
end
end
if defined?(::ActionMailer)
require 'shoulda/action_mailer'
module Rails::MailerExampleGroup
include Shoulda::ActionMailer::Matchers
end
end

View file

@ -1,17 +1,40 @@
require 'test/unit'
# :enddoc:
require 'shoulda/context'
require 'shoulda/proc_extensions'
require 'shoulda/assertions'
require 'shoulda/autoload_macros'
require 'shoulda/rails' if defined? RAILS_ROOT
if defined?(ActionController)
require 'shoulda/action_controller'
module Test # :nodoc: all
module Unit
class TestCase
include Shoulda::InstanceMethods
extend Shoulda::ClassMethods
include Shoulda::Assertions
class ActionController::TestCase
include Shoulda::ActionController::Matchers
extend Shoulda::ActionController::Matchers
def subject
@controller
end
end
end
if defined?(ActionMailer)
require 'shoulda/action_mailer'
module Test
module Unit
class TestCase
include Shoulda::ActionMailer::Matchers
extend Shoulda::ActionMailer::Matchers
end
end
end
end
if defined?(ActiveRecord)
require 'shoulda/active_record'
module Test
module Unit
class TestCase
include Shoulda::ActiveRecord::Matchers
extend Shoulda::ActiveRecord::Matchers
end
end
end
end

View file

@ -1,14 +0,0 @@
# Stolen straight from ActiveSupport
class Proc #:nodoc:
def bind(object)
block, time = self, Time.now
(class << object; self end).class_eval do
method_name = "__bind_#{time.to_i}_#{time.usec}"
define_method(method_name, &block)
method = instance_method(method_name)
remove_method(method_name)
method
end.bind(object)
end
end

View file

@ -1,8 +0,0 @@
require 'rubygems'
require 'active_support'
require 'shoulda'
require 'shoulda/active_record' if defined? ActiveRecord::Base
require 'shoulda/action_controller' if defined? ActionController::Base
require 'shoulda/action_mailer' if defined? ActionMailer::Base

View file

@ -1,3 +0,0 @@
Dir[File.join(File.dirname(__FILE__), 'tasks', '*.rake')].each do |f|
load f
end

View file

@ -1,29 +0,0 @@
namespace :shoulda do
desc "List the names of the test methods in a specification like format"
task :list do
$LOAD_PATH.unshift("test")
require 'test/unit'
require 'rubygems'
require 'active_support'
# bug in test unit. Set to true to stop from running.
Test::Unit.run = true
test_files = Dir.glob(File.join('test', '**', '*_test.rb'))
test_files.each do |file|
load file
klass = File.basename(file, '.rb').classify
unless Object.const_defined?(klass.to_s)
puts "Skipping #{klass} because it doesn't map to a Class"
next
end
klass = klass.constantize
puts klass.name.gsub('Test', '')
test_methods = klass.instance_methods.grep(/^test/).map {|s| s.gsub(/^test: /, '')}.sort
test_methods.each {|m| puts " " + m }
end
end
end

View file

@ -1,28 +0,0 @@
namespace :shoulda do
# From http://blog.internautdesign.com/2007/11/2/a-yaml_to_shoulda-rake-task
# David.Lowenfels@gmail.com
desc "Converts a YAML file (FILE=./path/to/yaml) into a Shoulda skeleton"
task :from_yaml do
require 'yaml'
def yaml_to_context(hash, indent = 0)
indent1 = ' ' * indent
indent2 = ' ' * (indent + 1)
hash.each_pair do |context, shoulds|
puts indent1 + "context \"#{context}\" do"
puts
shoulds.each do |should|
yaml_to_context( should, indent + 1 ) and next if should.is_a?( Hash )
puts indent2 + "should_eventually \"" + should.gsub(/^should +/,'') + "\" do"
puts indent2 + "end"
puts
end
puts indent1 + "end"
end
end
puts("Please pass in a FILE argument.") and exit unless ENV['FILE']
yaml_to_context( YAML.load_file( ENV['FILE'] ) )
end
end

View file

@ -1,8 +0,0 @@
if RAILS_ENV == 'test'
if defined? Spec
require 'shoulda/integrations/rspec'
else
require 'shoulda/integrations/test_unit'
Shoulda.autoload_macros RAILS_ROOT, File.join("vendor", "{plugins,gems}", "*")
end
end

7
spec/rails3_root/Gemfile Normal file
View file

@ -0,0 +1,7 @@
source 'http://rubygems.org'
gem 'rails', '3.0.0.beta4'
gem 'sqlite3-ruby', :require => 'sqlite3'
gem 'mocha'
gem 'rspec-rails', '2.0.0.beta.12'

View file

@ -31,6 +31,7 @@ GEM
arel (0.4.0)
activesupport (>= 3.0.0.beta)
builder (2.1.2)
diff-lcs (1.1.2)
erubis (2.6.6)
abstract (>= 1.0.0)
i18n (0.4.1)
@ -42,6 +43,7 @@ GEM
mime-types (1.16)
mocha (0.9.10)
rake
nokogiri (1.4.4)
polyglot (0.3.1)
rack (1.1.0)
rack-mount (0.6.13)
@ -62,11 +64,26 @@ GEM
rake (>= 0.8.3)
thor (~> 0.13.6)
rake (0.8.7)
rspec (2.0.0.beta.12)
rspec-core (= 2.0.0.beta.12)
rspec-expectations (= 2.0.0.beta.12)
rspec-mocks (= 2.0.0.beta.12)
rspec-core (2.0.0.beta.12)
rspec-expectations (2.0.0.beta.12)
diff-lcs (>= 1.1.2)
rspec-mocks (2.0.0.beta.12)
rspec-rails (2.0.0.beta.12)
rspec (= 2.0.0.beta.12)
webrat (>= 0.7.0)
sqlite3-ruby (1.3.2)
thor (0.13.8)
treetop (1.4.9)
polyglot (>= 0.3.1)
tzinfo (0.3.23)
webrat (0.7.2)
nokogiri (>= 1.2.0)
rack (>= 1.0)
rack-test (>= 0.5.3)
PLATFORMS
ruby
@ -74,4 +91,5 @@ PLATFORMS
DEPENDENCIES
mocha
rails (= 3.0.0.beta4)
rspec-rails (= 2.0.0.beta.12)
sqlite3-ruby

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