Dependent qualifier now supports more values

* :destroy
* :delete
* :nullify
* :restrict
* :restrict_with_exception (Rails 4+)
* :restrict_with_error (Rails 4+)
* true
* false
This commit is contained in:
Sean Devine 2014-12-28 08:04:49 -05:00 committed by Elliot Winkler
parent 45f39603aa
commit 948757b3f8
5 changed files with 99 additions and 16 deletions

12
NEWS.md
View File

@ -1,3 +1,15 @@
# HEAD
### Features
* Update `dependent` qualifier on association matchers to support `:destroy`,
`:delete`, `:nullify`, `:restrict`, `:restrict_with_exception`, and
`:restrict_with_error`. You can also pass `true` or `false` to assert that
the association has (or has not) been declared with *any* dependent option.
([#631])
[#631]: https://github.com/thoughtbot/shoulda-matchers/pull/631
# 2.8.0.rc1
### Deprecations

View File

@ -162,6 +162,24 @@ module Shoulda
# should belong_to(:world).dependent(:destroy)
# end
#
# To assert that *any* `:dependent` option was specified, use `true`:
#
# # RSpec
# describe Person do
# it { should belong_to(:world).dependent(true) }
# end
#
# To assert that *no* `:dependent` option was specified, use `false`:
#
# class Person < ActiveRecord::Base
# belongs_to :company
# end
#
# # RSpec
# describe Person do
# it { should belong_to(:company).dependent(false) }
# end
#
# ##### counter_cache
#
# Use `counter_cache` to assert that the `:counter_cache` option was
@ -993,7 +1011,7 @@ module Shoulda
end
def macro_supports_primary_key?
macro == :belongs_to ||
macro == :belongs_to ||
([:has_many, :has_one].include?(macro) && !through?)
end

View File

@ -19,10 +19,10 @@ module Shoulda
def matches?(subject)
self.subject = ModelReflector.new(subject, name)
if option_verifier.correct_for_string?(:dependent, dependent)
if option_matches?
true
else
self.missing_option = "#{name} should have #{dependent} dependency"
self.missing_option = generate_missing_option
false
end
end
@ -31,9 +31,30 @@ module Shoulda
attr_accessor :subject, :dependent, :name
private
def option_verifier
@option_verifier ||= OptionVerifier.new(subject)
end
def option_matches?
option_verifier.correct_for?(option_type, :dependent, dependent)
end
def option_type
case dependent
when true, false then :boolean
else :string
end
end
def generate_missing_option
[
"#{name} should have",
(dependent == true ? 'a' : dependent),
'dependency'
].join(' ')
end
end
end
end

View File

@ -32,6 +32,20 @@ module Shoulda
correct_for?(:relation_clause, name, expected_value)
end
def correct_for?(*args)
expected_value, name, type = args.reverse
if expected_value.nil?
true
else
expected_value = type_cast(
type,
expected_value_for(type, name, expected_value)
)
actual_value = type_cast(type, actual_value_for(name))
expected_value == actual_value
end
end
def actual_value_for(name)
if RELATION_OPTIONS.include?(name)
actual_value_for_relation_clause(name)
@ -49,17 +63,6 @@ module Shoulda
attr_reader :reflector
def correct_for?(*args)
expected_value, name, type = args.reverse
if expected_value.nil?
true
else
expected_value = type_cast(type, expected_value_for(type, name, expected_value))
actual_value = type_cast(type, actual_value_for(name))
expected_value == actual_value
end
end
def type_cast(type, value)
case type
when :string, :relation_clause then value.to_s

View File

@ -646,8 +646,28 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher, type: :model do
end
it 'accepts an association with a valid :dependent option' do
expect(having_one_detail(dependent: :destroy)).
to have_one(:detail).dependent(:destroy)
dependent_options.each do |option|
expect(having_one_detail(dependent: option)).
to have_one(:detail).dependent(option)
end
end
it 'accepts any dependent option if true' do
dependent_options.each do |option|
expect(having_one_detail(dependent: option)).
to have_one(:detail).dependent(true)
end
end
it 'rejects any dependent options if false' do
dependent_options.each do |option|
expect(having_one_detail(dependent: option)).
to_not have_one(:detail).dependent(false)
end
end
it 'accepts a nil dependent option if false' do
expect(having_one_detail).to have_one(:detail).dependent(false)
end
it 'rejects an association with a bad :dependent option' do
@ -1117,4 +1137,13 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher, type: :model do
args << options
model.__send__(macro, name, *args)
end
def dependent_options
case Rails.version
when /\A3/
[:destroy, :delete, :nullify, :restrict]
when /\A4/
[:destroy, :delete, :nullify, :restrict_with_exception, :restrict_with_error]
end
end
end