Add odd & even number matchers for numericality matcher

This commit is contained in:
Abd ar-Rahman 2013-03-19 09:50:39 +05:00 committed by Jason Draper
parent 5ad04a89e2
commit 8aa860dc2d
7 changed files with 210 additions and 5 deletions

View File

@ -1,5 +1,6 @@
# HEAD
* Add `:odd` and `:even` options to the `validate_numericality_of` matcher.
* Add `:touch` option to the association matcher.
* Ruby 2.0.0 is now officially supported.
* Fixes the issue where using %{attribute} or %{model} in I18n translations

View File

@ -5,6 +5,7 @@ require 'shoulda/matchers/active_model/exception_message_finder'
require 'shoulda/matchers/active_model/allow_value_matcher'
require 'shoulda/matchers/active_model/disallow_value_matcher'
require 'shoulda/matchers/active_model/only_integer_matcher'
require 'shoulda/matchers/active_model/odd_even_number_matcher'
require 'shoulda/matchers/active_model/ensure_length_of_matcher'
require 'shoulda/matchers/active_model/ensure_inclusion_of_matcher'
require 'shoulda/matchers/active_model/ensure_exclusion_of_matcher'

View File

@ -0,0 +1,43 @@
module Shoulda # :nodoc:
module Matchers
module ActiveModel # :nodoc:
class OddEvenNumberMatcher # :nodoc:
NON_EVEN_NUMBER_VALUE = 1
NON_ODD_NUMBER_VALUE = 2
def initialize(attribute, options = {})
@attribute = attribute
options[:odd] ||= true
options[:even] ||= false
if options[:odd] && !options[:even]
@disallow_value_matcher = DisallowValueMatcher.new(NON_ODD_NUMBER_VALUE).
for(@attribute).
with_message(:odd)
else
@disallow_value_matcher = DisallowValueMatcher.new(NON_EVEN_NUMBER_VALUE).
for(@attribute).
with_message(:even)
end
end
def matches?(subject)
@disallow_value_matcher.matches?(subject)
end
def with_message(message)
@disallow_value_matcher.with_message(message)
self
end
def allowed_types
'integer'
end
def failure_message_for_should
@disallow_value_matcher.failure_message_for_should
end
end
end
end
end

View File

@ -8,10 +8,14 @@ module Shoulda # :nodoc:
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
# translation for <tt>:not_a_number</tt>.
# * <tt>only_integer</tt> - allows only integer values
# * <tt>odd</tt> - Specifies the value must be an odd number.
# * <tt>even</tt> - Specifies the value must be an even number.
#
# Examples:
# it { should validate_numericality_of(:price) }
# it { should validate_numericality_of(:age).only_integer }
# it { should validate_numericality_of(:frequency).odd }
# it { should validate_numericality_of(:frequency).even }
#
def validate_numericality_of(attr)
ValidateNumericalityOfMatcher.new(attr)
@ -22,7 +26,6 @@ module Shoulda # :nodoc:
def initialize(attribute)
@attribute = attribute
@options = {}
@submatchers = []
add_disallow_value_matcher
@ -34,6 +37,18 @@ module Shoulda # :nodoc:
self
end
def odd
odd_number_matcher = OddEvenNumberMatcher.new(@attribute, :odd => true)
add_submatcher(odd_number_matcher)
self
end
def even
even_number_matcher = OddEvenNumberMatcher.new(@attribute, :even => true)
add_submatcher(even_number_matcher)
self
end
def with_message(message)
@submatchers.each { |matcher| matcher.with_message(message) }
self

View File

@ -0,0 +1,93 @@
require 'spec_helper'
describe Shoulda::Matchers::ActiveModel::OddEvenNumberMatcher do
context 'given an attribute that only allows odd number values' do
it 'matches' do
validating_odd_number.should new_odd_matcher
end
it 'returns itself when given a message' do
matcher = new_odd_matcher
matcher.with_message('some message').should == matcher
end
end
context 'given an attribute that only allows even number values' do
it 'matches' do
validating_even_number.should new_even_matcher
end
it 'returns itself when given a message' do
matcher = new_even_matcher
matcher.with_message('some message').should == matcher
end
end
context 'given an attribute that only allows odd number values with a custom validation message' do
it 'only accepts odd number values for that attribute with that message' do
validating_odd_number(:message => 'custom').should new_odd_matcher.with_message(/custom/)
end
it 'rejects odd number values for that attribute with another message' do
validating_odd_number(:message => 'custom').should_not new_odd_matcher.with_message(/wrong/)
end
end
context 'given an attribute that only allows even number values with a custom validation message' do
it 'only accepts even number values for that attribute with that message' do
validating_even_number(:message => 'custom').should new_even_matcher.with_message(/custom/)
end
it 'rejects even number values for that attribute with another message' do
validating_even_number(:message => 'custom').should_not new_even_matcher.with_message(/wrong/)
end
end
context 'when the model does not have an odd validation' do
it 'does not match' do
define_model(:example, :attr => :string).new.should_not new_odd_matcher
end
it 'fails with the ActiveRecord :odd message' do
matcher = new_odd_matcher
matcher.matches?(define_model(:example, :attr => :string).new)
matcher.failure_message_for_should.should include 'Expected errors to include "must be odd"'
end
end
context 'when the model does not have an even validation' do
it 'does not match' do
define_model(:example, :attr => :string).new.should_not new_even_matcher
end
it 'fails with the ActiveRecord :even message' do
matcher = new_even_matcher
matcher.matches?(define_model(:example, :attr => :string).new)
matcher.failure_message_for_should.should include 'Expected errors to include "must be even"'
end
end
def new_odd_matcher
described_class.new(:attr, :odd => true)
end
def new_even_matcher
described_class.new(:attr, :even => true)
end
def validating_odd_number(options = {})
define_model :example, :attr => :string do
validates_numericality_of :attr, { :odd => true }.merge(options)
end.new
end
def validating_even_number(options = {})
define_model :example, :attr => :string do
validates_numericality_of :attr, { :even => true }.merge(options)
end.new
end
end

View File

@ -3,7 +3,7 @@ require 'spec_helper'
describe Shoulda::Matchers::ActiveModel::OnlyIntegerMatcher do
context 'given an attribute that only allows integer values' do
it 'matches' do
only_integer.should new_matcher
validating_only_integer.should new_matcher
end
it 'allows integer types' do
@ -18,11 +18,11 @@ describe Shoulda::Matchers::ActiveModel::OnlyIntegerMatcher do
context 'given an attribute that only allows integer values with a custom validation message' do
it 'only accepts integer values for that attribute with that message' do
only_integer(:message => 'custom').should new_matcher.with_message(/custom/)
validating_only_integer(:message => 'custom').should new_matcher.with_message(/custom/)
end
it 'rejects integer values for that attribute with another message' do
only_integer(:message => 'custom').should_not new_matcher.with_message(/wrong/)
validating_only_integer(:message => 'custom').should_not new_matcher.with_message(/wrong/)
end
end
@ -44,7 +44,7 @@ describe Shoulda::Matchers::ActiveModel::OnlyIntegerMatcher do
described_class.new(:attr)
end
def only_integer(options = {})
def validating_only_integer(options = {})
define_model :example, :attr => :string do
validates_numericality_of :attr, { :only_integer => true }.merge(options)
end.new

View File

@ -29,6 +29,22 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher do
the_matcher.failure_message_for_should.should include 'Expected errors to include "must be an integer"'
end
it 'rejects with the ActiveRecord :odd message' do
the_matcher = matcher.odd
the_matcher.matches?(define_model(:example, :attr => :string).new)
the_matcher.failure_message_for_should.should include 'Expected errors to include "must be odd"'
end
it 'rejects with the ActiveRecord :even message' do
the_matcher = matcher.even
the_matcher.matches?(define_model(:example, :attr => :string).new)
the_matcher.failure_message_for_should.should include 'Expected errors to include "must be even"'
end
end
context 'with the only_integer option' do
@ -49,6 +65,42 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher do
end
end
context 'with the odd option' do
it 'allows odd number values for that attribute' do
validating_numericality(:odd => true).should matcher.odd
end
it 'rejects when the model does not enforce odd number values' do
validating_numericality.should_not matcher.odd
end
it 'rejects with the ActiveRecord :odd message' do
the_matcher = matcher.odd
the_matcher.matches?(validating_numericality)
the_matcher.failure_message_for_should.should include 'Expected errors to include "must be odd"'
end
end
context 'with the even option' do
it 'allows even number values for that attribute' do
validating_numericality(:even => true).should matcher.even
end
it 'rejects when the model does not enforce even number values' do
validating_numericality.should_not matcher.even
end
it 'rejects with the ActiveRecord :even message' do
the_matcher = matcher.even
the_matcher.matches?(validating_numericality)
the_matcher.failure_message_for_should.should include 'Expected errors to include "must be even"'
end
end
context 'with a custom validation message' do
it 'accepts when the messages match' do
validating_numericality(:message => 'custom').