Skip to content

Commit

Permalink
WIP: Add ignoring_interference_by_writer to all matchers
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmire committed Dec 22, 2015
1 parent 6a710f6 commit 24a358e
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 86 deletions.
23 changes: 23 additions & 0 deletions lib/shoulda/matchers/active_model/allow_value_matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,10 @@ def failure_message
end
end

if include_attribute_changed_value_message?
message << "\n\n" + attribute_changed_value_message
end

Shoulda::Matchers.word_wrap(message)
end

Expand Down Expand Up @@ -494,9 +498,23 @@ def failure_message_when_negated
end
end

if include_attribute_changed_value_message?
message << "\n\n" + attribute_changed_value_message
end

Shoulda::Matchers.word_wrap(message)
end

def attribute_changed_value_message
<<-MESSAGE.strip
As indicated in the message above, :#{result.attribute_setter.attribute_name}
seems to be changing certain values as they are set, and this could have
something to do with why this test is failing. If you've overridden the writer
method for this attribute, then you may need to change it to make this test
pass, or do something else entirely.
MESSAGE
end

def description
ValidationMatcher::BuildDescription.call(self, simple_description)
end
Expand Down Expand Up @@ -568,6 +586,11 @@ def attribute_setters_and_validators_for_values_to_set
)
end

def include_attribute_changed_value_message?
ignoring_interference_by_writer? &&
result.attribute_setter.attribute_changed_value?
end

def simple_description
"allow :#{attribute_to_set} to be #{inspected_values_to_set}"
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def self.set(args)
new(args).set
end

attr_reader :result_of_checking, :result_of_setting
attr_reader :attribute_name, :result_of_checking, :result_of_setting

def initialize(args)
@matcher_name = args.fetch(:matcher_name)
Expand Down Expand Up @@ -124,9 +124,13 @@ def successfully_set?
set? && result_of_setting.successful?
end

def attribute_changed_value?
value_written != value_read
end

protected

attr_reader :matcher_name, :object, :attribute_name, :value_written,
attr_reader :matcher_name, :object, :value_written,
:after_set_callback

private
Expand All @@ -139,10 +143,6 @@ def attribute_exists?
object.respond_to?("#{attribute_name}=")
end

def attribute_changed_value?
value_written != value_read
end

def value_read
@_value_read ||= object.public_send(attribute_name)
end
Expand Down
4 changes: 2 additions & 2 deletions lib/shoulda/matchers/active_model/disallow_value_matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ def strict(strict = true)
self
end

def ignoring_interference_by_writer
allow_matcher.ignoring_interference_by_writer
def ignoring_interference_by_writer(value = true)
allow_matcher.ignoring_interference_by_writer(value)
self
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def matches?(subject)
end

def simple_description
"validate that #{@attribute} has been set to true"
%(validate that :#{@attribute} has been set to "1")
end
end
end
Expand Down
17 changes: 11 additions & 6 deletions lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -352,17 +352,15 @@ def with_high_message(message)

def simple_description
if @range
"validate that :#{@attribute} lies inside the range #{@range.inspect}"
"validate that :#{@attribute} lies inside the range " +
Shoulda::Matchers::Util.inspect_range(@range)
else
description = "validate that :#{@attribute}"

if @array.many?
description << " is either " + @array.map(&:inspect).to_sentence(
two_words_connector: " or ",
last_word_connector: ", or "
)
description << " is either #{inspected_array}"
else
description << " is #{@array.first.inspect}"
description << " is #{inspected_array}"
end

description
Expand Down Expand Up @@ -552,6 +550,13 @@ def value_to_attribute_type(value)
else :unknown
end
end

def inspected_array
Shoulda::Matchers::Util.inspect_values(@array).to_sentence(
two_words_connector: " or ",
last_word_connector: ", or "
)
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def self.available_column_types

context 'when the writer method for the attribute changes incoming values' do
context 'and the matcher has not been qualified with ignoring_interference_by_writer' do
it 'raises a CouldNotSetAttributeError' do
it 'raises an AttributeChangedValueError' do
model = define_model_validating_absence_of(:name)

model.class_eval do
Expand All @@ -161,7 +161,7 @@ def name=(name)
end

expect(&assertion).to raise_error(
Shoulda::Matchers::ActiveModel::AllowValueMatcher::CouldNotSetAttributeError
Shoulda::Matchers::ActiveModel::AllowValueMatcher::AttributeChangedValueError
)
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

context 'when the writer method for the attribute changes incoming values' do
context 'and the matcher has not been qualified with ignoring_interference_by_writer' do
it 'raises a CouldNotSetAttributeError' do
it 'raises an AttributeChangedValueError' do
model = define_model_validating_acceptance(
attribute_name: :terms_of_service
)
Expand All @@ -53,7 +53,7 @@ def terms_of_service=(value)
end

expect(&assertion).to raise_error(
Shoulda::Matchers::ActiveModel::AllowValueMatcher::CouldNotSetAttributeError
Shoulda::Matchers::ActiveModel::AllowValueMatcher::AttributeChangedValueError
)
end
end
Expand Down Expand Up @@ -82,13 +82,15 @@ def terms_of_service=(value)
ignoring_interference_by_writer
end

xcontext 'and the value change causes a test failure' do
context 'and the value change causes a test failure' do
it 'lists how the value got changed in the failure message' do
model = define_model_validating_acceptance(
attribute_name: :terms_of_service
)

model.class_eval do
undef_method :terms_of_service=

def terms_of_service=(value)
end
end
Expand All @@ -100,7 +102,17 @@ def terms_of_service=(value)
end

message = <<-MESSAGE
This is yo message, yo.
Example did not properly validate that :terms_of_service has been set to
"1".
After setting :terms_of_service to false -- which was read back as nil
-- the matcher expected the Example to be invalid, but it was valid
instead.
As indicated in the message above, :terms_of_service seems to be
changing certain values as they are set, and this could have something
to do with why this test is failing. If you've overridden the writer
method for this attribute, then you may need to change it to make this
test pass, or do something else entirely.
MESSAGE

expect(&assertion).to fail_with_message(message)
Expand Down
Loading

0 comments on commit 24a358e

Please sign in to comment.