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

Adds accept_nested_attributes_for matcher

Currently supports the options "allow_destroy", "limit", and
"update_only"
This commit is contained in:
Brendan Loudermilk 2012-04-11 11:33:21 -07:00 committed by Gabe Berke-Williams
parent 6297c73615
commit ee7422280d
3 changed files with 212 additions and 0 deletions

View file

@ -4,6 +4,7 @@ require 'shoulda/matchers/active_record/have_db_index_matcher'
require 'shoulda/matchers/active_record/have_readonly_attribute_matcher'
require 'shoulda/matchers/active_record/serialize_matcher'
require 'shoulda/matchers/active_record/query_the_database_matcher'
require 'shoulda/matchers/active_record/accept_nested_attributes_for_matcher'
module Shoulda
module Matchers

View file

@ -0,0 +1,127 @@
module Shoulda
module Matchers
module ActiveRecord
# Ensures that the model can accept nested attributes for the specified
# association.
#
# Options:
# * <tt>allow_destroy</tt> - Whether or not to allow destroy
# * <tt>limit</tt> - Max number of nested attributes
# * <tt>update_only</tt> - Only allow updates
#
# Example:
# it { should accept_nested_attributes_for(:friends) }
# it { should accept_nested_attributes_for(:friends).
# allow_destroy(true).
# limit(4) }
# it { should accept_nested_attributes_for(:friends).
# update_only(true) }
#
def accept_nested_attributes_for(name)
AcceptNestedAttributesForMatcher.new(name)
end
class AcceptNestedAttributesForMatcher
def initialize(name)
@name = name
self
end
def allow_destroy(allow_destroy)
@allow_destroy = allow_destroy
self
end
def limit(limit)
@limit = limit
self
end
def update_only(update_only)
@update_only = update_only
self
end
def matches?(subject)
@subject = subject
exists? &&
allow_destroy_correct? &&
limit_correct? &&
update_only_correct?
end
def failure_message
"Expected #{expectation} (#{@problem})"
end
def negative_failure_message
"Did not expect #{expectation}"
end
def description
description = "accepts_nested_attributes_for :#{@name}"
description += " allow_destroy => #{@allow_destroy}" if @allow_destroy
description += " limit => #{@limit}" if @limit
description += " update_only => #{@update_only}" if @update_only
description
end
protected
def exists?
if config
true
else
@problem = "is not declared"
false
end
end
def allow_destroy_correct?
if @allow_destroy.nil? || @allow_destroy == config[:allow_destroy]
true
else
@problem = (@allow_destroy ? "should" : "should not") +
" allow destroy"
false
end
end
def limit_correct?
if @limit.nil? || @limit == config[:limit]
true
else
@problem = "limit should be #@limit, got #{config[:limit]}"
false
end
end
def update_only_correct?
if @update_only.nil? || @update_only == config[:update_only]
true
else
@problem = (@update_only ? "should" : "should not") +
" be update only"
false
end
end
def config
model_config[@name]
end
def model_config
model_class.nested_attributes_options
end
def model_class
@subject.class
end
def expectation
"#{model_class.name} to accept nested attributes for #{@name}"
end
end
end
end
end

View file

@ -0,0 +1,84 @@
require 'spec_helper'
describe Shoulda::Matchers::ActiveRecord::AcceptNestedAttributesForMatcher do
before do
define_model :child, :parent_id => :integer
define_model :parent do
has_many :children
end
end
let(:parent) { Parent.new }
let(:matcher) { accept_nested_attributes_for(:children) }
it "should accept an existing declaration" do
Parent.accepts_nested_attributes_for :children
matcher.matches?(parent).should be_true
end
it "should reject a missing declaration" do
matcher.matches?(parent).should be_false
matcher.failure_message.should == "Expected Parent to accept nested attributes for children (is not declared)"
end
context "allow_destroy" do
it "should accept a valid truthy value" do
Parent.accepts_nested_attributes_for :children, :allow_destroy => true
matcher.allow_destroy(true).matches?(parent).should be_true
end
it "should accept a valid falsey value" do
Parent.accepts_nested_attributes_for :children, :allow_destroy => false
matcher.allow_destroy(false).matches?(parent).should be_true
end
it "should reject an invalid truthy value" do
Parent.accepts_nested_attributes_for :children, :allow_destroy => true
matcher.allow_destroy(false).matches?(parent).should be_false
matcher.failure_message.should =~ /should not allow destroy/
end
it "should reject an invalid falsey value" do
Parent.accepts_nested_attributes_for :children, :allow_destroy => false
matcher.allow_destroy(true).matches?(parent).should be_false
matcher.failure_message.should =~ /should allow destroy/
end
end
context "limit" do
it "should accept a correct value" do
Parent.accepts_nested_attributes_for :children, :limit => 3
matcher.limit(3).matches?(parent).should be_true
end
it "should reject a false value" do
Parent.accepts_nested_attributes_for :children, :limit => 3
matcher.limit(2).matches?(parent).should be_false
matcher.failure_message.should =~ /limit should be 2, got 3/
end
end
context "update_only" do
it "should accept a valid truthy value" do
Parent.accepts_nested_attributes_for :children, :update_only => true
matcher.update_only(true).matches?(parent).should be_true
end
it "should accept a valid falsey value" do
Parent.accepts_nested_attributes_for :children, :update_only => false
matcher.update_only(false).matches?(parent).should be_true
end
it "should reject an invalid truthy value" do
Parent.accepts_nested_attributes_for :children, :update_only => true
matcher.update_only(false).matches?(parent).should be_false
matcher.failure_message.should =~ /should not be update only/
end
it "should reject an invalid falsey value" do
Parent.accepts_nested_attributes_for :children, :update_only => false
matcher.update_only(true).matches?(parent).should be_false
matcher.failure_message.should =~ /should be update only/
end
end
end