mirror of
https://github.com/thoughtbot/shoulda-matchers.git
synced 2022-11-09 12:01:38 -05:00
Use submatchers instead of inheritance for ValidatesNumericalityMatcher.
This commit is contained in:
parent
f5b5617663
commit
6ba8c9f1a1
7 changed files with 256 additions and 36 deletions
|
@ -3,6 +3,8 @@ require 'shoulda/matchers/active_model/validation_matcher'
|
|||
require 'shoulda/matchers/active_model/validation_message_finder'
|
||||
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/ensure_length_of_matcher'
|
||||
require 'shoulda/matchers/active_model/ensure_inclusion_of_matcher'
|
||||
require 'shoulda/matchers/active_model/ensure_exclusion_of_matcher'
|
||||
|
|
33
lib/shoulda/matchers/active_model/disallow_value_matcher.rb
Normal file
33
lib/shoulda/matchers/active_model/disallow_value_matcher.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
module Shoulda # :nodoc:
|
||||
module Matchers
|
||||
module ActiveModel # :nodoc:
|
||||
class DisallowValueMatcher # :nodoc:
|
||||
def initialize(value)
|
||||
@allow_matcher = Shoulda::Matchers::ActiveModel::AllowValueMatcher.new(value)
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
!@allow_matcher.matches?(subject)
|
||||
end
|
||||
|
||||
def for(attribute)
|
||||
@allow_matcher.for(attribute)
|
||||
self
|
||||
end
|
||||
|
||||
def with_message(message)
|
||||
@allow_matcher.with_message(message)
|
||||
self
|
||||
end
|
||||
|
||||
def failure_message
|
||||
@allow_matcher.negative_failure_message
|
||||
end
|
||||
|
||||
def allowed_types
|
||||
""
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
24
lib/shoulda/matchers/active_model/only_integer_matcher.rb
Normal file
24
lib/shoulda/matchers/active_model/only_integer_matcher.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
module Shoulda # :nodoc:
|
||||
module Matchers
|
||||
module ActiveModel # :nodoc:
|
||||
class OnlyIntegerMatcher # :nodoc:
|
||||
def initialize(attribute)
|
||||
@attribute = attribute
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
matcher = AllowValueMatcher.new(0.1).for(@attribute)
|
||||
!matcher.matches?(subject)
|
||||
end
|
||||
|
||||
def with_message(message)
|
||||
self
|
||||
end
|
||||
|
||||
def allowed_types
|
||||
"integer"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -17,55 +17,68 @@ module Shoulda # :nodoc:
|
|||
ValidateNumericalityOfMatcher.new(attr)
|
||||
end
|
||||
|
||||
class ValidateNumericalityOfMatcher < ValidationMatcher # :nodoc:
|
||||
class ValidateNumericalityOfMatcher
|
||||
def initialize(attribute)
|
||||
super(attribute)
|
||||
@attribute = attribute
|
||||
@options = {}
|
||||
@submatchers = []
|
||||
|
||||
add_disallow_value_matcher
|
||||
end
|
||||
|
||||
def only_integer
|
||||
@options[:only_integer] = true
|
||||
only_integer_matcher = OnlyIntegerMatcher.new(@attribute)
|
||||
add_submatcher(only_integer_matcher)
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def with_message(message)
|
||||
if message
|
||||
@expected_message = message
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
super(subject)
|
||||
disallows_non_integers? && disallows_text?
|
||||
@subject = subject
|
||||
set_expected_message_on_submatchers
|
||||
submatchers_match?
|
||||
end
|
||||
|
||||
def description
|
||||
"only allow #{allowed_type} values for #{@attribute}"
|
||||
"only allow #{allowed_types} values for #{@attribute}"
|
||||
end
|
||||
|
||||
def failure_message
|
||||
@disallow_value_matcher.failure_message
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def allowed_type
|
||||
if @options[:only_integer]
|
||||
"integer"
|
||||
else
|
||||
"numeric"
|
||||
end
|
||||
def add_disallow_value_matcher
|
||||
@disallow_value_matcher = DisallowValueMatcher.new('abcd').for(@attribute)
|
||||
add_submatcher(@disallow_value_matcher)
|
||||
end
|
||||
|
||||
def disallows_non_integers?
|
||||
if @options[:only_integer]
|
||||
message = @expected_message || :not_an_integer
|
||||
disallows_value_of(0.1, message)
|
||||
else
|
||||
true
|
||||
end
|
||||
def add_submatcher(submatcher)
|
||||
@submatchers << submatcher
|
||||
end
|
||||
|
||||
def disallows_text?
|
||||
def set_expected_message_on_submatchers
|
||||
message = @expected_message || :not_a_number
|
||||
disallows_value_of('abcd', message)
|
||||
@submatchers.each { |matcher| matcher.with_message(message) }
|
||||
end
|
||||
|
||||
def submatchers_match?
|
||||
@submatchers.all? { |matcher| matcher.matches?(@subject) }
|
||||
end
|
||||
|
||||
def allowed_types
|
||||
allowed = ["numeric"] + submatcher_allowed_types
|
||||
allowed.join(", ")
|
||||
end
|
||||
|
||||
def submatcher_allowed_types
|
||||
@submatchers.map(&:allowed_types).reject { |type| type.empty? }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
65
spec/shoulda/active_model/disallow_value_matcher_spec.rb
Normal file
65
spec/shoulda/active_model/disallow_value_matcher_spec.rb
Normal file
|
@ -0,0 +1,65 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Shoulda::Matchers::ActiveModel::DisallowValueMatcher do
|
||||
it "does not allow any types" do
|
||||
matcher = Shoulda::Matchers::ActiveModel::DisallowValueMatcher.new("abcde")
|
||||
matcher.allowed_types.should == ""
|
||||
end
|
||||
|
||||
context "an attribute with a format validation" do
|
||||
before do
|
||||
define_model :example, :attr => :string do
|
||||
validates_format_of :attr, :with => /abc/
|
||||
end
|
||||
@model = Example.new
|
||||
end
|
||||
|
||||
it "does not match if the value is allowed" do
|
||||
matcher = new_matcher("abcde")
|
||||
matcher.for(:attr)
|
||||
matcher.matches?(@model).should be_false
|
||||
end
|
||||
|
||||
it "matches if the value is not allowed" do
|
||||
matcher = new_matcher("xyz")
|
||||
matcher.for(:attr)
|
||||
matcher.matches?(@model).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "an attribute with a format validation and a custom message" do
|
||||
before do
|
||||
define_model :example, :attr => :string do
|
||||
validates_format_of :attr, :with => /abc/, :message => 'good message'
|
||||
end
|
||||
@model = Example.new
|
||||
end
|
||||
|
||||
it "does not match if the value and message are both correct" do
|
||||
matcher = new_matcher("abcde")
|
||||
matcher.for(:attr).with_message('good message')
|
||||
matcher.matches?(@model).should be_false
|
||||
end
|
||||
|
||||
it "delegates its failure message to its allow matcher's negative failure message" do
|
||||
allow_matcher = stub_everything(negative_failure_message: "allow matcher failure")
|
||||
Shoulda::Matchers::ActiveModel::AllowValueMatcher.stubs(:new).returns(allow_matcher)
|
||||
|
||||
matcher = new_matcher("abcde")
|
||||
matcher.for(:attr).with_message('good message')
|
||||
matcher.matches?(@model)
|
||||
|
||||
matcher.failure_message.should == "allow matcher failure"
|
||||
end
|
||||
|
||||
it "matches if the message is correct but the value is not" do
|
||||
matcher = new_matcher("xyz")
|
||||
matcher.for(:attr).with_message('good message')
|
||||
matcher.matches?(@model).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
def new_matcher(value)
|
||||
matcher = Shoulda::Matchers::ActiveModel::DisallowValueMatcher.new(value)
|
||||
end
|
||||
end
|
42
spec/shoulda/active_model/only_integer_matcher_spec.rb
Normal file
42
spec/shoulda/active_model/only_integer_matcher_spec.rb
Normal file
|
@ -0,0 +1,42 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Shoulda::Matchers::ActiveModel::OnlyIntegerMatcher do
|
||||
context "given an attribute that only allows integer values" do
|
||||
before do
|
||||
define_model :example, :attr => :string do
|
||||
validates_numericality_of :attr, { :only_integer => true }
|
||||
end
|
||||
@model = Example.new
|
||||
end
|
||||
|
||||
it "matches" do
|
||||
matcher = new_matcher(:attr)
|
||||
matcher.matches?(@model).should be_true
|
||||
end
|
||||
|
||||
it "allows integer types" do
|
||||
matcher = new_matcher(:attr)
|
||||
matcher.allowed_types.should == "integer"
|
||||
end
|
||||
|
||||
it "returns itself when given a message" do
|
||||
matcher = new_matcher(:attr)
|
||||
matcher.with_message("some message").should == matcher
|
||||
end
|
||||
end
|
||||
|
||||
context "given an attribute that allows values other than integers" do
|
||||
before do
|
||||
@model = define_model(:example, :attr => :string).new
|
||||
end
|
||||
|
||||
it "does not match" do
|
||||
matcher = new_matcher(:attr)
|
||||
matcher.matches?(@model).should be_false
|
||||
end
|
||||
end
|
||||
|
||||
def new_matcher(attribute)
|
||||
matcher = Shoulda::Matchers::ActiveModel::OnlyIntegerMatcher.new(attribute)
|
||||
end
|
||||
end
|
|
@ -1,8 +1,12 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher do
|
||||
it "should state in its description that it allows only numeric values" do
|
||||
matcher = Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher.new(:attr)
|
||||
matcher.description.should == "only allow numeric values for attr"
|
||||
end
|
||||
|
||||
context "a numeric attribute" do
|
||||
context "given a numeric attribute" do
|
||||
before do
|
||||
define_model :example, :attr => :string do
|
||||
validates_numericality_of :attr
|
||||
|
@ -11,15 +15,24 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher do
|
|||
end
|
||||
|
||||
it "should only allow numeric values for that attribute" do
|
||||
@model.should validate_numericality_of(:attr)
|
||||
matcher = new_matcher(:attr)
|
||||
matcher.matches?(@model).should be_true
|
||||
end
|
||||
|
||||
it "should not override the default message with a blank" do
|
||||
@model.should validate_numericality_of(:attr).with_message(nil)
|
||||
matcher = new_matcher(:attr)
|
||||
matcher.with_message(nil)
|
||||
matcher.matches?(@model).should be_true
|
||||
end
|
||||
|
||||
it "should not enforce integer values for that attribute" do
|
||||
matcher = new_matcher(:attr)
|
||||
matcher.only_integer
|
||||
matcher.matches?(@model).should be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "a numeric attribute which must be integer" do
|
||||
context "given a numeric attribute which must be integer" do
|
||||
before do
|
||||
define_model :example, :attr => :string do
|
||||
validates_numericality_of :attr, { :only_integer => true }
|
||||
|
@ -27,12 +40,26 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher do
|
|||
@model = Example.new
|
||||
end
|
||||
|
||||
it "should only allow integer values for that attribute" do
|
||||
@model.should validate_numericality_of(:attr).only_integer
|
||||
it "allows integer values for that attribute" do
|
||||
matcher = new_matcher(:attr)
|
||||
matcher.only_integer
|
||||
matcher.matches?(@model).should be_true
|
||||
end
|
||||
|
||||
it "does not allow non-integer values for that attribute" do
|
||||
matcher = new_matcher(:attr)
|
||||
matcher.only_integer
|
||||
matcher.matches?(@model).should be_true
|
||||
end
|
||||
|
||||
it "should state in its description that it allows only integer values" do
|
||||
matcher = new_matcher(:attr)
|
||||
matcher.only_integer
|
||||
matcher.description.should == "only allow numeric, integer values for attr"
|
||||
end
|
||||
end
|
||||
|
||||
context "a numeric attribute with a custom validation message" do
|
||||
context "given a numeric attribute with a custom validation message" do
|
||||
before do
|
||||
define_model :example, :attr => :string do
|
||||
validates_numericality_of :attr, :message => 'custom'
|
||||
|
@ -41,22 +68,36 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher do
|
|||
end
|
||||
|
||||
it "should only allow numeric values for that attribute with that message" do
|
||||
@model.should validate_numericality_of(:attr).with_message(/custom/)
|
||||
matcher = new_matcher(:attr)
|
||||
matcher.with_message(/custom/)
|
||||
matcher.matches?(@model).should be_true
|
||||
end
|
||||
|
||||
it "should not allow numeric values for that attribute with another message" do
|
||||
@model.should_not validate_numericality_of(:attr)
|
||||
matcher = new_matcher(:attr)
|
||||
matcher.with_message(/wrong/)
|
||||
matcher.matches?(@model).should be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "a non-numeric attribute" do
|
||||
context "given a non-numeric attribute" do
|
||||
before do
|
||||
@model = define_model(:example, :attr => :string).new
|
||||
end
|
||||
|
||||
it "should not only allow numeric values for that attribute" do
|
||||
@model.should_not validate_numericality_of(:attr)
|
||||
matcher = new_matcher(:attr)
|
||||
matcher.matches?(@model).should be_false
|
||||
end
|
||||
|
||||
it "should fail with the ActiveRecord :not_a_number message" do
|
||||
matcher = new_matcher(:attr)
|
||||
matcher.matches?(@model)
|
||||
matcher.failure_message.should include 'Expected errors to include "is not a number"'
|
||||
end
|
||||
end
|
||||
|
||||
def new_matcher(attr)
|
||||
Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher.new(attr)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue