Skip to content

Commit

Permalink
Converted should_ensure_length_in_range to use a matcher
Browse files Browse the repository at this point in the history
  • Loading branch information
jferris committed Jan 27, 2009
1 parent 291c332 commit d5c48ee
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 50 deletions.
44 changes: 12 additions & 32 deletions lib/shoulda/active_record/macros.rb
Expand Up @@ -87,7 +87,7 @@ def should_require_unique_attributes(*attributes)
with_message(message).scoped_to(scope)
matcher = matcher.case_insensitive unless case_sensitive
should matcher.description do
assert_accepts(matcher, klass.new)
assert_accepts(matcher, get_instance_of(klass))
end
end
end
Expand Down Expand Up @@ -195,39 +195,19 @@ def should_allow_values_for(attribute, *good_values)
# 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)
short_message ||= default_error_message(:too_short, :count => range.first)
long_message ||= default_error_message(:too_long, :count => range.last)

short_message, long_message = get_options!([opts],
:short_message,
:long_message)
klass = model_class
min_length = range.first
max_length = range.last
same_length = (min_length == max_length)

if min_length > 0
should "not allow #{attribute} to be less than #{min_length} chars long" do
min_value = "x" * (min_length - 1)
assert_bad_value(klass, attribute, min_value, short_message)
end
end

if min_length > 0
should "allow #{attribute} to be exactly #{min_length} chars long" do
min_value = "x" * min_length
assert_good_value(klass, attribute, min_value, short_message)
end
end

should "not allow #{attribute} to be more than #{max_length} chars long" do
max_value = "x" * (max_length + 1)
assert_bad_value(klass, attribute, max_value, long_message)
end
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)

unless same_length
should "allow #{attribute} to be exactly #{max_length} chars long" do
max_value = "x" * max_length
assert_good_value(klass, attribute, max_value, long_message)
end
should matcher.description do
assert_accepts matcher, get_instance_of(klass)
end
end

Expand All @@ -253,7 +233,7 @@ def should_ensure_length_at_least(attribute, min_length, opts = {})
with_short_message(short_message)

should matcher.description do
assert_accepts matcher, klass.new
assert_accepts matcher, get_instance_of(klass)
end
end

Expand Down
79 changes: 61 additions & 18 deletions lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb
Expand Up @@ -14,7 +14,17 @@ def is_at_least(length)
@short_message ||= :too_short
if Symbol === @short_message
@short_message = default_error_message(@short_message,
:count => @minimum)
:count => @minimum)
end
self
end

def is_at_most(length)
@maximum = length
@long_message ||= :too_long
if Symbol === @long_message
@long_message = default_error_message(@long_message,
:count => @maximum)
end
self
end
Expand All @@ -24,39 +34,58 @@ def with_short_message(message)
self
end

def with_long_message(message)
@long_message = message if message
self
end

attr_reader :failure_message, :negative_failure_message

def description
"ensure #{@attribute} has a length of at least #{@minimum}"
description = "ensure #{@attribute} has a length "
if @minimum && @maximum
description << "between #{@minimum} and #{@maximum}"
else
description << "of at least #{@minimum}" if @minimum
description << "of at most #{@maximum}" if @maximum
end
description
end

def matches?(subject)
@subject = subject
disallows_lower_length && allows_correct_length
disallows_lower_length &&
allows_minimum_length &&
disallows_higher_length &&
allows_maximum_length
end

private

def disallows_lower_length
return true if @minimum == 0
@disallow = AllowValueMatcher.
new(value_of_length(@minimum - 1)).
for(@attribute).
with_message(@short_message)
if @disallow.matches?(@subject)
@failure_message = @disallow.negative_failure_message
false
else
@negative_failure_message = @disallow.failure_message
true
end
return true if @minimum == 0 || @minimum.nil?
disallows_length_of(@minimum - 1, @short_message)
end

def allows_correct_length
def disallows_higher_length
return true if @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)
return true if length.nil?
@allow = AllowValueMatcher.
new(value_of_length(@minimum)).
new(value_of_length(length)).
for(@attribute).
with_message(@short_message)
with_message(message)
if @allow.matches?(@subject)
@negative_failure_message = @allow.failure_message
true
Expand All @@ -66,6 +95,20 @@ def allows_correct_length
end
end

def disallows_length_of(length, message)
@disallow = AllowValueMatcher.
new(value_of_length(length)).
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

def value_of_length(length)
'x' * length
end
Expand Down
49 changes: 49 additions & 0 deletions test/matchers/ensure_length_of_matcher_test.rb
Expand Up @@ -47,6 +47,39 @@ class EnsureLengthOfMatcher < Test::Unit::TestCase # :nodoc:
end
end

context "an attribute with a maximum length" do
setup do
@model = build_model_class(:example, :attr => :string) do
validates_length_of :attr, :maximum => 4
end.new
end

should "accept ensuring the correct maximum length" do
assert_accepts ensure_length_of(:attr).is_at_most(4), @model
end

should "reject ensuring a lower maximum length with any message" do
assert_rejects ensure_length_of(:attr).
is_at_most(3).
with_long_message(/.*/),
@model
end

should "reject ensuring a higher maximum length with any message" do
assert_rejects ensure_length_of(:attr).
is_at_most(5).
with_long_message(/.*/),
@model
end

should "not override the default message with a blank" do
assert_accepts ensure_length_of(:attr).
is_at_most(4).
with_long_message(nil),
@model
end
end

context "an attribute with a custom minimum length validation" do
setup do
@model = build_model_class(:example, :attr => :string) do
Expand All @@ -63,6 +96,22 @@ class EnsureLengthOfMatcher < Test::Unit::TestCase # :nodoc:

end

context "an attribute with a custom maximum length validation" do
setup do
@model = build_model_class(:example, :attr => :string) do
validates_length_of :attr, :maximum => 4, :too_long => 'long'
end.new
end

should "accept ensuring the correct minimum length" do
assert_accepts ensure_length_of(:attr).
is_at_most(4).
with_long_message(/long/),
@model
end

end

context "an attribute without a length validation" do
setup do
@model = build_model_class(:example, :attr => :string).new
Expand Down

0 comments on commit d5c48ee

Please sign in to comment.