Organizando plugins e gems.
This commit is contained in:
32
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller.rb
vendored
Normal file
32
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller.rb
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
require 'shoulda'
|
||||
require 'shoulda/action_controller/helpers'
|
||||
require 'shoulda/action_controller/matchers'
|
||||
require 'shoulda/action_controller/macros'
|
||||
require 'shoulda/action_controller/resource_options'
|
||||
|
||||
module Test # :nodoc: all
|
||||
module Unit
|
||||
class TestCase
|
||||
include Shoulda::ActionController::Matchers
|
||||
include Shoulda::ActionController::Helpers
|
||||
extend Shoulda::ActionController::Macros
|
||||
Shoulda::ActionController::VALID_FORMATS.each do |format|
|
||||
include "Shoulda::ActionController::#{format.to_s.upcase}".constantize
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'shoulda/active_record/assertions'
|
||||
require 'shoulda/action_mailer/assertions'
|
||||
|
||||
module ActionController #:nodoc: all
|
||||
module Integration
|
||||
class Session
|
||||
include Shoulda::Assertions
|
||||
include Shoulda::Helpers
|
||||
include Shoulda::ActiveRecord::Assertions
|
||||
include Shoulda::ActionMailer::Assertions
|
||||
end
|
||||
end
|
||||
end
|
||||
199
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/formats/html.rb
vendored
Normal file
199
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/formats/html.rb
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActionController # :nodoc:
|
||||
module HTML # :nodoc: all
|
||||
def self.included(other)
|
||||
other.class_eval do
|
||||
extend Shoulda::ActionController::HTML::ClassMethods
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def controller_name_from_class
|
||||
self.name.gsub(/Test/, '')
|
||||
end
|
||||
|
||||
def make_show_html_tests(res)
|
||||
context "on GET to #{controller_name_from_class}#show" do
|
||||
setup do
|
||||
record = get_existing_record(res)
|
||||
parent_params = make_parent_params(res, record)
|
||||
get :show, parent_params.merge({ res.identifier => record.to_param })
|
||||
end
|
||||
|
||||
if res.denied.actions.include?(:show)
|
||||
should_not_assign_to res.object
|
||||
should_redirect_to res.denied.redirect
|
||||
should_set_the_flash_to res.denied.flash
|
||||
else
|
||||
should_assign_to res.object
|
||||
should_respond_with :success
|
||||
should_render_template :show
|
||||
should_not_set_the_flash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def make_edit_html_tests(res)
|
||||
context "on GET to #{controller_name_from_class}#edit" do
|
||||
setup do
|
||||
@record = get_existing_record(res)
|
||||
parent_params = make_parent_params(res, @record)
|
||||
get :edit, parent_params.merge({ res.identifier => @record.to_param })
|
||||
end
|
||||
|
||||
if res.denied.actions.include?(:edit)
|
||||
should_not_assign_to res.object
|
||||
should_redirect_to res.denied.redirect
|
||||
should_set_the_flash_to res.denied.flash
|
||||
else
|
||||
should_assign_to res.object
|
||||
should_respond_with :success
|
||||
should_render_template :edit
|
||||
should_not_set_the_flash
|
||||
should_render_a_form
|
||||
should "set @#{res.object} to requested instance" do
|
||||
assert_equal @record, assigns(res.object)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def make_index_html_tests(res)
|
||||
context "on GET to #{controller_name_from_class}#index" do
|
||||
setup do
|
||||
record = get_existing_record(res) rescue nil
|
||||
parent_params = make_parent_params(res, record)
|
||||
get(:index, parent_params)
|
||||
end
|
||||
|
||||
if res.denied.actions.include?(:index)
|
||||
should_not_assign_to res.object.to_s.pluralize
|
||||
should_redirect_to res.denied.redirect
|
||||
should_set_the_flash_to res.denied.flash
|
||||
else
|
||||
should_respond_with :success
|
||||
should_assign_to res.object.to_s.pluralize
|
||||
should_render_template :index
|
||||
should_not_set_the_flash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def make_new_html_tests(res)
|
||||
context "on GET to #{controller_name_from_class}#new" do
|
||||
setup do
|
||||
record = get_existing_record(res) rescue nil
|
||||
parent_params = make_parent_params(res, record)
|
||||
get(:new, parent_params)
|
||||
end
|
||||
|
||||
if res.denied.actions.include?(:new)
|
||||
should_not_assign_to res.object
|
||||
should_redirect_to res.denied.redirect
|
||||
should_set_the_flash_to res.denied.flash
|
||||
else
|
||||
should_respond_with :success
|
||||
should_assign_to res.object
|
||||
should_not_set_the_flash
|
||||
should_render_template :new
|
||||
should_render_a_form
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def make_destroy_html_tests(res)
|
||||
context "on DELETE to #{controller_name_from_class}#destroy" do
|
||||
setup do
|
||||
@record = get_existing_record(res)
|
||||
parent_params = make_parent_params(res, @record)
|
||||
delete :destroy, parent_params.merge({ res.identifier => @record.to_param })
|
||||
end
|
||||
|
||||
if res.denied.actions.include?(:destroy)
|
||||
should_redirect_to res.denied.redirect
|
||||
should_set_the_flash_to res.denied.flash
|
||||
|
||||
should "not destroy record" do
|
||||
assert_nothing_raised { assert @record.reload }
|
||||
end
|
||||
else
|
||||
should_set_the_flash_to res.destroy.flash
|
||||
if res.destroy.redirect.is_a? Symbol
|
||||
should_respond_with res.destroy.redirect
|
||||
else
|
||||
should_redirect_to res.destroy.redirect
|
||||
end
|
||||
|
||||
should "destroy record" do
|
||||
assert_raises(::ActiveRecord::RecordNotFound, "@#{res.object} was not destroyed.") do
|
||||
@record.reload
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def make_create_html_tests(res)
|
||||
context "on POST to #{controller_name_from_class}#create with #{res.create.params.inspect}" do
|
||||
setup do
|
||||
record = get_existing_record(res) rescue nil
|
||||
parent_params = make_parent_params(res, record)
|
||||
@count = res.klass.count
|
||||
post :create, parent_params.merge(res.object => res.create.params)
|
||||
end
|
||||
|
||||
if res.denied.actions.include?(:create)
|
||||
should_redirect_to res.denied.redirect
|
||||
should_set_the_flash_to res.denied.flash
|
||||
should_not_assign_to res.object
|
||||
|
||||
should "not create new record" do
|
||||
assert_equal @count, res.klass.count
|
||||
end
|
||||
else
|
||||
should_assign_to res.object
|
||||
should_set_the_flash_to res.create.flash
|
||||
if res.create.redirect.is_a? Symbol
|
||||
should_respond_with res.create.redirect
|
||||
else
|
||||
should_redirect_to res.create.redirect
|
||||
end
|
||||
|
||||
should "not have errors on @#{res.object}" do
|
||||
assert_equal [], pretty_error_messages(assigns(res.object)), "@#{res.object} has errors:"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def make_update_html_tests(res)
|
||||
context "on PUT to #{controller_name_from_class}#update with #{res.create.params.inspect}" do
|
||||
setup do
|
||||
@record = get_existing_record(res)
|
||||
parent_params = make_parent_params(res, @record)
|
||||
put :update, parent_params.merge(res.identifier => @record.to_param, res.object => res.update.params)
|
||||
end
|
||||
|
||||
if res.denied.actions.include?(:update)
|
||||
should_not_assign_to res.object
|
||||
should_redirect_to res.denied.redirect
|
||||
should_set_the_flash_to res.denied.flash
|
||||
else
|
||||
should_assign_to res.object
|
||||
should_set_the_flash_to(res.update.flash)
|
||||
if res.update.redirect.is_a? Symbol
|
||||
should_respond_with res.update.redirect
|
||||
else
|
||||
should_redirect_to res.update.redirect
|
||||
end
|
||||
|
||||
should "not have errors on @#{res.object}" do
|
||||
assert_equal [], pretty_error_messages(assigns(res.object)), "@#{res.object} has errors:"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
168
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/formats/xml.rb
vendored
Normal file
168
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/formats/xml.rb
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActionController # :nodoc:
|
||||
module XML
|
||||
def self.included(other) #:nodoc:
|
||||
other.class_eval do
|
||||
extend Shoulda::ActionController::XML::ClassMethods
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Macro that creates a test asserting that the controller responded with an XML content-type
|
||||
# and that the XML contains +<name/>+ as the root element.
|
||||
def should_respond_with_xml_for(name = nil)
|
||||
should "have ContentType set to 'application/xml'" do
|
||||
assert_xml_response
|
||||
end
|
||||
|
||||
if name
|
||||
should "return <#{name}/> as the root element" do
|
||||
body = @response.body.first(100).map {|l| " #{l}"}
|
||||
assert_select name.to_s.dasherize, 1, "Body:\n#{body}...\nDoes not have <#{name}/> as the root element."
|
||||
end
|
||||
end
|
||||
end
|
||||
alias should_respond_with_xml should_respond_with_xml_for
|
||||
|
||||
protected
|
||||
|
||||
def make_show_xml_tests(res) # :nodoc:
|
||||
context "on GET to #{controller_name_from_class}#show as xml" do
|
||||
setup do
|
||||
request_xml
|
||||
record = get_existing_record(res)
|
||||
parent_params = make_parent_params(res, record)
|
||||
get :show, parent_params.merge({ res.identifier => record.to_param })
|
||||
end
|
||||
|
||||
if res.denied.actions.include?(:show)
|
||||
should_not_assign_to res.object
|
||||
should_respond_with 401
|
||||
else
|
||||
should_assign_to res.object
|
||||
should_respond_with :success
|
||||
should_respond_with_xml_for res.object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def make_edit_xml_tests(res) # :nodoc:
|
||||
# XML doesn't need an :edit action
|
||||
end
|
||||
|
||||
def make_new_xml_tests(res) # :nodoc:
|
||||
# XML doesn't need a :new action
|
||||
end
|
||||
|
||||
def make_index_xml_tests(res) # :nodoc:
|
||||
context "on GET to #{controller_name_from_class}#index as xml" do
|
||||
setup do
|
||||
request_xml
|
||||
parent_params = make_parent_params(res)
|
||||
get(:index, parent_params)
|
||||
end
|
||||
|
||||
if res.denied.actions.include?(:index)
|
||||
should_not_assign_to res.object.to_s.pluralize
|
||||
should_respond_with 401
|
||||
else
|
||||
should_respond_with :success
|
||||
should_respond_with_xml_for res.object.to_s.pluralize
|
||||
should_assign_to res.object.to_s.pluralize
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def make_destroy_xml_tests(res) # :nodoc:
|
||||
context "on DELETE to #{controller_name_from_class}#destroy as xml" do
|
||||
setup do
|
||||
request_xml
|
||||
@record = get_existing_record(res)
|
||||
parent_params = make_parent_params(res, @record)
|
||||
delete :destroy, parent_params.merge({ res.identifier => @record.to_param })
|
||||
end
|
||||
|
||||
if res.denied.actions.include?(:destroy)
|
||||
should_respond_with 401
|
||||
|
||||
should "not destroy record" do
|
||||
assert @record.reload
|
||||
end
|
||||
else
|
||||
should "destroy record" do
|
||||
assert_raises(::ActiveRecord::RecordNotFound, "@#{res.object} was not destroyed.") do
|
||||
@record.reload
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def make_create_xml_tests(res) # :nodoc:
|
||||
context "on POST to #{controller_name_from_class}#create as xml" do
|
||||
setup do
|
||||
request_xml
|
||||
parent_params = make_parent_params(res)
|
||||
@count = res.klass.count
|
||||
post :create, parent_params.merge(res.object => res.create.params)
|
||||
end
|
||||
|
||||
if res.denied.actions.include?(:create)
|
||||
should_respond_with 401
|
||||
should_not_assign_to res.object
|
||||
|
||||
should "not create new record" do
|
||||
assert_equal @count, res.klass.count
|
||||
end
|
||||
else
|
||||
should_assign_to res.object
|
||||
|
||||
should "not have errors on @#{res.object}" do
|
||||
assert_equal [], pretty_error_messages(assigns(res.object)), "@#{res.object} has errors:"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def make_update_xml_tests(res) # :nodoc:
|
||||
context "on PUT to #{controller_name_from_class}#update as xml" do
|
||||
setup do
|
||||
request_xml
|
||||
@record = get_existing_record(res)
|
||||
parent_params = make_parent_params(res, @record)
|
||||
put :update, parent_params.merge(res.identifier => @record.to_param, res.object => res.update.params)
|
||||
end
|
||||
|
||||
if res.denied.actions.include?(:update)
|
||||
should_not_assign_to res.object
|
||||
should_respond_with 401
|
||||
else
|
||||
should_assign_to res.object
|
||||
|
||||
should "not have errors on @#{res.object}" do
|
||||
assert_equal [], assigns(res.object).errors.full_messages, "@#{res.object} has errors:"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the next request's format to 'application/xml'
|
||||
def request_xml
|
||||
@request.accept = "application/xml"
|
||||
end
|
||||
|
||||
# Asserts that the controller's response was 'application/xml'
|
||||
def assert_xml_response
|
||||
content_type = (@response.headers["Content-Type"] || @response.headers["type"]).to_s
|
||||
regex = %r{\bapplication/xml\b}
|
||||
|
||||
msg = "Content Type '#{content_type.inspect}' doesn't match '#{regex.inspect}'\n"
|
||||
msg += "Body: #{@response.body.first(100).chomp} ..."
|
||||
|
||||
assert_match regex, content_type, msg
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
64
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/helpers.rb
vendored
Normal file
64
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/helpers.rb
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActionController # :nodoc:
|
||||
module Helpers # :nodoc:
|
||||
private # :enddoc:
|
||||
|
||||
SPECIAL_INSTANCE_VARIABLES = %w{
|
||||
_cookies
|
||||
_flash
|
||||
_headers
|
||||
_params
|
||||
_request
|
||||
_response
|
||||
_session
|
||||
action_name
|
||||
before_filter_chain_aborted
|
||||
cookies
|
||||
flash
|
||||
headers
|
||||
ignore_missing_templates
|
||||
logger
|
||||
params
|
||||
request
|
||||
request_origin
|
||||
response
|
||||
session
|
||||
template
|
||||
template_class
|
||||
template_root
|
||||
url
|
||||
variables_added
|
||||
}.map(&:to_s)
|
||||
|
||||
def instantiate_variables_from_assigns(*names, &blk)
|
||||
old = {}
|
||||
names = (@response.template.assigns.keys - SPECIAL_INSTANCE_VARIABLES) if names.empty?
|
||||
names.each do |name|
|
||||
old[name] = instance_variable_get("@#{name}")
|
||||
instance_variable_set("@#{name}", assigns(name.to_sym))
|
||||
end
|
||||
blk.call
|
||||
names.each do |name|
|
||||
instance_variable_set("@#{name}", old[name])
|
||||
end
|
||||
end
|
||||
|
||||
def get_existing_record(res) # :nodoc:
|
||||
returning(instance_variable_get("@#{res.object}")) do |record|
|
||||
assert(record, "This test requires you to set @#{res.object} in your setup block")
|
||||
end
|
||||
end
|
||||
|
||||
def make_parent_params(resource, record = nil, parent_names = nil) # :nodoc:
|
||||
parent_names ||= resource.parents.reverse
|
||||
return {} if parent_names == [] # Base case
|
||||
parent_name = parent_names.shift
|
||||
parent = record ? record.send(parent_name) : parent_name.to_s.classify.constantize.find(:first)
|
||||
|
||||
{ :"#{parent_name}_id" => parent.to_param }.merge(make_parent_params(resource, parent, parent_names))
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
296
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/macros.rb
vendored
Normal file
296
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/macros.rb
vendored
Normal file
@@ -0,0 +1,296 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActionController # :nodoc:
|
||||
# = Macro test helpers for your controllers
|
||||
#
|
||||
# By using the macro helpers you can quickly and easily create concise and easy to read test suites.
|
||||
#
|
||||
# This code segment:
|
||||
# context "on GET to :show for first record" do
|
||||
# setup do
|
||||
# get :show, :id => 1
|
||||
# end
|
||||
#
|
||||
# should_assign_to :user
|
||||
# should_respond_with :success
|
||||
# should_render_template :show
|
||||
# should_not_set_the_flash
|
||||
#
|
||||
# should "do something else really cool" do
|
||||
# assert_equal 1, assigns(:user).id
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# Would produce 5 tests for the +show+ action
|
||||
module Macros
|
||||
include Matchers
|
||||
|
||||
def should_be_restful(&blk) # :yields: resource
|
||||
resource = ResourceOptions.new
|
||||
blk.call(resource)
|
||||
resource.normalize!(self)
|
||||
|
||||
resource.formats.each do |format|
|
||||
resource.actions.each do |action|
|
||||
if self.respond_to? :"make_#{action}_#{format}_tests"
|
||||
self.send(:"make_#{action}_#{format}_tests", resource)
|
||||
else
|
||||
should "test #{action} #{format}" do
|
||||
flunk "Test for #{action} as #{format} not implemented"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Macro that creates a test asserting that the flash contains the given value.
|
||||
# val can be a String, a Regex, or nil (indicating that the flash should not be set)
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# should_set_the_flash_to "Thank you for placing this order."
|
||||
# should_set_the_flash_to /created/i
|
||||
# should_set_the_flash_to nil
|
||||
def should_set_the_flash_to(val)
|
||||
matcher = set_the_flash.to(val)
|
||||
if val
|
||||
should matcher.description do
|
||||
assert_accepts matcher, @controller
|
||||
end
|
||||
else
|
||||
should "not #{matcher.description}" do
|
||||
assert_rejects matcher, @controller
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Macro that creates a test asserting that the flash is empty. Same as
|
||||
# @should_set_the_flash_to nil@
|
||||
def should_not_set_the_flash
|
||||
should_set_the_flash_to nil
|
||||
end
|
||||
|
||||
# Macro that creates a test asserting that filter_parameter_logging
|
||||
#
|
||||
# is set for the specified keys
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# should_filter_params :password, :ssn
|
||||
def should_filter_params(*keys)
|
||||
keys.each do |key|
|
||||
matcher = filter_param(key)
|
||||
should matcher.description do
|
||||
assert_accepts matcher, @controller
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Macro that creates a test asserting that the controller assigned to
|
||||
# each of the named instance variable(s).
|
||||
#
|
||||
# Options:
|
||||
# * <tt>:class</tt> - The expected class of the instance variable being checked.
|
||||
# * <tt>:equals</tt> - A string which is evaluated and compared for equality with
|
||||
# the instance variable being checked.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# should_assign_to :user, :posts
|
||||
# should_assign_to :user, :class => User
|
||||
# should_assign_to(:user) { @user }
|
||||
def should_assign_to(*names, &block)
|
||||
opts = names.extract_options!
|
||||
if opts[:equals]
|
||||
warn "[DEPRECATION] should_assign_to :var, :equals => 'val' " <<
|
||||
"is deprecated. Use should_assign_to(:var) { 'val' } instead."
|
||||
end
|
||||
names.each do |name|
|
||||
matcher = assign_to(name).with_kind_of(opts[:class])
|
||||
test_name = matcher.description
|
||||
test_name << " which is equal to #{opts[:equals]}" if opts[:equals]
|
||||
should test_name do
|
||||
if opts[:equals]
|
||||
instantiate_variables_from_assigns do
|
||||
expected_value = eval(opts[:equals],
|
||||
self.send(:binding),
|
||||
__FILE__,
|
||||
__LINE__)
|
||||
matcher = matcher.with(expected_value)
|
||||
end
|
||||
elsif block
|
||||
expected_value = instance_eval(&block)
|
||||
matcher = matcher.with(expected_value)
|
||||
end
|
||||
|
||||
assert_accepts matcher, @controller
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Macro that creates a test asserting that the controller did not assign to
|
||||
# any of the named instance variable(s).
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# should_not_assign_to :user, :posts
|
||||
def should_not_assign_to(*names)
|
||||
names.each do |name|
|
||||
matcher = assign_to(name)
|
||||
should "not #{matcher.description}" do
|
||||
assert_rejects matcher, @controller
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Macro that creates a test asserting that the controller responded with a 'response' status code.
|
||||
# Example:
|
||||
#
|
||||
# should_respond_with :success
|
||||
def should_respond_with(response)
|
||||
should "respond with #{response}" do
|
||||
matcher = respond_with(response)
|
||||
assert_accepts matcher, @controller
|
||||
end
|
||||
end
|
||||
|
||||
# Macro that creates a test asserting that the response content type was 'content_type'.
|
||||
# Example:
|
||||
#
|
||||
# should_respond_with_content_type 'application/rss+xml'
|
||||
# should_respond_with_content_type :rss
|
||||
# should_respond_with_content_type /rss/
|
||||
def should_respond_with_content_type(content_type)
|
||||
should "respond with content type of #{content_type}" do
|
||||
matcher = respond_with_content_type(content_type)
|
||||
assert_accepts matcher, @controller
|
||||
end
|
||||
end
|
||||
|
||||
# Macro that creates a test asserting that a value returned from the session is correct.
|
||||
# The given string is evaled to produce the resulting redirect path. All of the instance variables
|
||||
# set by the controller are available to the evaled string.
|
||||
# Example:
|
||||
#
|
||||
# should_set_session(:user_id) { '@user.id' }
|
||||
# should_set_session(:message) { "Free stuff" }
|
||||
def should_set_session(key, expected = nil, &block)
|
||||
matcher = set_session(key)
|
||||
if expected
|
||||
warn "[DEPRECATION] should_set_session :key, 'val' is deprecated. " <<
|
||||
"Use should_set_session(:key) { 'val' } instead."
|
||||
end
|
||||
should matcher.description do
|
||||
if expected
|
||||
instantiate_variables_from_assigns do
|
||||
expected_value = eval(expected,
|
||||
self.send(:binding),
|
||||
__FILE__,
|
||||
__LINE__)
|
||||
matcher = matcher.to(expected_value)
|
||||
end
|
||||
else
|
||||
expected_value = instance_eval(&block)
|
||||
matcher = matcher.to(expected_value)
|
||||
end
|
||||
assert_accepts matcher, @controller
|
||||
end
|
||||
end
|
||||
|
||||
# Deprecated. See should_set_session
|
||||
def should_return_from_session(key, expected)
|
||||
warn "[DEPRECATION] should_require_attributes is deprecated. " <<
|
||||
"Use should_set_session instead."
|
||||
should_set_session(key, expected)
|
||||
end
|
||||
|
||||
# Macro that creates a test asserting that the controller rendered the given template.
|
||||
# Example:
|
||||
#
|
||||
# should_render_template :new
|
||||
def should_render_template(template)
|
||||
should "render template #{template.inspect}" do
|
||||
assert_template template.to_s
|
||||
end
|
||||
end
|
||||
|
||||
# Macro that creates a test asserting that the controller rendered with the given layout.
|
||||
# Example:
|
||||
#
|
||||
# should_render_with_layout 'special'
|
||||
def should_render_with_layout(expected_layout = 'application')
|
||||
matcher = render_with_layout(expected_layout)
|
||||
if expected_layout
|
||||
should matcher.description do
|
||||
assert_accepts matcher, @controller
|
||||
end
|
||||
else
|
||||
should "render without layout" do
|
||||
assert_rejects matcher, @controller
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Macro that creates a test asserting that the controller rendered without a layout.
|
||||
# Same as @should_render_with_layout false@
|
||||
def should_render_without_layout
|
||||
should_render_with_layout nil
|
||||
end
|
||||
|
||||
# Macro that creates a test asserting that the controller returned a redirect to the given path.
|
||||
# The given string is evaled to produce the resulting redirect path. All of the instance variables
|
||||
# set by the controller are available to the evaled string.
|
||||
# Example:
|
||||
#
|
||||
# should_redirect_to("the user's profile") { user_url(@user) }
|
||||
def should_redirect_to(description, &block)
|
||||
unless block
|
||||
warn "[DEPRECATION] should_redirect_to without a block is " <<
|
||||
"deprecated. Use should_redirect_to('somewhere') { } instead."
|
||||
end
|
||||
should "redirect to #{description}" do
|
||||
if block
|
||||
url = instance_eval(&block)
|
||||
else
|
||||
instantiate_variables_from_assigns do
|
||||
url = eval(description, self.send(:binding), __FILE__, __LINE__)
|
||||
end
|
||||
end
|
||||
assert_redirected_to url
|
||||
end
|
||||
end
|
||||
|
||||
# Macro that creates a routing test. It tries to use the given HTTP
|
||||
# +method+ on the given +path+, and asserts that it routes to the
|
||||
# given +options+.
|
||||
#
|
||||
# If you don't specify a :controller, it will try to guess the controller
|
||||
# based on the current test.
|
||||
#
|
||||
# +to_param+ is called on the +options+ given.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# should_route :get, "/posts", :controller => :posts, :action => :index
|
||||
# should_route :get, "/posts/new", :action => :new
|
||||
# should_route :post, "/posts", :action => :create
|
||||
# should_route :get, "/posts/1", :action => :show, :id => 1
|
||||
# should_route :edit, "/posts/1", :action => :show, :id => 1
|
||||
# should_route :put, "/posts/1", :action => :update, :id => 1
|
||||
# should_route :delete, "/posts/1", :action => :destroy, :id => 1
|
||||
# should_route :get, "/users/1/posts/1",
|
||||
# :action => :show, :id => 1, :user_id => 1
|
||||
#
|
||||
def should_route(method, path, options)
|
||||
unless options[:controller]
|
||||
options[:controller] = self.name.gsub(/ControllerTest$/, '').tableize
|
||||
end
|
||||
|
||||
matcher = route(method, path).to(options)
|
||||
|
||||
should matcher.description do
|
||||
assert_accepts matcher.in_context(self), self
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
37
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/matchers.rb
vendored
Normal file
37
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/matchers.rb
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
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'
|
||||
|
||||
module Shoulda # :nodoc:
|
||||
module ActionController # :nodoc:
|
||||
|
||||
# By using the macro helpers 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
|
||||
109
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/matchers/assign_to_matcher.rb
vendored
Normal file
109
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/matchers/assign_to_matcher.rb
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActionController # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures that the controller assigned to the named instance variable.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>with_kind_of</tt> - The expected class of the instance variable
|
||||
# being checked.
|
||||
# * <tt>with</tt> - The value that should be assigned.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# it { should assign_to(:user) }
|
||||
# it { should_not assign_to(:user) }
|
||||
# it { should assign_to(:user).with_kind_of(User) }
|
||||
# it { should assign_to(:user).with(@user) }
|
||||
def assign_to(variable)
|
||||
AssignToMatcher.new(variable)
|
||||
end
|
||||
|
||||
class AssignToMatcher # :nodoc:
|
||||
|
||||
def initialize(variable)
|
||||
@variable = variable.to_s
|
||||
end
|
||||
|
||||
def with_kind_of(expected_class)
|
||||
@expected_class = expected_class
|
||||
self
|
||||
end
|
||||
|
||||
def with(expected_value)
|
||||
@expected_value = expected_value
|
||||
self
|
||||
end
|
||||
|
||||
def matches?(controller)
|
||||
@controller = controller
|
||||
assigned_value? && kind_of_expected_class? && equal_to_expected_value?
|
||||
end
|
||||
|
||||
attr_reader :failure_message, :negative_failure_message
|
||||
|
||||
def description
|
||||
description = "assign @#{@variable}"
|
||||
description << " with a kind of #{@expected_class}" if @expected_class
|
||||
description
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assigned_value?
|
||||
if assigned_value.nil?
|
||||
@failure_message =
|
||||
"Expected action to assign a value for @#{@variable}"
|
||||
false
|
||||
else
|
||||
@negative_failure_message =
|
||||
"Didn't expect action to assign a value for @#{@variable}, " <<
|
||||
"but it was assigned to #{assigned_value.inspect}"
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def kind_of_expected_class?
|
||||
return true unless @expected_class
|
||||
if assigned_value.kind_of?(@expected_class)
|
||||
@negative_failure_message =
|
||||
"Didn't expect action to assign a kind of #{@expected_class} " <<
|
||||
"for #{@variable}, but got one anyway"
|
||||
true
|
||||
else
|
||||
@failure_message =
|
||||
"Expected action to assign a kind of #{@expected_class} " <<
|
||||
"for #{@variable}, but got #{@variable.inspect} " <<
|
||||
"(#{@variable.class.name})"
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def equal_to_expected_value?
|
||||
return true unless @expected_value
|
||||
if @expected_value == assigned_value
|
||||
@negative_failure_message =
|
||||
"Didn't expect action to assign #{@expected_value.inspect} " <<
|
||||
"for #{@variable}, but got it anyway"
|
||||
true
|
||||
else
|
||||
@failure_message =
|
||||
"Expected action to assign #{@expected_value.inspect} " <<
|
||||
"for #{@variable}, but got #{assigned_value.inspect}"
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def assigned_value
|
||||
assigns[@variable]
|
||||
end
|
||||
|
||||
def assigns
|
||||
@controller.response.template.assigns
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,57 @@
|
||||
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)
|
||||
end
|
||||
|
||||
def filters_key?
|
||||
filtered_value == '[FILTERED]'
|
||||
end
|
||||
|
||||
def filtered_value
|
||||
filtered = @controller.send(:filter_parameters,
|
||||
@key.to_s => @key.to_s)
|
||||
filtered[@key.to_s]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,81 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActionController # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures that the controller rendered with the given layout.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# it { should render_with_layout }
|
||||
# it { should render_with_layout(:special) }
|
||||
# it { should_not render_with_layout }
|
||||
def render_with_layout(layout = nil)
|
||||
RenderWithLayout.new(layout)
|
||||
end
|
||||
|
||||
class RenderWithLayout # :nodoc:
|
||||
|
||||
def initialize(layout)
|
||||
@layout = layout.to_s unless layout.nil?
|
||||
end
|
||||
|
||||
def matches?(controller)
|
||||
@controller = controller
|
||||
rendered_with_layout? && rendered_with_expected_layout?
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Expected #{expectation}, but #{result}"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"Did not expect #{expectation}, but #{result}"
|
||||
end
|
||||
|
||||
def description
|
||||
description = "render with "
|
||||
if @layout.nil?
|
||||
description << "a layout"
|
||||
else
|
||||
description << "the #{@layout.inspect} layout"
|
||||
end
|
||||
description
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def rendered_with_layout?
|
||||
!layout.blank?
|
||||
end
|
||||
|
||||
def rendered_with_expected_layout?
|
||||
return true if @layout.nil?
|
||||
layout == @layout
|
||||
end
|
||||
|
||||
def layout
|
||||
layout = @controller.response.layout
|
||||
if layout.nil?
|
||||
nil
|
||||
else
|
||||
layout.split('/').last
|
||||
end
|
||||
end
|
||||
|
||||
def expectation
|
||||
"to #{description}"
|
||||
end
|
||||
|
||||
def result
|
||||
if rendered_with_layout?
|
||||
"rendered with the #{layout.inspect} layout"
|
||||
else
|
||||
"rendered without a layout"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,70 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActionController # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures a controller responded with expected 'response' content type.
|
||||
#
|
||||
# You can pass an explicit content type such as 'application/rss+xml'
|
||||
# or its symbolic equivalent :rss
|
||||
# or a regular expression such as /rss/
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# it { should respond_with_content_type(:xml) }
|
||||
# it { should respond_with_content_type(:csv) }
|
||||
# it { should respond_with_content_type(:atom) }
|
||||
# it { should respond_with_content_type(:yaml) }
|
||||
# it { should respond_with_content_type(:text) }
|
||||
# it { should respond_with_content_type('application/rss+xml') }
|
||||
# it { should respond_with_content_type(/json/) }
|
||||
def respond_with_content_type(content_type)
|
||||
RespondWithContentTypeMatcher.new(content_type)
|
||||
end
|
||||
|
||||
class RespondWithContentTypeMatcher # :nodoc:
|
||||
|
||||
def initialize(content_type)
|
||||
@content_type = if content_type.is_a?(Symbol)
|
||||
lookup_by_extension(content_type)
|
||||
else
|
||||
content_type
|
||||
end
|
||||
end
|
||||
|
||||
def matches?(controller)
|
||||
@controller = controller
|
||||
if @content_type.is_a?(Regexp)
|
||||
response_content_type =~ @content_type
|
||||
else
|
||||
response_content_type == @content_type
|
||||
end
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Expected #{expectation}"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"Did not expect #{expectation}"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def response_content_type
|
||||
@controller.response.content_type
|
||||
end
|
||||
|
||||
def lookup_by_extension(extension)
|
||||
Mime::Type.lookup_by_extension(extension.to_s).to_s
|
||||
end
|
||||
|
||||
def expectation
|
||||
"content type to be #{@content_type}, " <<
|
||||
"but was #{response_content_type}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,81 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActionController # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures a controller responded with expected 'response' status code.
|
||||
#
|
||||
# You can pass an explicit status number like 200, 301, 404, 500
|
||||
# or its symbolic equivalent :success, :redirect, :missing, :error.
|
||||
# See ActionController::StatusCodes for a full list.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# it { should respond_with(:success) }
|
||||
# it { should respond_with(:redirect) }
|
||||
# it { should respond_with(:missing) }
|
||||
# it { should respond_with(:error) }
|
||||
# it { should respond_with(501) }
|
||||
def respond_with(status)
|
||||
RespondWithMatcher.new(status)
|
||||
end
|
||||
|
||||
class RespondWithMatcher # :nodoc:
|
||||
|
||||
def initialize(status)
|
||||
@status = symbol_to_status_code(status)
|
||||
end
|
||||
|
||||
def matches?(controller)
|
||||
@controller = controller
|
||||
correct_status_code? || correct_status_code_range?
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Expected #{expectation}"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"Did not expect #{expectation}"
|
||||
end
|
||||
|
||||
def description
|
||||
"respond with #{@status}"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def correct_status_code?
|
||||
response_code == @status
|
||||
end
|
||||
|
||||
def correct_status_code_range?
|
||||
@status.is_a?(Range) &&
|
||||
@status.include?(response_code)
|
||||
end
|
||||
|
||||
def response_code
|
||||
@controller.response.response_code
|
||||
end
|
||||
|
||||
def symbol_to_status_code(potential_symbol)
|
||||
case potential_symbol
|
||||
when :success then 200
|
||||
when :redirect then 300..399
|
||||
when :missing then 404
|
||||
when :error then 500..599
|
||||
when Symbol
|
||||
::ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE[potential_symbol]
|
||||
else
|
||||
potential_symbol
|
||||
end
|
||||
end
|
||||
|
||||
def expectation
|
||||
"response to be a #{@status}, but was #{response_code}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
93
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/matchers/route_matcher.rb
vendored
Normal file
93
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/matchers/route_matcher.rb
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActionController # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures that requesting +path+ using +method+ routes to +options+.
|
||||
#
|
||||
# If you don't specify a controller, it will use the controller from the
|
||||
# example group.
|
||||
#
|
||||
# +to_param+ is called on the +options+ given.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# it { should route(:get, "/posts").
|
||||
# to(:controller => :posts, :action => :index) }
|
||||
# it { should route(:get, "/posts/new").to(:action => :new) }
|
||||
# it { should route(:post, "/posts").to(:action => :create) }
|
||||
# it { should route(:get, "/posts/1").to(:action => :show, :id => 1) }
|
||||
# it { should route(:edit, "/posts/1").to(:action => :show, :id => 1) }
|
||||
# it { should route(:put, "/posts/1").to(:action => :update, :id => 1) }
|
||||
# it { should route(:delete, "/posts/1").
|
||||
# to(:action => :destroy, :id => 1) }
|
||||
# it { should route(:get, "/users/1/posts/1").
|
||||
# to(:action => :show, :id => 1, :user_id => 1) }
|
||||
def route(method, path)
|
||||
RouteMatcher.new(method, path, self)
|
||||
end
|
||||
|
||||
class RouteMatcher # :nodoc:
|
||||
|
||||
def initialize(method, path, context)
|
||||
@method = method
|
||||
@path = path
|
||||
@context = context
|
||||
end
|
||||
|
||||
def to(params)
|
||||
@params = params
|
||||
self
|
||||
end
|
||||
|
||||
def in_context(context)
|
||||
@context = context
|
||||
self
|
||||
end
|
||||
|
||||
def matches?(controller)
|
||||
@controller = controller
|
||||
guess_controller!
|
||||
stringify_params!
|
||||
route_recognized?
|
||||
end
|
||||
|
||||
attr_reader :failure_message, :negative_failure_message
|
||||
|
||||
def description
|
||||
"route #{@method.to_s.upcase} #{@path} to/from #{@params.inspect}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def guess_controller!
|
||||
@params[:controller] ||= @controller.controller_path
|
||||
end
|
||||
|
||||
def stringify_params!
|
||||
@params.each do |key, value|
|
||||
@params[key] = value.to_param
|
||||
end
|
||||
end
|
||||
|
||||
def route_recognized?
|
||||
begin
|
||||
@context.send(:assert_routing,
|
||||
{ :method => @method, :path => @path },
|
||||
@params)
|
||||
|
||||
@negative_failure_message = "Didn't expect to #{description}"
|
||||
true
|
||||
rescue ::ActionController::RoutingError => error
|
||||
@failure_message = error.message
|
||||
false
|
||||
rescue Test::Unit::AssertionFailedError => error
|
||||
@failure_message = error.message
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,87 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActionController # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures that a session key was set to the expected value.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# it { should set_session(:message) }
|
||||
# it { should set_session(:user_id).to(@user.id) }
|
||||
# it { should_not set_session(:user_id) }
|
||||
def set_session(key)
|
||||
SetSessionMatcher.new(key)
|
||||
end
|
||||
|
||||
class SetSessionMatcher # :nodoc:
|
||||
|
||||
def initialize(key)
|
||||
@key = key.to_s
|
||||
end
|
||||
|
||||
def to(value)
|
||||
@value = value
|
||||
self
|
||||
end
|
||||
|
||||
def matches?(controller)
|
||||
@controller = controller
|
||||
(assigned_value? && assigned_correct_value?) || cleared_value?
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Expected #{expectation}, but #{result}"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"Didn't expect #{expectation}, but #{result}"
|
||||
end
|
||||
|
||||
def description
|
||||
description = "set session variable #{@key.inspect}"
|
||||
description << " to #{@value.inspect}" if defined?(@value)
|
||||
description
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assigned_value?
|
||||
!assigned_value.blank?
|
||||
end
|
||||
|
||||
def cleared_value?
|
||||
defined?(@value) && @value.nil? && assigned_value.nil?
|
||||
end
|
||||
|
||||
def assigned_correct_value?
|
||||
return true if @value.nil?
|
||||
assigned_value == @value
|
||||
end
|
||||
|
||||
def assigned_value
|
||||
session[@key]
|
||||
end
|
||||
|
||||
def session
|
||||
@controller.response.session.data
|
||||
end
|
||||
|
||||
def expectation
|
||||
expectation = "session variable #{@key} to be set"
|
||||
expectation << " to #{@value.inspect}" if @value
|
||||
expectation
|
||||
end
|
||||
|
||||
def result
|
||||
if session.empty?
|
||||
"no session variables were set"
|
||||
else
|
||||
"the session was #{session.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,85 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActionController # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures that the flash contains the given value. Can be a String, a
|
||||
# Regexp, or nil (indicating that the flash should not be set).
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# it { should set_the_flash }
|
||||
# it { should set_the_flash.to("Thank you for placing this order.") }
|
||||
# it { should set_the_flash.to(/created/i) }
|
||||
# it { should_not set_the_flash }
|
||||
def set_the_flash
|
||||
SetTheFlashMatcher.new
|
||||
end
|
||||
|
||||
class SetTheFlashMatcher # :nodoc:
|
||||
|
||||
def to(value)
|
||||
@value = value
|
||||
self
|
||||
end
|
||||
|
||||
def matches?(controller)
|
||||
@controller = controller
|
||||
sets_the_flash? && string_value_matches? && regexp_value_matches?
|
||||
end
|
||||
|
||||
attr_reader :failure_message, :negative_failure_message
|
||||
|
||||
def description
|
||||
description = "set the flash"
|
||||
description << " to #{@value.inspect}" unless @value.nil?
|
||||
description
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Expected #{expectation}"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"Did not expect #{expectation}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sets_the_flash?
|
||||
!flash.blank?
|
||||
end
|
||||
|
||||
def string_value_matches?
|
||||
return true unless String === @value
|
||||
flash.values.any? {|value| value == @value }
|
||||
end
|
||||
|
||||
def regexp_value_matches?
|
||||
return true unless Regexp === @value
|
||||
flash.values.any? {|value| value =~ @value }
|
||||
end
|
||||
|
||||
def flash
|
||||
@controller.response.session['flash']
|
||||
end
|
||||
|
||||
def expectation
|
||||
expectation = "the flash to be set"
|
||||
expectation << " to #{@value.inspect}" unless @value.nil?
|
||||
expectation << ", but #{flash_description}"
|
||||
expectation
|
||||
end
|
||||
|
||||
def flash_description
|
||||
if flash.blank?
|
||||
"no flash was set"
|
||||
else
|
||||
"was #{flash.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
233
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/resource_options.rb
vendored
Normal file
233
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_controller/resource_options.rb
vendored
Normal file
@@ -0,0 +1,233 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActionController
|
||||
# Formats tested by #should_be_restful. Defaults to [:html, :xml]
|
||||
VALID_FORMATS = Dir.glob(File.join(File.dirname(__FILE__), 'formats', '*.rb')).map { |f| File.basename(f, '.rb') }.map(&:to_sym) # :doc:
|
||||
VALID_FORMATS.each {|f| require "shoulda/action_controller/formats/#{f}"}
|
||||
|
||||
# Actions tested by #should_be_restful
|
||||
VALID_ACTIONS = [:index, :show, :new, :edit, :create, :update, :destroy] # :doc:
|
||||
|
||||
# A ResourceOptions object is passed into should_be_restful in order to configure the tests for your controller.
|
||||
#
|
||||
# Example:
|
||||
# class UsersControllerTest < Test::Unit::TestCase
|
||||
# fixtures :all
|
||||
#
|
||||
# def setup
|
||||
# ...normal setup code...
|
||||
# @user = User.find(:first)
|
||||
# end
|
||||
#
|
||||
# should_be_restful do |resource|
|
||||
# resource.identifier = :id
|
||||
# resource.klass = User
|
||||
# resource.object = :user
|
||||
# resource.parent = []
|
||||
# resource.actions = [:index, :show, :new, :edit, :update, :create, :destroy]
|
||||
# resource.formats = [:html, :xml]
|
||||
#
|
||||
# resource.create.params = { :name => "bob", :email => 'bob@bob.com', :age => 13}
|
||||
# resource.update.params = { :name => "sue" }
|
||||
#
|
||||
# resource.create.redirect = "user_url(@user)"
|
||||
# resource.update.redirect = "user_url(@user)"
|
||||
# resource.destroy.redirect = "users_url"
|
||||
#
|
||||
# resource.create.flash = /created/i
|
||||
# resource.update.flash = /updated/i
|
||||
# resource.destroy.flash = /removed/i
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# Whenever possible, the resource attributes will be set to sensible defaults.
|
||||
#
|
||||
class ResourceOptions
|
||||
# Configuration options for the create, update, destroy actions under should_be_restful
|
||||
class ActionOptions
|
||||
# String evaled to get the target of the redirection.
|
||||
# All of the instance variables set by the controller will be available to the
|
||||
# evaled code.
|
||||
#
|
||||
# Example:
|
||||
# resource.create.redirect = "user_url(@user.company, @user)"
|
||||
#
|
||||
# Defaults to a generated url based on the name of the controller, the action, and the resource.parents list.
|
||||
attr_accessor :redirect
|
||||
|
||||
# String or Regexp describing a value expected in the flash. Will match against any flash key.
|
||||
#
|
||||
# Defaults:
|
||||
# destroy:: /removed/
|
||||
# create:: /created/
|
||||
# update:: /updated/
|
||||
attr_accessor :flash
|
||||
|
||||
# Hash describing the params that should be sent in with this action.
|
||||
attr_accessor :params
|
||||
end
|
||||
|
||||
# Configuration options for the denied actions under should_be_restful
|
||||
#
|
||||
# Example:
|
||||
# context "The public" do
|
||||
# setup do
|
||||
# @request.session[:logged_in] = false
|
||||
# end
|
||||
#
|
||||
# should_be_restful do |resource|
|
||||
# resource.parent = :user
|
||||
#
|
||||
# resource.denied.actions = [:index, :show, :edit, :new, :create, :update, :destroy]
|
||||
# resource.denied.flash = /get outta here/i
|
||||
# resource.denied.redirect = 'new_session_url'
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class DeniedOptions
|
||||
# String evaled to get the target of the redirection.
|
||||
# All of the instance variables set by the controller will be available to the
|
||||
# evaled code.
|
||||
#
|
||||
# Example:
|
||||
# resource.create.redirect = "user_url(@user.company, @user)"
|
||||
attr_accessor :redirect
|
||||
|
||||
# String or Regexp describing a value expected in the flash. Will match against any flash key.
|
||||
#
|
||||
# Example:
|
||||
# resource.create.flash = /created/
|
||||
attr_accessor :flash
|
||||
|
||||
# Actions that should be denied (only used by resource.denied). <i>Note that these actions will
|
||||
# only be tested if they are also listed in +resource.actions+</i>
|
||||
# The special value of :all will deny all of the REST actions.
|
||||
attr_accessor :actions
|
||||
end
|
||||
|
||||
# Name of key in params that references the primary key.
|
||||
# Will almost always be :id (default), unless you are using a plugin or have patched rails.
|
||||
attr_accessor :identifier
|
||||
|
||||
# Name of the ActiveRecord class this resource is responsible for. Automatically determined from
|
||||
# test class if not explicitly set. UserTest => "User"
|
||||
attr_accessor :klass
|
||||
|
||||
# Name of the instantiated ActiveRecord object that should be used by some of the tests.
|
||||
# Defaults to the underscored name of the AR class. CompanyManager => :company_manager
|
||||
attr_accessor :object
|
||||
|
||||
# Name of the parent AR objects. Can be set as parent= or parents=, and can take either
|
||||
# the name of the parent resource (if there's only one), or an array of names (if there's
|
||||
# more than one).
|
||||
#
|
||||
# Example:
|
||||
# # in the routes...
|
||||
# map.resources :companies do
|
||||
# map.resources :people do
|
||||
# map.resources :limbs
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # in the tests...
|
||||
# class PeopleControllerTest < Test::Unit::TestCase
|
||||
# should_be_restful do |resource|
|
||||
# resource.parent = :companies
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# class LimbsControllerTest < Test::Unit::TestCase
|
||||
# should_be_restful do |resource|
|
||||
# resource.parents = [:companies, :people]
|
||||
# end
|
||||
# end
|
||||
attr_accessor :parent
|
||||
alias parents parent
|
||||
alias parents= parent=
|
||||
|
||||
# Actions that should be tested. Must be a subset of VALID_ACTIONS (default).
|
||||
# Tests for each actionw will only be generated if the action is listed here.
|
||||
# The special value of :all will test all of the REST actions.
|
||||
#
|
||||
# Example (for a read-only controller):
|
||||
# resource.actions = [:show, :index]
|
||||
attr_accessor :actions
|
||||
|
||||
# Formats that should be tested. Must be a subset of VALID_FORMATS (default).
|
||||
# Each action will be tested against the formats listed here. The special value
|
||||
# of :all will test all of the supported formats.
|
||||
#
|
||||
# Example:
|
||||
# resource.actions = [:html, :xml]
|
||||
attr_accessor :formats
|
||||
|
||||
# ActionOptions object specifying options for the create action.
|
||||
attr_accessor :create
|
||||
|
||||
# ActionOptions object specifying options for the update action.
|
||||
attr_accessor :update
|
||||
|
||||
# ActionOptions object specifying options for the desrtoy action.
|
||||
attr_accessor :destroy
|
||||
|
||||
# DeniedOptions object specifying which actions should return deny a request, and what should happen in that case.
|
||||
attr_accessor :denied
|
||||
|
||||
def initialize # :nodoc:
|
||||
@create = ActionOptions.new
|
||||
@update = ActionOptions.new
|
||||
@destroy = ActionOptions.new
|
||||
@denied = DeniedOptions.new
|
||||
|
||||
@create.flash ||= /created/i
|
||||
@update.flash ||= /updated/i
|
||||
@destroy.flash ||= /removed/i
|
||||
@denied.flash ||= /denied/i
|
||||
|
||||
@create.params ||= {}
|
||||
@update.params ||= {}
|
||||
|
||||
@actions = VALID_ACTIONS
|
||||
@formats = VALID_FORMATS
|
||||
@denied.actions = []
|
||||
end
|
||||
|
||||
def normalize!(target) # :nodoc:
|
||||
@denied.actions = VALID_ACTIONS if @denied.actions == :all
|
||||
@actions = VALID_ACTIONS if @actions == :all
|
||||
@formats = VALID_FORMATS if @formats == :all
|
||||
|
||||
@denied.actions = @denied.actions.map(&:to_sym)
|
||||
@actions = @actions.map(&:to_sym)
|
||||
@formats = @formats.map(&:to_sym)
|
||||
|
||||
ensure_valid_members(@actions, VALID_ACTIONS, 'actions')
|
||||
ensure_valid_members(@denied.actions, VALID_ACTIONS, 'denied.actions')
|
||||
ensure_valid_members(@formats, VALID_FORMATS, 'formats')
|
||||
|
||||
@identifier ||= :id
|
||||
@klass ||= target.name.gsub(/ControllerTest$/, '').singularize.constantize
|
||||
@object ||= @klass.name.tableize.singularize
|
||||
@parent ||= []
|
||||
@parent = [@parent] unless @parent.is_a? Array
|
||||
|
||||
collection_helper = [@parent, @object.to_s.pluralize, 'url'].flatten.join('_')
|
||||
collection_args = @parent.map {|n| "@#{object}.#{n}"}.join(', ')
|
||||
@destroy.redirect ||= "#{collection_helper}(#{collection_args})"
|
||||
|
||||
member_helper = [@parent, @object, 'url'].flatten.join('_')
|
||||
member_args = [@parent.map {|n| "@#{object}.#{n}"}, "@#{object}"].flatten.join(', ')
|
||||
@create.redirect ||= "#{member_helper}(#{member_args})"
|
||||
@update.redirect ||= "#{member_helper}(#{member_args})"
|
||||
@denied.redirect ||= "new_session_url"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensure_valid_members(ary, valid_members, name) # :nodoc:
|
||||
invalid = ary - valid_members
|
||||
raise ArgumentError, "Unsupported #{name}: #{invalid.inspect}" unless invalid.empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
10
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_mailer.rb
vendored
Normal file
10
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_mailer.rb
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
require 'shoulda'
|
||||
require 'shoulda/action_mailer/assertions'
|
||||
|
||||
module Test # :nodoc: all
|
||||
module Unit
|
||||
class TestCase
|
||||
include Shoulda::ActionMailer::Assertions
|
||||
end
|
||||
end
|
||||
end
|
||||
38
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_mailer/assertions.rb
vendored
Normal file
38
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_mailer/assertions.rb
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActionMailer # :nodoc:
|
||||
module Assertions
|
||||
# Asserts that an email was delivered. Can take a block that can further
|
||||
# narrow down the types of emails you're expecting.
|
||||
#
|
||||
# assert_sent_email
|
||||
#
|
||||
# Passes if ActionMailer::Base.deliveries has an email
|
||||
#
|
||||
# assert_sent_email do |email|
|
||||
# email.subject =~ /hi there/ && email.to.include?('none@none.com')
|
||||
# end
|
||||
#
|
||||
# Passes if there is an email with subject containing 'hi there' and
|
||||
# 'none@none.com' as one of the recipients.
|
||||
#
|
||||
def assert_sent_email
|
||||
emails = ::ActionMailer::Base.deliveries
|
||||
assert !emails.empty?, "No emails were sent"
|
||||
if block_given?
|
||||
matching_emails = emails.select {|email| yield email }
|
||||
assert !matching_emails.empty?, "None of the emails matched."
|
||||
end
|
||||
end
|
||||
|
||||
# Asserts that no ActionMailer mails were delivered
|
||||
#
|
||||
# assert_did_not_send_email
|
||||
def assert_did_not_send_email
|
||||
msg = "Sent #{::ActionMailer::Base.deliveries.size} emails.\n"
|
||||
::ActionMailer::Base.deliveries.each { |m| msg << " '#{m.subject}' sent to #{m.to.to_sentence}\n" }
|
||||
assert ::ActionMailer::Base.deliveries.empty?, msg
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
10
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_view.rb
vendored
Normal file
10
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_view.rb
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
require 'shoulda'
|
||||
require 'shoulda/action_view/macros'
|
||||
|
||||
module Test # :nodoc: all
|
||||
module Unit
|
||||
class TestCase
|
||||
extend Shoulda::ActionView::Macros
|
||||
end
|
||||
end
|
||||
end
|
||||
56
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_view/macros.rb
vendored
Normal file
56
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/action_view/macros.rb
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActionView # :nodoc:
|
||||
# = Macro test helpers for your view
|
||||
#
|
||||
# By using the macro helpers you can quickly and easily create concise and
|
||||
# easy to read test suites.
|
||||
#
|
||||
# This code segment:
|
||||
# context "on GET to :new" do
|
||||
# setup do
|
||||
# get :new
|
||||
# end
|
||||
#
|
||||
# should_render_a_form
|
||||
# should_render_page_with_metadata :title => /index/
|
||||
#
|
||||
# should "do something else really cool" do
|
||||
# assert_select '#really_cool'
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# Would produce 3 tests for the +show+ action
|
||||
module Macros
|
||||
|
||||
# Macro that creates a test asserting that the rendered view contains a <form> element.
|
||||
def should_render_a_form
|
||||
should "display a form" do
|
||||
assert_select "form", true, "The template doesn't contain a <form> element"
|
||||
end
|
||||
end
|
||||
|
||||
# Macro that creates a test asserting that the rendered view contains the selected metatags.
|
||||
# Values can be string or Regexps.
|
||||
# Example:
|
||||
#
|
||||
# should_render_page_with_metadata :description => "Description of this page", :keywords => /post/
|
||||
#
|
||||
# You can also use this method to test the rendered views title.
|
||||
#
|
||||
# Example:
|
||||
# should_render_page_with_metadata :title => /index/
|
||||
def should_render_page_with_metadata(options)
|
||||
options.each do |key, value|
|
||||
should "have metatag #{key}" do
|
||||
if key.to_sym == :title
|
||||
assert_select "title", value
|
||||
else
|
||||
assert_select "meta[name=?][content#{"*" if value.is_a?(Regexp)}=?]", key, value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
16
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record.rb
vendored
Normal file
16
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record.rb
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
require 'shoulda'
|
||||
require 'shoulda/active_record/helpers'
|
||||
require 'shoulda/active_record/matchers'
|
||||
require 'shoulda/active_record/assertions'
|
||||
require 'shoulda/active_record/macros'
|
||||
|
||||
module Test # :nodoc: all
|
||||
module Unit
|
||||
class TestCase
|
||||
include Shoulda::ActiveRecord::Helpers
|
||||
include Shoulda::ActiveRecord::Matchers
|
||||
include Shoulda::ActiveRecord::Assertions
|
||||
extend Shoulda::ActiveRecord::Macros
|
||||
end
|
||||
end
|
||||
end
|
||||
69
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/assertions.rb
vendored
Normal file
69
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/assertions.rb
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Assertions
|
||||
# Asserts that the given object can be saved
|
||||
#
|
||||
# assert_save User.new(params)
|
||||
def assert_save(obj)
|
||||
assert obj.save, "Errors: #{pretty_error_messages obj}"
|
||||
obj.reload
|
||||
end
|
||||
|
||||
# Asserts that the given object is valid
|
||||
#
|
||||
# assert_valid User.new(params)
|
||||
def assert_valid(obj)
|
||||
assert obj.valid?, "Errors: #{pretty_error_messages obj}"
|
||||
end
|
||||
|
||||
# Asserts that an Active Record model validates with the passed
|
||||
# <tt>value</tt> by making sure the <tt>error_message_to_avoid</tt> is not
|
||||
# contained within the list of errors for that attribute.
|
||||
#
|
||||
# assert_good_value(User.new, :email, "user@example.com")
|
||||
# assert_good_value(User.new, :ssn, "123456789", /length/)
|
||||
#
|
||||
# If a class is passed as the first argument, a new object will be
|
||||
# instantiated before the assertion. If an instance variable exists with
|
||||
# the same name as the class (underscored), that object will be used
|
||||
# instead.
|
||||
#
|
||||
# assert_good_value(User, :email, "user@example.com")
|
||||
#
|
||||
# @product = Product.new(:tangible => false)
|
||||
# assert_good_value(Product, :price, "0")
|
||||
def assert_good_value(object_or_klass, attribute, value, error_message_to_avoid = nil)
|
||||
object = get_instance_of(object_or_klass)
|
||||
matcher = allow_value(value).
|
||||
for(attribute).
|
||||
with_message(error_message_to_avoid)
|
||||
assert_accepts(matcher, object)
|
||||
end
|
||||
|
||||
# Asserts that an Active Record model invalidates the passed
|
||||
# <tt>value</tt> by making sure the <tt>error_message_to_expect</tt> is
|
||||
# contained within the list of errors for that attribute.
|
||||
#
|
||||
# assert_bad_value(User.new, :email, "invalid")
|
||||
# assert_bad_value(User.new, :ssn, "123", /length/)
|
||||
#
|
||||
# If a class is passed as the first argument, a new object will be
|
||||
# instantiated before the assertion. If an instance variable exists with
|
||||
# the same name as the class (underscored), that object will be used
|
||||
# instead.
|
||||
#
|
||||
# assert_bad_value(User, :email, "invalid")
|
||||
#
|
||||
# @product = Product.new(:tangible => true)
|
||||
# assert_bad_value(Product, :price, "0")
|
||||
def assert_bad_value(object_or_klass, attribute, value,
|
||||
error_message_to_expect = nil)
|
||||
object = get_instance_of(object_or_klass)
|
||||
matcher = allow_value(value).
|
||||
for(attribute).
|
||||
with_message(error_message_to_expect)
|
||||
assert_rejects(matcher, object)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
40
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/helpers.rb
vendored
Normal file
40
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/helpers.rb
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Helpers
|
||||
def pretty_error_messages(obj) # :nodoc:
|
||||
obj.errors.map do |a, m|
|
||||
msg = "#{a} #{m}"
|
||||
msg << " (#{obj.send(a).inspect})" unless a.to_sym == :base
|
||||
end
|
||||
end
|
||||
|
||||
def get_instance_of(object_or_klass)
|
||||
if object_or_klass.is_a?(Class)
|
||||
klass = object_or_klass
|
||||
instance_variable_get("@#{instance_variable_name_for(klass)}") || klass.new
|
||||
else
|
||||
object_or_klass
|
||||
end
|
||||
end
|
||||
|
||||
def instance_variable_name_for(klass)
|
||||
klass.to_s.split('::').last.underscore
|
||||
end
|
||||
|
||||
# Helper method that determines the default error message used by Active
|
||||
# Record. Works for both existing Rails 2.1 and Rails 2.2 with the newly
|
||||
# introduced I18n module used for localization.
|
||||
#
|
||||
# default_error_message(:blank)
|
||||
# default_error_message(:too_short, :count => 5)
|
||||
# default_error_message(:too_long, :count => 60)
|
||||
def default_error_message(key, values = {})
|
||||
if Object.const_defined?(:I18n) # Rails >= 2.2
|
||||
I18n.translate("activerecord.errors.messages.#{key}", values)
|
||||
else # Rails <= 2.1.x
|
||||
::ActiveRecord::Errors.default_error_messages[key] % values[:count]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
589
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/macros.rb
vendored
Normal file
589
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/macros.rb
vendored
Normal file
@@ -0,0 +1,589 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
# = Macro test helpers for your active record models
|
||||
#
|
||||
# These helpers will test most of the validations and associations for your ActiveRecord models.
|
||||
#
|
||||
# class UserTest < Test::Unit::TestCase
|
||||
# should_validate_presence_of :name, :phone_number
|
||||
# should_not_allow_values_for :phone_number, "abcd", "1234"
|
||||
# should_allow_values_for :phone_number, "(123) 456-7890"
|
||||
#
|
||||
# should_not_allow_mass_assignment_of :password
|
||||
#
|
||||
# should_have_one :profile
|
||||
# should_have_many :dogs
|
||||
# should_have_many :messes, :through => :dogs
|
||||
# should_belong_to :lover
|
||||
# end
|
||||
#
|
||||
# For all of these helpers, the last parameter may be a hash of options.
|
||||
#
|
||||
module Macros
|
||||
include Helpers
|
||||
include Matchers
|
||||
|
||||
# Ensures that the model cannot be saved if one of the attributes listed is not present.
|
||||
#
|
||||
# If an instance variable has been created in the setup named after the
|
||||
# model being tested, then this method will use that. Otherwise, it will
|
||||
# create a new instance to test against.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
||||
# Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.blank')</tt>
|
||||
#
|
||||
# Example:
|
||||
# should_validate_presence_of :name, :phone_number
|
||||
#
|
||||
def should_validate_presence_of(*attributes)
|
||||
message = get_options!(attributes, :message)
|
||||
klass = model_class
|
||||
|
||||
attributes.each do |attribute|
|
||||
matcher = validate_presence_of(attribute).with_message(message)
|
||||
should matcher.description do
|
||||
assert_accepts(matcher, get_instance_of(klass))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Deprecated. See should_validate_presence_of
|
||||
def should_require_attributes(*attributes)
|
||||
warn "[DEPRECATION] should_require_attributes is deprecated. " <<
|
||||
"Use should_validate_presence_of instead."
|
||||
should_validate_presence_of(*attributes)
|
||||
end
|
||||
|
||||
# Ensures that the model cannot be saved if one of the attributes listed is not unique.
|
||||
# Requires an existing record
|
||||
#
|
||||
# Options:
|
||||
|
||||
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
||||
# Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.taken')</tt>
|
||||
# * <tt>:scoped_to</tt> - field(s) to scope the uniqueness to.
|
||||
# * <tt>:case_sensitive</tt> - whether or not uniqueness is defined by an
|
||||
# exact match. Ignored by non-text attributes. Default = <tt>true</tt>
|
||||
#
|
||||
# Examples:
|
||||
# should_validate_uniqueness_of :keyword, :username
|
||||
# should_validate_uniqueness_of :name, :message => "O NOES! SOMEONE STOELED YER NAME!"
|
||||
# should_validate_uniqueness_of :email, :scoped_to => :name
|
||||
# should_validate_uniqueness_of :address, :scoped_to => [:first_name, :last_name]
|
||||
# should_validate_uniqueness_of :email, :case_sensitive => false
|
||||
#
|
||||
def should_validate_uniqueness_of(*attributes)
|
||||
message, scope, case_sensitive = get_options!(attributes, :message, :scoped_to, :case_sensitive)
|
||||
scope = [*scope].compact
|
||||
case_sensitive = true if case_sensitive.nil?
|
||||
|
||||
klass = model_class
|
||||
|
||||
attributes.each do |attribute|
|
||||
matcher = validate_uniqueness_of(attribute).
|
||||
with_message(message).scoped_to(scope)
|
||||
matcher = matcher.case_insensitive unless case_sensitive
|
||||
should matcher.description do
|
||||
assert_accepts(matcher, get_instance_of(klass))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Deprecated. See should_validate_uniqueness_of
|
||||
def should_require_unique_attributes(*attributes)
|
||||
warn "[DEPRECATION] should_require_unique_attributes is deprecated. " <<
|
||||
"Use should_validate_uniqueness_of instead."
|
||||
should_validate_uniqueness_of(*attributes)
|
||||
end
|
||||
|
||||
# Ensures that the attribute can be set on mass update.
|
||||
#
|
||||
# should_allow_mass_assignment_of :first_name, :last_name
|
||||
#
|
||||
def should_allow_mass_assignment_of(*attributes)
|
||||
get_options!(attributes)
|
||||
klass = model_class
|
||||
|
||||
attributes.each do |attribute|
|
||||
matcher = allow_mass_assignment_of(attribute)
|
||||
should matcher.description do
|
||||
assert_accepts matcher, klass.new
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Ensures that the attribute cannot be set on mass update.
|
||||
#
|
||||
# should_not_allow_mass_assignment_of :password, :admin_flag
|
||||
#
|
||||
def should_not_allow_mass_assignment_of(*attributes)
|
||||
get_options!(attributes)
|
||||
klass = model_class
|
||||
|
||||
attributes.each do |attribute|
|
||||
matcher = allow_mass_assignment_of(attribute)
|
||||
should "not #{matcher.description}" do
|
||||
assert_rejects matcher, klass.new
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Deprecated. See should_not_allow_mass_assignment_of
|
||||
def should_protect_attributes(*attributes)
|
||||
warn "[DEPRECATION] should_protect_attributes is deprecated. " <<
|
||||
"Use should_not_allow_mass_assignment_of instead."
|
||||
should_not_allow_mass_assignment_of(*attributes)
|
||||
end
|
||||
|
||||
# Ensures that the attribute cannot be changed once the record has been created.
|
||||
#
|
||||
# should_have_readonly_attributes :password, :admin_flag
|
||||
#
|
||||
def should_have_readonly_attributes(*attributes)
|
||||
get_options!(attributes)
|
||||
klass = model_class
|
||||
|
||||
attributes.each do |attribute|
|
||||
matcher = have_readonly_attribute(attribute)
|
||||
should matcher.description do
|
||||
assert_accepts matcher, klass.new
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Ensures that the attribute cannot be set to the given values
|
||||
#
|
||||
# If an instance variable has been created in the setup named after the
|
||||
# model being tested, then this method will use that. Otherwise, it will
|
||||
# create a new instance to test against.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
||||
# Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.invalid')</tt>
|
||||
#
|
||||
# Example:
|
||||
# should_not_allow_values_for :isbn, "bad 1", "bad 2"
|
||||
#
|
||||
def should_not_allow_values_for(attribute, *bad_values)
|
||||
message = get_options!(bad_values, :message)
|
||||
klass = model_class
|
||||
bad_values.each do |value|
|
||||
matcher = allow_value(value).for(attribute).with_message(message)
|
||||
should "not #{matcher.description}" do
|
||||
assert_rejects matcher, get_instance_of(klass)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Ensures that the attribute can be set to the given values.
|
||||
#
|
||||
# If an instance variable has been created in the setup named after the
|
||||
# model being tested, then this method will use that. Otherwise, it will
|
||||
# create a new instance to test against.
|
||||
#
|
||||
# Example:
|
||||
# should_allow_values_for :isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0"
|
||||
#
|
||||
def should_allow_values_for(attribute, *good_values)
|
||||
get_options!(good_values)
|
||||
klass = model_class
|
||||
klass = model_class
|
||||
good_values.each do |value|
|
||||
matcher = allow_value(value).for(attribute)
|
||||
should matcher.description do
|
||||
assert_accepts matcher, get_instance_of(klass)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Ensures that the length of the attribute is in the given range
|
||||
#
|
||||
# If an instance variable has been created in the setup named after the
|
||||
# model being tested, then this method will use that. Otherwise, it will
|
||||
# create a new instance to test against.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>:short_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
||||
# Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.too_short') % range.first</tt>
|
||||
# * <tt>:long_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
||||
# Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.too_long') % range.last</tt>
|
||||
#
|
||||
# Example:
|
||||
# should_ensure_length_in_range :password, (6..20)
|
||||
#
|
||||
def should_ensure_length_in_range(attribute, range, opts = {})
|
||||
short_message, long_message = get_options!([opts],
|
||||
:short_message,
|
||||
:long_message)
|
||||
klass = model_class
|
||||
|
||||
matcher = ensure_length_of(attribute).
|
||||
is_at_least(range.first).
|
||||
with_short_message(short_message).
|
||||
is_at_most(range.last).
|
||||
with_long_message(long_message)
|
||||
|
||||
should matcher.description do
|
||||
assert_accepts matcher, get_instance_of(klass)
|
||||
end
|
||||
end
|
||||
|
||||
# Ensures that the length of the attribute is at least a certain length
|
||||
#
|
||||
# If an instance variable has been created in the setup named after the
|
||||
# model being tested, then this method will use that. Otherwise, it will
|
||||
# create a new instance to test against.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>:short_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
||||
# Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.too_short') % min_length</tt>
|
||||
#
|
||||
# Example:
|
||||
# should_ensure_length_at_least :name, 3
|
||||
#
|
||||
def should_ensure_length_at_least(attribute, min_length, opts = {})
|
||||
short_message = get_options!([opts], :short_message)
|
||||
klass = model_class
|
||||
|
||||
matcher = ensure_length_of(attribute).
|
||||
is_at_least(min_length).
|
||||
with_short_message(short_message)
|
||||
|
||||
should matcher.description do
|
||||
assert_accepts matcher, get_instance_of(klass)
|
||||
end
|
||||
end
|
||||
|
||||
# Ensures that the length of the attribute is exactly a certain length
|
||||
#
|
||||
# If an instance variable has been created in the setup named after the
|
||||
# model being tested, then this method will use that. Otherwise, it will
|
||||
# create a new instance to test against.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
||||
# Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.wrong_length') % length</tt>
|
||||
#
|
||||
# Example:
|
||||
# should_ensure_length_is :ssn, 9
|
||||
#
|
||||
def should_ensure_length_is(attribute, length, opts = {})
|
||||
message = get_options!([opts], :message)
|
||||
klass = model_class
|
||||
matcher = ensure_length_of(attribute).
|
||||
is_equal_to(length).
|
||||
with_message(message)
|
||||
|
||||
should matcher.description do
|
||||
assert_accepts matcher, get_instance_of(klass)
|
||||
end
|
||||
end
|
||||
|
||||
# Ensure that the attribute is in the range specified
|
||||
#
|
||||
# If an instance variable has been created in the setup named after the
|
||||
# model being tested, then this method will use that. Otherwise, it will
|
||||
# create a new instance to test against.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>:low_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
||||
# Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.inclusion')</tt>
|
||||
# * <tt>:high_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
||||
# Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.inclusion')</tt>
|
||||
#
|
||||
# Example:
|
||||
# should_ensure_value_in_range :age, (0..100)
|
||||
#
|
||||
def should_ensure_value_in_range(attribute, range, opts = {})
|
||||
message, low_message, high_message = get_options!([opts],
|
||||
:message,
|
||||
:low_message,
|
||||
:high_message)
|
||||
klass = model_class
|
||||
matcher = ensure_inclusion_of(attribute).
|
||||
in_range(range).
|
||||
with_message(message).
|
||||
with_low_message(low_message).
|
||||
with_high_message(high_message)
|
||||
should matcher.description do
|
||||
assert_accepts matcher, get_instance_of(klass)
|
||||
end
|
||||
end
|
||||
|
||||
# Ensure that the attribute is numeric
|
||||
#
|
||||
# If an instance variable has been created in the setup named after the
|
||||
# model being tested, then this method will use that. Otherwise, it will
|
||||
# create a new instance to test against.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
||||
# Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.not_a_number')</tt>
|
||||
#
|
||||
# Example:
|
||||
# should_validate_numericality_of :age
|
||||
#
|
||||
def should_validate_numericality_of(*attributes)
|
||||
message = get_options!(attributes, :message)
|
||||
klass = model_class
|
||||
attributes.each do |attribute|
|
||||
matcher = validate_numericality_of(attribute).
|
||||
with_message(message)
|
||||
should matcher.description do
|
||||
assert_accepts matcher, get_instance_of(klass)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Deprecated. See should_validate_numericality_of
|
||||
def should_only_allow_numeric_values_for(*attributes)
|
||||
warn "[DEPRECATION] should_only_allow_numeric_values_for is " <<
|
||||
"deprecated. Use should_validate_numericality_of instead."
|
||||
should_validate_numericality_of(*attributes)
|
||||
end
|
||||
|
||||
# Ensures that the has_many relationship exists. Will also test that the
|
||||
# associated table has the required columns. Works with polymorphic
|
||||
# associations.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>:through</tt> - association name for <tt>has_many :through</tt>
|
||||
# * <tt>:dependent</tt> - tests that the association makes use of the dependent option.
|
||||
#
|
||||
# Example:
|
||||
# should_have_many :friends
|
||||
# should_have_many :enemies, :through => :friends
|
||||
# should_have_many :enemies, :dependent => :destroy
|
||||
#
|
||||
def should_have_many(*associations)
|
||||
through, dependent = get_options!(associations, :through, :dependent)
|
||||
klass = model_class
|
||||
associations.each do |association|
|
||||
matcher = have_many(association).through(through).dependent(dependent)
|
||||
should matcher.description do
|
||||
assert_accepts(matcher, klass.new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Ensure that the has_one relationship exists. Will also test that the
|
||||
# associated table has the required columns. Works with polymorphic
|
||||
# associations.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>:dependent</tt> - tests that the association makes use of the dependent option.
|
||||
#
|
||||
# Example:
|
||||
# should_have_one :god # unless hindu
|
||||
#
|
||||
def should_have_one(*associations)
|
||||
dependent = get_options!(associations, :dependent)
|
||||
klass = model_class
|
||||
associations.each do |association|
|
||||
matcher = have_one(association).dependent(dependent)
|
||||
should matcher.description do
|
||||
assert_accepts(matcher, klass.new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Ensures that the has_and_belongs_to_many relationship exists, and that the join
|
||||
# table is in place.
|
||||
#
|
||||
# should_have_and_belong_to_many :posts, :cars
|
||||
#
|
||||
def should_have_and_belong_to_many(*associations)
|
||||
get_options!(associations)
|
||||
klass = model_class
|
||||
|
||||
associations.each do |association|
|
||||
matcher = have_and_belong_to_many(association)
|
||||
should matcher.description do
|
||||
assert_accepts(matcher, klass.new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Ensure that the belongs_to relationship exists.
|
||||
#
|
||||
# should_belong_to :parent
|
||||
#
|
||||
def should_belong_to(*associations)
|
||||
dependent = get_options!(associations, :dependent)
|
||||
klass = model_class
|
||||
associations.each do |association|
|
||||
matcher = belong_to(association).dependent(dependent)
|
||||
should matcher.description do
|
||||
assert_accepts(matcher, klass.new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Ensure that the given class methods are defined on the model.
|
||||
#
|
||||
# should_have_class_methods :find, :destroy
|
||||
#
|
||||
def should_have_class_methods(*methods)
|
||||
get_options!(methods)
|
||||
klass = model_class
|
||||
methods.each do |method|
|
||||
should "respond to class method ##{method}" do
|
||||
assert_respond_to klass, method, "#{klass.name} does not have class method #{method}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Ensure that the given instance methods are defined on the model.
|
||||
#
|
||||
# should_have_instance_methods :email, :name, :name=
|
||||
#
|
||||
def should_have_instance_methods(*methods)
|
||||
get_options!(methods)
|
||||
klass = model_class
|
||||
methods.each do |method|
|
||||
should "respond to instance method ##{method}" do
|
||||
assert_respond_to klass.new, method, "#{klass.name} does not have instance method #{method}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Ensure that the given columns are defined on the models backing SQL table.
|
||||
# Also aliased to should_have_index for readability.
|
||||
# Takes the same options available in migrations:
|
||||
# :type, :precision, :limit, :default, :null, and :scale
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# should_have_db_columns :id, :email, :name, :created_at
|
||||
#
|
||||
# should_have_db_column :email, :type => "string", :limit => 255
|
||||
# should_have_db_column :salary, :decimal, :precision => 15, :scale => 2
|
||||
# should_have_db_column :admin, :default => false, :null => false
|
||||
#
|
||||
def should_have_db_columns(*columns)
|
||||
column_type, precision, limit, default, null, scale, sql_type =
|
||||
get_options!(columns, :type, :precision, :limit,
|
||||
:default, :null, :scale, :sql_type)
|
||||
klass = model_class
|
||||
columns.each do |name|
|
||||
matcher = have_db_column(name).
|
||||
of_type(column_type).
|
||||
with_options(:precision => precision, :limit => limit,
|
||||
:default => default, :null => null,
|
||||
:scale => scale, :sql_type => sql_type)
|
||||
should matcher.description do
|
||||
assert_accepts(matcher, klass.new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
alias_method :should_have_db_column, :should_have_db_columns
|
||||
|
||||
# Ensures that there are DB indices on the given columns or tuples of columns.
|
||||
# Also aliased to should_have_index for readability
|
||||
#
|
||||
# Options:
|
||||
# * <tt>:unique</tt> - whether or not the index has a unique
|
||||
# constraint. Use <tt>true</tt> to explicitly test for a unique
|
||||
# constraint. Use <tt>false</tt> to explicitly test for a non-unique
|
||||
# constraint. Use <tt>nil</tt> if you don't care whether the index is
|
||||
# unique or not. Default = <tt>nil</tt>
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# should_have_indices :email, :name, [:commentable_type, :commentable_id]
|
||||
# should_have_index :age
|
||||
# should_have_index :ssn, :unique => true
|
||||
#
|
||||
def should_have_indices(*columns)
|
||||
unique = get_options!(columns, :unique)
|
||||
klass = model_class
|
||||
|
||||
columns.each do |column|
|
||||
matcher = have_index(column).unique(unique)
|
||||
should matcher.description do
|
||||
assert_accepts(matcher, klass.new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
alias_method :should_have_index, :should_have_indices
|
||||
|
||||
# Ensures that the model cannot be saved if one of the attributes listed is not accepted.
|
||||
#
|
||||
# If an instance variable has been created in the setup named after the
|
||||
# model being tested, then this method will use that. Otherwise, it will
|
||||
# create a new instance to test against.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
||||
# Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.accepted')</tt>
|
||||
#
|
||||
# Example:
|
||||
# should_validate_acceptance_of :eula
|
||||
#
|
||||
def should_validate_acceptance_of(*attributes)
|
||||
message = get_options!(attributes, :message)
|
||||
klass = model_class
|
||||
|
||||
attributes.each do |attribute|
|
||||
matcher = validate_acceptance_of(attribute).with_message(message)
|
||||
should matcher.description do
|
||||
assert_accepts matcher, get_instance_of(klass)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Deprecated. See should_validate_uniqueness_of
|
||||
def should_require_acceptance_of(*attributes)
|
||||
warn "[DEPRECATION] should_require_acceptance_of is deprecated. " <<
|
||||
"Use should_validate_acceptance_of instead."
|
||||
should_validate_acceptance_of(*attributes)
|
||||
end
|
||||
|
||||
# Ensures that the model has a method named scope_name that returns a NamedScope object with the
|
||||
# proxy options set to the options you supply. scope_name can be either a symbol, or a method
|
||||
# call which will be evaled against the model. The eval'd method call has access to all the same
|
||||
# instance variables that a should statement would.
|
||||
#
|
||||
# Options: Any of the options that the named scope would pass on to find.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# should_have_named_scope :visible, :conditions => {:visible => true}
|
||||
#
|
||||
# Passes for
|
||||
#
|
||||
# named_scope :visible, :conditions => {:visible => true}
|
||||
#
|
||||
# Or for
|
||||
#
|
||||
# def self.visible
|
||||
# scoped(:conditions => {:visible => true})
|
||||
# end
|
||||
#
|
||||
# You can test lambdas or methods that return ActiveRecord#scoped calls:
|
||||
#
|
||||
# should_have_named_scope 'recent(5)', :limit => 5
|
||||
# should_have_named_scope 'recent(1)', :limit => 1
|
||||
#
|
||||
# Passes for
|
||||
# named_scope :recent, lambda {|c| {:limit => c}}
|
||||
#
|
||||
# Or for
|
||||
#
|
||||
# def self.recent(c)
|
||||
# scoped(:limit => c)
|
||||
# end
|
||||
#
|
||||
def should_have_named_scope(scope_call, find_options = nil)
|
||||
klass = model_class
|
||||
matcher = have_named_scope(scope_call).finding(find_options)
|
||||
should matcher.description do
|
||||
assert_accepts matcher.in_context(self), klass.new
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
42
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers.rb
vendored
Normal file
42
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers.rb
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
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_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_index_matcher'
|
||||
require 'shoulda/active_record/matchers/have_readonly_attribute_matcher'
|
||||
require 'shoulda/active_record/matchers/allow_mass_assignment_of_matcher'
|
||||
require 'shoulda/active_record/matchers/have_named_scope_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
|
||||
@@ -0,0 +1,83 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures that the attribute can be set on mass update.
|
||||
#
|
||||
# it { should_not allow_mass_assignment_of(:password) }
|
||||
# it { should allow_mass_assignment_of(:first_name) }
|
||||
#
|
||||
def allow_mass_assignment_of(value)
|
||||
AllowMassAssignmentOfMatcher.new(value)
|
||||
end
|
||||
|
||||
class AllowMassAssignmentOfMatcher # :nodoc:
|
||||
|
||||
def initialize(attribute)
|
||||
@attribute = attribute.to_s
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
@subject = subject
|
||||
if attr_mass_assignable?
|
||||
if whitelisting?
|
||||
@failure_message = "#{@attribute} was made accessible"
|
||||
else
|
||||
if protected_attributes.empty?
|
||||
@failure_message = "no attributes were protected"
|
||||
else
|
||||
@failure_message = "#{class_name} is protecting " <<
|
||||
"#{protected_attributes.to_a.to_sentence}, " <<
|
||||
"but not #{@attribute}."
|
||||
end
|
||||
end
|
||||
true
|
||||
else
|
||||
if whitelisting?
|
||||
@negative_failure_message =
|
||||
"Expected #{@attribute} to be accessible"
|
||||
else
|
||||
@negative_failure_message =
|
||||
"Did not expect #{@attribute} to be protected"
|
||||
end
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :failure_message, :negative_failure_message
|
||||
|
||||
def description
|
||||
"protect #{@attribute} from mass updates"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def protected_attributes
|
||||
@protected_attributes ||= (@subject.class.protected_attributes || [])
|
||||
end
|
||||
|
||||
def accessible_attributes
|
||||
@accessible_attributes ||= (@subject.class.accessible_attributes || [])
|
||||
end
|
||||
|
||||
def whitelisting?
|
||||
!accessible_attributes.empty?
|
||||
end
|
||||
|
||||
def attr_mass_assignable?
|
||||
if whitelisting?
|
||||
accessible_attributes.include?(@attribute)
|
||||
else
|
||||
!protected_attributes.include?(@attribute)
|
||||
end
|
||||
end
|
||||
|
||||
def class_name
|
||||
@subject.class.name
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
102
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers/allow_value_matcher.rb
vendored
Normal file
102
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers/allow_value_matcher.rb
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures that the attribute can be set to the given value.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>with_message</tt> - value the test expects to find in
|
||||
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
|
||||
# translation for :invalid.
|
||||
#
|
||||
# Example:
|
||||
# it { should_not allow_value('bad').for(:isbn) }
|
||||
# it { should allow_value("isbn 1 2345 6789 0").for(:isbn) }
|
||||
#
|
||||
def allow_value(value)
|
||||
AllowValueMatcher.new(value)
|
||||
end
|
||||
|
||||
class AllowValueMatcher # :nodoc:
|
||||
include Helpers
|
||||
|
||||
def initialize(value)
|
||||
@value = value
|
||||
end
|
||||
|
||||
def for(attribute)
|
||||
@attribute = attribute
|
||||
self
|
||||
end
|
||||
|
||||
def with_message(message)
|
||||
@expected_message = message if message
|
||||
self
|
||||
end
|
||||
|
||||
def matches?(instance)
|
||||
@instance = instance
|
||||
@expected_message ||= :invalid
|
||||
if Symbol === @expected_message
|
||||
@expected_message = default_error_message(@expected_message)
|
||||
end
|
||||
@instance.send("#{@attribute}=", @value)
|
||||
!errors_match?
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Did not expect #{expectation}, got error: #{@matched_error}"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"Expected #{expectation}, got #{error_description}"
|
||||
end
|
||||
|
||||
def description
|
||||
"allow #{@attribute} to be set to #{@value.inspect}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def errors_match?
|
||||
@instance.valid?
|
||||
@errors = @instance.errors.on(@attribute)
|
||||
@errors = [@errors] unless @errors.is_a?(Array)
|
||||
errors_match_regexp? || errors_match_string?
|
||||
end
|
||||
|
||||
def errors_match_regexp?
|
||||
if Regexp === @expected_message
|
||||
@matched_error = @errors.detect { |e| e =~ @expected_message }
|
||||
!@matched_error.nil?
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def errors_match_string?
|
||||
if @errors.include?(@expected_message)
|
||||
@matched_error = @expected_message
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def expectation
|
||||
"errors to include #{@expected_message.inspect} " <<
|
||||
"when #{@attribute} is set to #{@value.inspect}"
|
||||
end
|
||||
|
||||
def error_description
|
||||
if @instance.errors.empty?
|
||||
"no errors"
|
||||
else
|
||||
"errors: #{pretty_error_messages(@instance)}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
226
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers/association_matcher.rb
vendored
Normal file
226
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers/association_matcher.rb
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensure that the belongs_to relationship exists.
|
||||
#
|
||||
# it { should belong_to(:parent) }
|
||||
#
|
||||
def belong_to(name)
|
||||
AssociationMatcher.new(:belongs_to, name)
|
||||
end
|
||||
|
||||
# Ensures that the has_many relationship exists. Will also test that the
|
||||
# associated table has the required columns. Works with polymorphic
|
||||
# associations.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>through</tt> - association name for <tt>has_many :through</tt>
|
||||
# * <tt>dependent</tt> - tests that the association makes use of the
|
||||
# dependent option.
|
||||
#
|
||||
# Example:
|
||||
# it { should_have_many(:friends) }
|
||||
# it { should_have_many(:enemies).through(:friends) }
|
||||
# it { should_have_many(:enemies).dependent(:destroy) }
|
||||
#
|
||||
def have_many(name)
|
||||
AssociationMatcher.new(:has_many, name)
|
||||
end
|
||||
|
||||
# Ensure that the has_one relationship exists. Will also test that the
|
||||
# associated table has the required columns. Works with polymorphic
|
||||
# associations.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>:dependent</tt> - tests that the association makes use of the
|
||||
# dependent option.
|
||||
#
|
||||
# Example:
|
||||
# it { should have_one(:god) } # unless hindu
|
||||
#
|
||||
def have_one(name)
|
||||
AssociationMatcher.new(:has_one, name)
|
||||
end
|
||||
|
||||
# Ensures that the has_and_belongs_to_many relationship exists, and that
|
||||
# the join table is in place.
|
||||
#
|
||||
# it { should have_and_belong_to_many(:posts) }
|
||||
#
|
||||
def have_and_belong_to_many(name)
|
||||
AssociationMatcher.new(:has_and_belongs_to_many, name)
|
||||
end
|
||||
|
||||
class AssociationMatcher # :nodoc:
|
||||
def initialize(macro, name)
|
||||
@macro = macro
|
||||
@name = name
|
||||
end
|
||||
|
||||
def through(through)
|
||||
@through = through
|
||||
self
|
||||
end
|
||||
|
||||
def dependent(dependent)
|
||||
@dependent = dependent
|
||||
self
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
@subject = subject
|
||||
association_exists? &&
|
||||
macro_correct? &&
|
||||
foreign_key_exists? &&
|
||||
through_association_valid? &&
|
||||
dependent_correct? &&
|
||||
join_table_exists?
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Expected #{expectation} (#{@missing})"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"Did not expect #{expectation}"
|
||||
end
|
||||
|
||||
def description
|
||||
description = "#{macro_description} #{@name}"
|
||||
description += " through #{@through}" if @through
|
||||
description += " dependent => #{@dependent}" if @dependent
|
||||
description
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def association_exists?
|
||||
if reflection.nil?
|
||||
@missing = "no association called #{@name}"
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def macro_correct?
|
||||
if reflection.macro == @macro
|
||||
true
|
||||
else
|
||||
@missing = "actual association type was #{reflection.macro}"
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def foreign_key_exists?
|
||||
!(belongs_foreign_key_missing? || has_foreign_key_missing?)
|
||||
end
|
||||
|
||||
def belongs_foreign_key_missing?
|
||||
@macro == :belongs_to && !class_has_foreign_key?(model_class)
|
||||
end
|
||||
|
||||
def has_foreign_key_missing?
|
||||
[:has_many, :has_one].include?(@macro) &&
|
||||
!through? &&
|
||||
!class_has_foreign_key?(associated_class)
|
||||
end
|
||||
|
||||
def through_association_valid?
|
||||
@through.nil? || (through_association_exists? && through_association_correct?)
|
||||
end
|
||||
|
||||
def through_association_exists?
|
||||
if through_reflection.nil?
|
||||
"#{model_class.name} does not have any relationship to #{@through}"
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def through_association_correct?
|
||||
if @through == reflection.options[:through]
|
||||
"Expected #{model_class.name} to have #{@name} through #{@through}, " <<
|
||||
" but got it through #{reflection.options[:through]}"
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def dependent_correct?
|
||||
if @dependent.nil? || @dependent.to_s == reflection.options[:dependent].to_s
|
||||
true
|
||||
else
|
||||
@missing = "#{@name} should have #{@dependent} dependency"
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def join_table_exists?
|
||||
if @macro != :has_and_belongs_to_many ||
|
||||
::ActiveRecord::Base.connection.tables.include?(join_table.to_s)
|
||||
true
|
||||
else
|
||||
@missing = "join table #{join_table} doesn't exist"
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def class_has_foreign_key?(klass)
|
||||
if klass.column_names.include?(foreign_key.to_s)
|
||||
true
|
||||
else
|
||||
@missing = "#{klass} does not have a #{foreign_key} foreign key."
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def model_class
|
||||
@subject.class
|
||||
end
|
||||
|
||||
def join_table
|
||||
reflection.options[:join_table]
|
||||
end
|
||||
|
||||
def associated_class
|
||||
reflection.klass
|
||||
end
|
||||
|
||||
def foreign_key
|
||||
reflection.primary_key_name
|
||||
end
|
||||
|
||||
def through?
|
||||
reflection.options[:through]
|
||||
end
|
||||
|
||||
def reflection
|
||||
@reflection ||= model_class.reflect_on_association(@name)
|
||||
end
|
||||
|
||||
def through_reflection
|
||||
@through_reflection ||= model_class.reflect_on_association(@through)
|
||||
end
|
||||
|
||||
def expectation
|
||||
"#{model_class.name} to have a #{@macro} association called #{@name}"
|
||||
end
|
||||
|
||||
def macro_description
|
||||
case @macro.to_s
|
||||
when 'belongs_to' then 'belong to'
|
||||
when 'has_many' then 'have many'
|
||||
when 'has_one' then 'have one'
|
||||
when 'has_and_belongs_to_many' then
|
||||
'have and belong to many'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,87 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensure that the attribute's value is in the range specified
|
||||
#
|
||||
# Options:
|
||||
# * <tt>in_range</tt> - the range of allowed values for this attribute
|
||||
# * <tt>with_low_message</tt> - value the test expects to find in
|
||||
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
|
||||
# translation for :inclusion.
|
||||
# * <tt>with_high_message</tt> - value the test expects to find in
|
||||
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
|
||||
# translation for :inclusion.
|
||||
#
|
||||
# Example:
|
||||
# it { should ensure_inclusion_of(:age).in_range(0..100) }
|
||||
#
|
||||
def ensure_inclusion_of(attr)
|
||||
EnsureInclusionOfMatcher.new(attr)
|
||||
end
|
||||
|
||||
class EnsureInclusionOfMatcher < ValidationMatcher # :nodoc:
|
||||
|
||||
def in_range(range)
|
||||
@range = range
|
||||
@minimum = range.first
|
||||
@maximum = range.last
|
||||
self
|
||||
end
|
||||
|
||||
def with_message(message)
|
||||
if message
|
||||
@low_message = message
|
||||
@high_message = message
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def with_low_message(message)
|
||||
@low_message = message if message
|
||||
self
|
||||
end
|
||||
|
||||
def with_high_message(message)
|
||||
@high_message = message if message
|
||||
self
|
||||
end
|
||||
|
||||
def description
|
||||
"ensure inclusion of #{@attribute} in #{@range.inspect}"
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
super(subject)
|
||||
|
||||
@low_message ||= :inclusion
|
||||
@high_message ||= :inclusion
|
||||
|
||||
disallows_lower_value &&
|
||||
allows_minimum_value &&
|
||||
disallows_higher_value &&
|
||||
allows_maximum_value
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def disallows_lower_value
|
||||
@minimum == 0 || disallows_value_of(@minimum - 1, @low_message)
|
||||
end
|
||||
|
||||
def disallows_higher_value
|
||||
disallows_value_of(@maximum + 1, @high_message)
|
||||
end
|
||||
|
||||
def allows_minimum_value
|
||||
allows_value_of(@minimum, @low_message)
|
||||
end
|
||||
|
||||
def allows_maximum_value
|
||||
allows_value_of(@maximum, @high_message)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
141
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb
vendored
Normal file
141
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures that the length of the attribute is validated.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>is_at_least</tt> - minimum length of this attribute
|
||||
# * <tt>is_at_most</tt> - maximum length of this attribute
|
||||
# * <tt>is_equal_to</tt> - exact requred length of this attribute
|
||||
# * <tt>with_short_message</tt> - value the test expects to find in
|
||||
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
|
||||
# translation for :too_short.
|
||||
# * <tt>with_long_message</tt> - value the test expects to find in
|
||||
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
|
||||
# translation for :too_long.
|
||||
# * <tt>with_message</tt> - value the test expects to find in
|
||||
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
|
||||
# translation for :wrong_length. Used in conjunction with
|
||||
# <tt>is_equal_to</tt>.
|
||||
#
|
||||
# Examples:
|
||||
# it { should ensure_length_of(:password).
|
||||
# is_at_least(6).
|
||||
# is_at_most(20) }
|
||||
# it { should ensure_length_of(:name).
|
||||
# is_at_least(3).
|
||||
# with_short_message(/not long enough/) }
|
||||
# it { should ensure_length_of(:ssn).
|
||||
# is_equal_to(9).
|
||||
# with_message(/is invalid/) }
|
||||
def ensure_length_of(attr)
|
||||
EnsureLengthOfMatcher.new(attr)
|
||||
end
|
||||
|
||||
class EnsureLengthOfMatcher < ValidationMatcher # :nodoc:
|
||||
include Helpers
|
||||
|
||||
def is_at_least(length)
|
||||
@minimum = length
|
||||
@short_message ||= :too_short
|
||||
self
|
||||
end
|
||||
|
||||
def is_at_most(length)
|
||||
@maximum = length
|
||||
@long_message ||= :too_long
|
||||
self
|
||||
end
|
||||
|
||||
def is_equal_to(length)
|
||||
@minimum = length
|
||||
@maximum = length
|
||||
@short_message ||= :wrong_length
|
||||
self
|
||||
end
|
||||
|
||||
def with_short_message(message)
|
||||
@short_message = message if message
|
||||
self
|
||||
end
|
||||
alias_method :with_message, :with_short_message
|
||||
|
||||
def with_long_message(message)
|
||||
@long_message = message if message
|
||||
self
|
||||
end
|
||||
|
||||
def description
|
||||
description = "ensure #{@attribute} has a length "
|
||||
if @minimum && @maximum
|
||||
if @minimum == @maximum
|
||||
description << "of exactly #{@minimum}"
|
||||
else
|
||||
description << "between #{@minimum} and #{@maximum}"
|
||||
end
|
||||
else
|
||||
description << "of at least #{@minimum}" if @minimum
|
||||
description << "of at most #{@maximum}" if @maximum
|
||||
end
|
||||
description
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
super(subject)
|
||||
translate_messages!
|
||||
disallows_lower_length &&
|
||||
allows_minimum_length &&
|
||||
((@minimum == @maximum) ||
|
||||
(disallows_higher_length &&
|
||||
allows_maximum_length))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def translate_messages!
|
||||
if Symbol === @short_message
|
||||
@short_message = default_error_message(@short_message,
|
||||
:count => @minimum)
|
||||
end
|
||||
|
||||
if Symbol === @long_message
|
||||
@long_message = default_error_message(@long_message,
|
||||
:count => @maximum)
|
||||
end
|
||||
end
|
||||
|
||||
def disallows_lower_length
|
||||
@minimum == 0 ||
|
||||
@minimum.nil? ||
|
||||
disallows_length_of(@minimum - 1, @short_message)
|
||||
end
|
||||
|
||||
def disallows_higher_length
|
||||
@maximum.nil? || disallows_length_of(@maximum + 1, @long_message)
|
||||
end
|
||||
|
||||
def allows_minimum_length
|
||||
allows_length_of(@minimum, @short_message)
|
||||
end
|
||||
|
||||
def allows_maximum_length
|
||||
allows_length_of(@maximum, @long_message)
|
||||
end
|
||||
|
||||
def allows_length_of(length, message)
|
||||
length.nil? || allows_value_of(string_of_length(length), message)
|
||||
end
|
||||
|
||||
def disallows_length_of(length, message)
|
||||
length.nil? || disallows_value_of(string_of_length(length), message)
|
||||
end
|
||||
|
||||
def string_of_length(length)
|
||||
'x' * length
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
169
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers/have_db_column_matcher.rb
vendored
Normal file
169
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers/have_db_column_matcher.rb
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures the database column exists.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>of_type</tt> - db column type (:integer, :string, etc.)
|
||||
# * <tt>with_options</tt> - same options available in migrations
|
||||
# (:default, :null, :limit, :precision, :scale)
|
||||
#
|
||||
# Examples:
|
||||
# it { should_not have_db_column(:admin).of_type(:boolean) }
|
||||
# it { should have_db_column(:salary).
|
||||
# of_type(:decimal).
|
||||
# with_options(:precision => 10, :scale => 2) }
|
||||
#
|
||||
def have_db_column(column)
|
||||
HaveDbColumnMatcher.new(:have_db_column, column)
|
||||
end
|
||||
|
||||
class HaveDbColumnMatcher # :nodoc:
|
||||
def initialize(macro, column)
|
||||
@macro = macro
|
||||
@column = column
|
||||
end
|
||||
|
||||
def of_type(column_type)
|
||||
@column_type = column_type
|
||||
self
|
||||
end
|
||||
|
||||
def with_options(opts = {})
|
||||
@precision = opts[:precision]
|
||||
@limit = opts[:limit]
|
||||
@default = opts[:default]
|
||||
@null = opts[:null]
|
||||
@scale = opts[:scale]
|
||||
self
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
@subject = subject
|
||||
column_exists? &&
|
||||
correct_column_type? &&
|
||||
correct_precision? &&
|
||||
correct_limit? &&
|
||||
correct_default? &&
|
||||
correct_null? &&
|
||||
correct_scale?
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Expected #{expectation} (#{@missing})"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"Did not expect #{expectation}"
|
||||
end
|
||||
|
||||
def description
|
||||
desc = "have db column named #{@column}"
|
||||
desc << " of type #{@column_type}" unless @column_type.nil?
|
||||
desc << " of precision #{@precision}" unless @precision.nil?
|
||||
desc << " of limit #{@limit}" unless @limit.nil?
|
||||
desc << " of default #{@default}" unless @default.nil?
|
||||
desc << " of null #{@null}" unless @null.nil?
|
||||
desc << " of primary #{@primary}" unless @primary.nil?
|
||||
desc << " of scale #{@scale}" unless @scale.nil?
|
||||
desc
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def column_exists?
|
||||
if model_class.column_names.include?(@column.to_s)
|
||||
true
|
||||
else
|
||||
@missing = "#{model_class} does not have a db column named #{@column}."
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def correct_column_type?
|
||||
return true if @column_type.nil?
|
||||
if matched_column.type.to_s == @column_type.to_s
|
||||
true
|
||||
else
|
||||
@missing = "#{model_class} has a db column named #{@column} " <<
|
||||
"of type #{matched_column.type}, not #{@column_type}."
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def correct_precision?
|
||||
return true if @precision.nil?
|
||||
if matched_column.precision.to_s == @precision.to_s
|
||||
true
|
||||
else
|
||||
@missing = "#{model_class} has a db column named #{@column} " <<
|
||||
"of precision #{matched_column.precision}, " <<
|
||||
"not #{@precision}."
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def correct_limit?
|
||||
return true if @limit.nil?
|
||||
if matched_column.limit.to_s == @limit.to_s
|
||||
true
|
||||
else
|
||||
@missing = "#{model_class} has a db column named #{@column} " <<
|
||||
"of limit #{matched_column.limit}, " <<
|
||||
"not #{@limit}."
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def correct_default?
|
||||
return true if @default.nil?
|
||||
if matched_column.default.to_s == @default.to_s
|
||||
true
|
||||
else
|
||||
@missing = "#{model_class} has a db column named #{@column} " <<
|
||||
"of default #{matched_column.default}, " <<
|
||||
"not #{@default}."
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def correct_null?
|
||||
return true if @null.nil?
|
||||
if matched_column.null.to_s == @null.to_s
|
||||
true
|
||||
else
|
||||
@missing = "#{model_class} has a db column named #{@column} " <<
|
||||
"of null #{matched_column.null}, " <<
|
||||
"not #{@null}."
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def correct_scale?
|
||||
return true if @scale.nil?
|
||||
if matched_column.scale.to_s == @scale.to_s
|
||||
true
|
||||
else
|
||||
@missing = "#{model_class} has a db column named #{@column} " <<
|
||||
"of scale #{matched_column.scale}, not #{@scale}."
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def matched_column
|
||||
model_class.columns.detect { |each| each.name == @column.to_s }
|
||||
end
|
||||
|
||||
def model_class
|
||||
@subject.class
|
||||
end
|
||||
|
||||
def expectation
|
||||
expected = "#{model_class.name} to #{description}"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
105
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers/have_index_matcher.rb
vendored
Normal file
105
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers/have_index_matcher.rb
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures that there are DB indices on the given columns or tuples of
|
||||
# columns.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>unique</tt> - whether or not the index has a unique
|
||||
# constraint. Use <tt>true</tt> to explicitly test for a unique
|
||||
# constraint. Use <tt>false</tt> to explicitly test for a non-unique
|
||||
# constraint. Use <tt>nil</tt> if you don't care whether the index is
|
||||
# unique or not. Default = <tt>nil</tt>
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# it { should have_index(:age) }
|
||||
# it { should have_index([:commentable_type, :commentable_id]) }
|
||||
# it { should have_index(:ssn).unique(true) }
|
||||
#
|
||||
def have_index(columns)
|
||||
HaveIndexMatcher.new(:have_index, columns)
|
||||
end
|
||||
|
||||
class HaveIndexMatcher # :nodoc:
|
||||
def initialize(macro, columns)
|
||||
@macro = macro
|
||||
@columns = normalize_columns_to_array(columns)
|
||||
end
|
||||
|
||||
def unique(unique)
|
||||
@unique = unique
|
||||
self
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
@subject = subject
|
||||
index_exists? && correct_unique?
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Expected #{expectation} (#{@missing})"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"Did not expect #{expectation}"
|
||||
end
|
||||
|
||||
def description
|
||||
"have a #{index_type} index on columns #{@columns}"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def index_exists?
|
||||
! matched_index.nil?
|
||||
end
|
||||
|
||||
def correct_unique?
|
||||
return true if @unique.nil?
|
||||
if matched_index.unique == @unique
|
||||
true
|
||||
else
|
||||
@missing = "#{table_name} has an index named #{matched_index.name} " <<
|
||||
"of unique #{matched_index.unique}, not #{@unique}."
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def matched_index
|
||||
indexes.detect { |each| each.columns == @columns }
|
||||
end
|
||||
|
||||
def model_class
|
||||
@subject.class
|
||||
end
|
||||
|
||||
def table_name
|
||||
model_class.table_name
|
||||
end
|
||||
|
||||
def indexes
|
||||
::ActiveRecord::Base.connection.indexes(table_name)
|
||||
end
|
||||
|
||||
def expectation
|
||||
expected = "#{model_class.name} to #{description}"
|
||||
end
|
||||
|
||||
def index_type
|
||||
@unique ? "unique" : "non-unique"
|
||||
end
|
||||
|
||||
def normalize_columns_to_array(columns)
|
||||
if columns.class == Array
|
||||
columns.collect { |each| each.to_s }
|
||||
else
|
||||
[columns.to_s]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
125
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers/have_named_scope_matcher.rb
vendored
Normal file
125
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers/have_named_scope_matcher.rb
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures that the model has a method named scope_call that returns a
|
||||
# NamedScope object with the proxy options set to the options you supply.
|
||||
# scope_call can be either a symbol, or a Ruby expression in a String
|
||||
# which will be evaled. The eval'd method call has access to all the same
|
||||
# instance variables that an example would.
|
||||
#
|
||||
# Options:
|
||||
#
|
||||
# * <tt>in_context</tt> - Any of the options that the named scope would
|
||||
# pass on to find.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# it { should have_named_scope(:visible).
|
||||
# finding(:conditions => {:visible => true}) }
|
||||
#
|
||||
# Passes for
|
||||
#
|
||||
# named_scope :visible, :conditions => {:visible => true}
|
||||
#
|
||||
# Or for
|
||||
#
|
||||
# def self.visible
|
||||
# scoped(:conditions => {:visible => true})
|
||||
# end
|
||||
#
|
||||
# You can test lambdas or methods that return ActiveRecord#scoped calls:
|
||||
#
|
||||
# it { should have_named_scope('recent(5)').finding(:limit => 5) }
|
||||
# it { should have_named_scope('recent(1)').finding(:limit => 1) }
|
||||
#
|
||||
# Passes for
|
||||
# named_scope :recent, lambda {|c| {:limit => c}}
|
||||
#
|
||||
# Or for
|
||||
#
|
||||
# def self.recent(c)
|
||||
# scoped(:limit => c)
|
||||
# end
|
||||
#
|
||||
def have_named_scope(scope_call)
|
||||
HaveNamedScopeMatcher.new(scope_call).in_context(self)
|
||||
end
|
||||
|
||||
class HaveNamedScopeMatcher # :nodoc:
|
||||
|
||||
def initialize(scope_call)
|
||||
@scope_call = scope_call.to_s
|
||||
end
|
||||
|
||||
def finding(finding)
|
||||
@finding = finding
|
||||
self
|
||||
end
|
||||
|
||||
def in_context(context)
|
||||
@context = context
|
||||
self
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
@subject = subject
|
||||
call_succeeds? && returns_scope? && finds_correct_scope?
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Expected #{@missing_expectation}"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"Didn't expect a named scope for #{@scope_call}"
|
||||
end
|
||||
|
||||
def description
|
||||
result = "have a named scope for #{@scope_call}"
|
||||
result << " finding #{@finding.inspect}" unless @finding.nil?
|
||||
result
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def call_succeeds?
|
||||
scope
|
||||
true
|
||||
rescue Exception => exception
|
||||
@missing_expectation = "#{@subject.class.name} " <<
|
||||
"to respond to #{@scope_call} " <<
|
||||
"but raised error: #{exception.inspect}"
|
||||
false
|
||||
end
|
||||
|
||||
def scope
|
||||
@scope ||= @context.instance_eval("#{@subject.class.name}.#{@scope_call}")
|
||||
end
|
||||
|
||||
def returns_scope?
|
||||
if ::ActiveRecord::NamedScope::Scope === scope
|
||||
true
|
||||
else
|
||||
@missing_expectation = "#{@scope_call} to return a scope"
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def finds_correct_scope?
|
||||
return true if @finding.nil?
|
||||
if @finding == scope.proxy_options
|
||||
true
|
||||
else
|
||||
@missing_expectation = "#{@scope_call} to return results scoped to "
|
||||
@missing_expectation << "#{@finding.inspect} but was scoped to "
|
||||
@missing_expectation << scope.proxy_options.inspect
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,59 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures that the attribute cannot be changed once the record has been
|
||||
# created.
|
||||
#
|
||||
# it { should have_readonly_attributes(:password) }
|
||||
#
|
||||
def have_readonly_attribute(value)
|
||||
HaveReadonlyAttributeMatcher.new(value)
|
||||
end
|
||||
|
||||
class HaveReadonlyAttributeMatcher # :nodoc:
|
||||
|
||||
def initialize(attribute)
|
||||
@attribute = attribute.to_s
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
@subject = subject
|
||||
if readonly_attributes.include?(@attribute)
|
||||
@negative_failure_message =
|
||||
"Did not expect #{@attribute} to be read-only"
|
||||
true
|
||||
else
|
||||
if readonly_attributes.empty?
|
||||
@failure_message = "#{class_name} attribute #{@attribute} " <<
|
||||
"is not read-only"
|
||||
else
|
||||
@failure_message = "#{class_name} is making " <<
|
||||
"#{readonly_attributes.to_sentence} " <<
|
||||
"read-only, but not #{@attribute}."
|
||||
end
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :failure_message, :negative_failure_message
|
||||
|
||||
def description
|
||||
"make #{@attribute} read-only"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def readonly_attributes
|
||||
@readonly_attributes ||= (@subject.class.readonly_attributes || [])
|
||||
end
|
||||
|
||||
def class_name
|
||||
@subject.class.name
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,41 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures that the model cannot be saved the given attribute is not
|
||||
# accepted.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>with_message</tt> - value the test expects to find in
|
||||
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
|
||||
# translation for <tt>:accepted</tt>.
|
||||
#
|
||||
# Example:
|
||||
# it { should validate_acceptance_of(:eula) }
|
||||
#
|
||||
def validate_acceptance_of(attr)
|
||||
ValidateAcceptanceOfMatcher.new(attr)
|
||||
end
|
||||
|
||||
class ValidateAcceptanceOfMatcher < ValidationMatcher # :nodoc:
|
||||
|
||||
def with_message(message)
|
||||
@expected_message = message if message
|
||||
self
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
super(subject)
|
||||
@expected_message ||= :accepted
|
||||
disallows_value_of(false, @expected_message)
|
||||
end
|
||||
|
||||
def description
|
||||
"require #{@attribute} to be accepted"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,39 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensure that the attribute is numeric
|
||||
#
|
||||
# Options:
|
||||
# * <tt>with_message</tt> - value the test expects to find in
|
||||
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
|
||||
# translation for <tt>:not_a_number</tt>.
|
||||
#
|
||||
# Example:
|
||||
# it { should validate_numericality_of(:age) }
|
||||
#
|
||||
def validate_numericality_of(attr)
|
||||
ValidateNumericalityOfMatcher.new(attr)
|
||||
end
|
||||
|
||||
class ValidateNumericalityOfMatcher < ValidationMatcher # :nodoc:
|
||||
|
||||
def with_message(message)
|
||||
@expected_message = message if message
|
||||
self
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
super(subject)
|
||||
@expected_message ||= :not_a_number
|
||||
disallows_value_of('abcd', @expected_message)
|
||||
end
|
||||
|
||||
def description
|
||||
"only allow numeric values for #{@attribute}"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,60 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures that the model is not valid if the given attribute is not
|
||||
# present.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>with_message</tt> - value the test expects to find in
|
||||
# <tt>errors.on(:attribute)</tt>. <tt>Regexp</tt> or <tt>String</tt>.
|
||||
# Defaults to the translation for <tt>:blank</tt>.
|
||||
#
|
||||
# Examples:
|
||||
# it { should validate_presence_of(:name) }
|
||||
# it { should validate_presence_of(:name).
|
||||
# with_message(/is not optional/) }
|
||||
#
|
||||
def validate_presence_of(attr)
|
||||
ValidatePresenceOfMatcher.new(attr)
|
||||
end
|
||||
|
||||
class ValidatePresenceOfMatcher < ValidationMatcher # :nodoc:
|
||||
|
||||
def with_message(message)
|
||||
@expected_message = message if message
|
||||
self
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
super(subject)
|
||||
@expected_message ||= :blank
|
||||
disallows_value_of(blank_value, @expected_message)
|
||||
end
|
||||
|
||||
def description
|
||||
"require #{@attribute} to be set"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def blank_value
|
||||
if collection?
|
||||
[]
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def collection?
|
||||
if reflection = @subject.class.reflect_on_association(@attribute)
|
||||
[:has_many, :has_and_belongs_to_many].include?(reflection.macro)
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,148 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Matchers
|
||||
|
||||
# Ensures that the model is invalid if the given attribute is not unique.
|
||||
#
|
||||
# Internally, this uses values from existing records to test validations,
|
||||
# so this will always fail if you have not saved at least one record for
|
||||
# the model being tested, like so:
|
||||
#
|
||||
# describe User do
|
||||
# before(:each) { User.create!(:email => 'address@example.com') }
|
||||
# it { should validate_uniqueness_of(:email) }
|
||||
# end
|
||||
#
|
||||
# Options:
|
||||
#
|
||||
# * <tt>with_message</tt> - value the test expects to find in
|
||||
# <tt>errors.on(:attribute)</tt>. <tt>Regexp</tt> or <tt>String</tt>.
|
||||
# Defaults to the translation for <tt>:taken</tt>.
|
||||
# * <tt>scoped_to</tt> - field(s) to scope the uniqueness to.
|
||||
# * <tt>case_insensitive</tt> - ensures that the validation does not
|
||||
# check case. Off by default. Ignored by non-text attributes.
|
||||
#
|
||||
# Examples:
|
||||
# it { should validate_uniqueness_of(:keyword) }
|
||||
# it { should validate_uniqueness_of(:keyword).with_message(/dup/) }
|
||||
# it { should validate_uniqueness_of(:email).scoped_to(:name) }
|
||||
# it { should validate_uniqueness_of(:email).
|
||||
# scoped_to(:first_name, :last_name) }
|
||||
# it { should validate_uniqueness_of(:keyword).case_insensitive }
|
||||
#
|
||||
def validate_uniqueness_of(attr)
|
||||
ValidateUniquenessOfMatcher.new(attr)
|
||||
end
|
||||
|
||||
class ValidateUniquenessOfMatcher < ValidationMatcher # :nodoc:
|
||||
include Helpers
|
||||
|
||||
def initialize(attribute)
|
||||
@attribute = attribute
|
||||
end
|
||||
|
||||
def scoped_to(*scopes)
|
||||
@scopes = [*scopes].flatten
|
||||
self
|
||||
end
|
||||
|
||||
def with_message(message)
|
||||
@expected_message = message
|
||||
self
|
||||
end
|
||||
|
||||
def case_insensitive
|
||||
@case_insensitive = true
|
||||
self
|
||||
end
|
||||
|
||||
def description
|
||||
result = "require "
|
||||
result << "case sensitive " unless @case_insensitive
|
||||
result << "unique value for #{@attribute}"
|
||||
result << " scoped to #{@scopes.join(', ')}" unless @scopes.blank?
|
||||
result
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
@subject = subject.class.new
|
||||
@expected_message ||= :taken
|
||||
find_existing &&
|
||||
set_scoped_attributes &&
|
||||
validate_attribute &&
|
||||
validate_after_scope_change
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_existing
|
||||
if @existing = @subject.class.find(:first)
|
||||
true
|
||||
else
|
||||
@failure_message = "Can't find first #{class_name}"
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def set_scoped_attributes
|
||||
unless @scopes.blank?
|
||||
@scopes.each do |scope|
|
||||
setter = :"#{scope}="
|
||||
unless @subject.respond_to?(setter)
|
||||
@failure_message =
|
||||
"#{class_name} doesn't seem to have a #{scope} attribute."
|
||||
return false
|
||||
end
|
||||
@subject.send("#{scope}=", @existing.send(scope))
|
||||
end
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def validate_attribute
|
||||
disallows_value_of(existing_value, @expected_message)
|
||||
end
|
||||
|
||||
# TODO: There is a chance that we could change the scoped field
|
||||
# to a value that's already taken. An alternative implementation
|
||||
# could actually find all values for scope and create a unique
|
||||
def validate_after_scope_change
|
||||
if @scopes.blank?
|
||||
true
|
||||
else
|
||||
@scopes.all? do |scope|
|
||||
previous_value = @existing.send(scope)
|
||||
|
||||
# Assume the scope is a foreign key if the field is nil
|
||||
previous_value ||= 0
|
||||
|
||||
next_value = previous_value.next
|
||||
|
||||
@subject.send("#{scope}=", next_value)
|
||||
|
||||
if allows_value_of(existing_value, @expected_message)
|
||||
@negative_failure_message <<
|
||||
" (with different value of #{scope})"
|
||||
true
|
||||
else
|
||||
@failure_message << " (with different value of #{scope})"
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def class_name
|
||||
@subject.class.name
|
||||
end
|
||||
|
||||
def existing_value
|
||||
value = @existing.send(@attribute)
|
||||
value.swapcase! if @case_insensitive && value.respond_to?(:swapcase!)
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
56
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers/validation_matcher.rb
vendored
Normal file
56
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/active_record/matchers/validation_matcher.rb
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
module Shoulda # :nodoc:
|
||||
module ActiveRecord # :nodoc:
|
||||
module Matchers
|
||||
|
||||
class ValidationMatcher # :nodoc:
|
||||
|
||||
attr_reader :failure_message
|
||||
|
||||
def initialize(attribute)
|
||||
@attribute = attribute
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
@negative_failure_message || @failure_message
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
@subject = subject
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def allows_value_of(value, message = nil)
|
||||
allow = AllowValueMatcher.
|
||||
new(value).
|
||||
for(@attribute).
|
||||
with_message(message)
|
||||
if allow.matches?(@subject)
|
||||
@negative_failure_message = allow.failure_message
|
||||
true
|
||||
else
|
||||
@failure_message = allow.negative_failure_message
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def disallows_value_of(value, message = nil)
|
||||
disallow = AllowValueMatcher.
|
||||
new(value).
|
||||
for(@attribute).
|
||||
with_message(message)
|
||||
if disallow.matches?(@subject)
|
||||
@failure_message = disallow.negative_failure_message
|
||||
false
|
||||
else
|
||||
@negative_failure_message = disallow.failure_message
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
59
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/assertions.rb
vendored
Normal file
59
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/assertions.rb
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
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)
|
||||
success = matcher.matches?(target)
|
||||
assert_block(matcher.failure_message) { success }
|
||||
end
|
||||
|
||||
# Asserts that the given matcher returns false when +target+ is passed to #matches?
|
||||
def assert_rejects(matcher, target)
|
||||
success = !matcher.matches?(target)
|
||||
assert_block(matcher.negative_failure_message) { success }
|
||||
end
|
||||
end
|
||||
end
|
||||
46
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/autoload_macros.rb
vendored
Normal file
46
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/autoload_macros.rb
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
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
|
||||
304
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/context.rb
vendored
Normal file
304
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/context.rb
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
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
|
||||
|
||||
def should(name, options = {}, &blk)
|
||||
if Shoulda.current_context
|
||||
block_given? ? Shoulda.current_context.should(name, options, &blk) : Should.current_context.should_eventually(name)
|
||||
else
|
||||
context_name = self.name.gsub(/Test/, "")
|
||||
context = Shoulda::Context.new(context_name, self) do
|
||||
block_given? ? should(name, options, &blk) : should_eventually(name)
|
||||
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
|
||||
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
|
||||
|
||||
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, options = {}, &blk)
|
||||
if block_given?
|
||||
self.shoulds << { :name => name, :before => options[:before], :block => blk }
|
||||
else
|
||||
self.should_eventuallys << { :name => name }
|
||||
end
|
||||
end
|
||||
|
||||
def should_eventually(name, &blk)
|
||||
self.should_eventuallys << { :name => name, :block => blk }
|
||||
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 create_test_from_should_hash(should)
|
||||
test_name = ["test:", full_name, "should", "#{should[:name]}. "].flatten.join(' ').to_sym
|
||||
|
||||
if test_unit_class.instance_methods.include?(test_name.to_s)
|
||||
warn " * WARNING: '#{test_name}' is already defined"
|
||||
end
|
||||
|
||||
context = self
|
||||
test_unit_class.send(:define_method, test_name) do
|
||||
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
|
||||
8
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/helpers.rb
vendored
Normal file
8
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/helpers.rb
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
module Shoulda # :nodoc:
|
||||
module Helpers
|
||||
# Prints a message to stdout, tagged with the name of the calling method.
|
||||
def report!(msg = "")
|
||||
puts("#{caller.first}: #{msg}")
|
||||
end
|
||||
end
|
||||
end
|
||||
73
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/macros.rb
vendored
Normal file
73
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/macros.rb
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
require 'shoulda/private_helpers'
|
||||
|
||||
module Shoulda # :nodoc:
|
||||
module Macros
|
||||
# Macro that creates a test asserting a change between the return value
|
||||
# of an expression that is run before and after the current setup block
|
||||
# is run. This is similar to Active Support's <tt>assert_difference</tt>
|
||||
# assertion, but supports more than just numeric values. See also
|
||||
# should_not_change.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# context "Creating a post" do
|
||||
# setup { Post.create }
|
||||
# should_change "Post.count", :by => 1
|
||||
# end
|
||||
#
|
||||
# As shown in this example, the <tt>:by</tt> option expects a numeric
|
||||
# difference between the before and after values of the expression. You
|
||||
# may also specify <tt>:from</tt> and <tt>:to</tt> options:
|
||||
#
|
||||
# should_change "Post.count", :from => 0, :to => 1
|
||||
# should_change "@post.title", :from => "old", :to => "new"
|
||||
#
|
||||
# Combinations of <tt>:by</tt>, <tt>:from</tt>, and <tt>:to</tt> are allowed:
|
||||
#
|
||||
# should_change "@post.title" # => assert the value changed in some way
|
||||
# should_change "@post.title", :from => "old" # => assert the value changed to anything other than "old"
|
||||
# should_change "@post.title", :to => "new" # => assert the value changed from anything other than "new"
|
||||
def should_change(expression, options = {})
|
||||
by, from, to = get_options!([options], :by, :from, :to)
|
||||
stmt = "change #{expression.inspect}"
|
||||
stmt << " from #{from.inspect}" if from
|
||||
stmt << " to #{to.inspect}" if to
|
||||
stmt << " by #{by.inspect}" if by
|
||||
|
||||
expression_eval = lambda { eval(expression) }
|
||||
before = lambda { @_before_should_change = expression_eval.bind(self).call }
|
||||
should stmt, :before => before do
|
||||
old_value = @_before_should_change
|
||||
new_value = expression_eval.bind(self).call
|
||||
assert_operator from, :===, old_value, "#{expression.inspect} did not originally match #{from.inspect}" if from
|
||||
assert_not_equal old_value, new_value, "#{expression.inspect} did not change" unless by == 0
|
||||
assert_operator to, :===, new_value, "#{expression.inspect} was not changed to match #{to.inspect}" if to
|
||||
assert_equal old_value + by, new_value if by
|
||||
end
|
||||
end
|
||||
|
||||
# Macro that creates a test asserting no change between the return value
|
||||
# of an expression that is run before and after the current setup block
|
||||
# is run. This is the logical opposite of should_change.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# context "Updating a post" do
|
||||
# setup { @post.update_attributes(:title => "new") }
|
||||
# should_not_change "Post.count"
|
||||
# end
|
||||
def should_not_change(expression)
|
||||
expression_eval = lambda { eval(expression) }
|
||||
before = lambda { @_before_should_not_change = expression_eval.bind(self).call }
|
||||
should "not change #{expression.inspect}", :before => before do
|
||||
new_value = expression_eval.bind(self).call
|
||||
assert_equal @_before_should_not_change, new_value, "#{expression.inspect} changed"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
include Shoulda::Private
|
||||
end
|
||||
end
|
||||
|
||||
20
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/private_helpers.rb
vendored
Normal file
20
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/private_helpers.rb
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
module Shoulda # :nodoc:
|
||||
module Private # :nodoc:
|
||||
# Returns the values for the entries in the args hash who's keys are listed in the wanted array.
|
||||
# Will raise if there are keys in the args hash that aren't listed.
|
||||
def get_options!(args, *wanted)
|
||||
ret = []
|
||||
opts = (args.last.is_a?(Hash) ? args.pop : {})
|
||||
wanted.each {|w| ret << opts.delete(w)}
|
||||
raise ArgumentError, "Unsupported options given: #{opts.keys.join(', ')}" unless opts.keys.empty?
|
||||
return *ret
|
||||
end
|
||||
|
||||
# Returns the model class constant, as determined by the test class name.
|
||||
#
|
||||
# class TestUser; model_class; end => User
|
||||
def model_class
|
||||
self.name.gsub(/Test$/, '').constantize
|
||||
end
|
||||
end
|
||||
end
|
||||
14
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/proc_extensions.rb
vendored
Normal file
14
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/proc_extensions.rb
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# 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
|
||||
13
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/rails.rb
vendored
Normal file
13
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/rails.rb
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
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_view' if defined? ActionView::Base
|
||||
require 'shoulda/action_mailer' if defined? ActionMailer::Base
|
||||
|
||||
if defined?(RAILS_ROOT)
|
||||
# load in the 3rd party macros from vendorized plugins and gems
|
||||
Shoulda.autoload_macros RAILS_ROOT, File.join("vendor", "{plugins,gems}", "*")
|
||||
end
|
||||
11
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/rspec.rb
vendored
Normal file
11
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/rspec.rb
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
require 'shoulda/active_record/matchers'
|
||||
require 'shoulda/action_controller/matchers'
|
||||
require 'active_support/test_case'
|
||||
|
||||
# :enddoc:
|
||||
module ActiveSupport
|
||||
class TestCase
|
||||
include Shoulda::ActiveRecord::Matchers
|
||||
include Shoulda::ActionController::Matchers
|
||||
end
|
||||
end
|
||||
3
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/tasks.rb
vendored
Normal file
3
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/tasks.rb
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Dir[File.join(File.dirname(__FILE__), 'tasks', '*.rake')].each do |f|
|
||||
load f
|
||||
end
|
||||
29
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/tasks/list_tests.rake
vendored
Normal file
29
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/tasks/list_tests.rake
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
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
|
||||
28
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/tasks/yaml_to_shoulda.rake
vendored
Normal file
28
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/tasks/yaml_to_shoulda.rake
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
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
|
||||
19
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/test_unit.rb
vendored
Normal file
19
vendor/gems/thoughtbot-shoulda-2.10.1/lib/shoulda/test_unit.rb
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
require 'shoulda/context'
|
||||
require 'shoulda/proc_extensions'
|
||||
require 'shoulda/assertions'
|
||||
require 'shoulda/macros'
|
||||
require 'shoulda/helpers'
|
||||
require 'shoulda/autoload_macros'
|
||||
require 'shoulda/rails' if defined? RAILS_ROOT
|
||||
|
||||
module Test # :nodoc: all
|
||||
module Unit
|
||||
class TestCase
|
||||
extend Shoulda::ClassMethods
|
||||
include Shoulda::Assertions
|
||||
extend Shoulda::Macros
|
||||
include Shoulda::Helpers
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user