forked from thefrontiergroup/remarkable_mongo
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
347 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
lib/remarkable_mongomapper/matchers/validate_length_of_matcher.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
module Remarkable | ||
module MongoMapper | ||
module Matchers | ||
class ValidateLengthOfMatcher < Remarkable::MongoMapper::Base #:nodoc: | ||
arguments :collection => :attributes, :as => :attribute | ||
|
||
optional :within, :minimum, :maximum, :is | ||
optional :allow_nil, :allow_blank, :default => true | ||
optional :message | ||
|
||
default_options :message => "is invalid" | ||
|
||
collection_assertions :less_than_min_length?, :exactly_min_length?, | ||
:more_than_max_length?, :exactly_max_length?, | ||
:allow_nil?, :allow_blank? | ||
|
||
before_assert do | ||
if @options[:is] | ||
@min_value, @max_value = @options[:is], @options[:is] | ||
elsif @options[:within] | ||
@min_value, @max_value = @options[:within].first, @options[:within].last | ||
elsif @options[:maximum] | ||
@min_value, @max_value = nil, @options[:maximum] | ||
elsif @options[:minimum] | ||
@min_value, @max_value = @options[:minimum], nil | ||
end | ||
end | ||
|
||
protected | ||
def allow_nil? | ||
super(default_message_for(:too_short)) | ||
end | ||
|
||
def allow_blank? | ||
super(default_message_for(:too_short)) | ||
end | ||
|
||
def less_than_min_length? | ||
@min_value.nil? || @min_value <= 1 || bad?(@min_value - 1, default_message_for(:too_short)) | ||
end | ||
|
||
def exactly_min_length? | ||
@min_value.nil? || @min_value <= 0 || good?(@min_value, default_message_for(:too_short)) | ||
end | ||
|
||
def more_than_max_length? | ||
@max_value.nil? || bad?(@max_value + 1, default_message_for(:too_long)) | ||
end | ||
|
||
def exactly_max_length? | ||
@max_value.nil? || @min_value == @max_value || good?(@max_value, default_message_for(:too_long)) | ||
end | ||
|
||
def interpolation_options | ||
{ :minimum => @min_value, :maximum => @max_value } | ||
end | ||
|
||
# Returns the default message for the validation type. | ||
# If user supplied :message, it will return it. Otherwise it will return | ||
# wrong_length on :is validation and :too_short or :too_long in the other | ||
# types. | ||
# | ||
def default_message_for(validation_type) | ||
return :message if @options[:message] | ||
end | ||
end | ||
|
||
# Validates the length of the given attributes. You have also to supply | ||
# one of the following options: minimum, maximum, is or within. | ||
# | ||
# Note: this method is also aliased as <tt>validate_size_of</tt>. | ||
# | ||
# == Options | ||
# | ||
# * <tt>:minimum</tt> - The minimum size of the attribute. | ||
# * <tt>:maximum</tt> - The maximum size of the attribute. | ||
# * <tt>:is</tt> - The exact size of the attribute. | ||
# * <tt>:within</tt> - A range specifying the minimum and maximum size of the attribute. | ||
# * <tt>:allow_nil</tt> - when supplied, validates if it allows nil or not. | ||
# * <tt>:allow_blank</tt> - when supplied, validates if it allows blank or not. | ||
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>. | ||
# Regexp, string or symbol. Default = "is invalid"</tt> | ||
# | ||
# == Examples | ||
# | ||
# it { should validate_length_of(:password).within(6..20) } | ||
# it { should validate_length_of(:password).maximum(20) } | ||
# it { should validate_length_of(:password).minimum(6) } | ||
# it { should validate_length_of(:age).is(18) } | ||
# | ||
# should_validate_length_of :password, :within => 6..20 | ||
# should_validate_length_of :password, :maximum => 20 | ||
# should_validate_length_of :password, :minimum => 6 | ||
# should_validate_length_of :age, :is => 18 | ||
# | ||
# should_validate_length_of :password do |m| | ||
# m.minimum 6 | ||
# m.maximum 20 | ||
# end | ||
# | ||
def validate_length_of(*attributes, &block) | ||
ValidateLengthOfMatcher.new(*attributes, &block).spec(self) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') | ||
|
||
describe 'validate_length_of' do | ||
include ModelBuilder | ||
|
||
# Defines a model, create a validation and returns a raw matcher | ||
def define_and_validate(options={}) | ||
options = options.merge(:within => 3..5) if options.slice(:within, :maximum, :minimum, :is).empty? | ||
|
||
@model = define_model :product do | ||
include MongoMapper::Document | ||
|
||
key :size, String | ||
key :category, String | ||
|
||
validates_length_of :size, options | ||
end | ||
|
||
validate_length_of(:size) | ||
end | ||
|
||
describe 'messages' do | ||
before(:each){ @matcher = define_and_validate } | ||
|
||
it 'should contain a description' do | ||
@matcher.within(3..5) | ||
@matcher.description.should == 'ensure length of size is within 3..5 characters' | ||
|
||
@matcher.within(nil).is(3) | ||
@matcher.description.should == 'ensure length of size is equal to 3 characters' | ||
|
||
@matcher.is(nil).maximum(5) | ||
@matcher.description.should == 'ensure length of size is maximum 5 characters' | ||
|
||
@matcher.maximum(nil).minimum(3) | ||
@matcher.description.should == 'ensure length of size is minimum 3 characters' | ||
|
||
@matcher.allow_nil(false) | ||
@matcher.description.should == 'ensure length of size is minimum 3 characters and not allowing nil values' | ||
|
||
@matcher.allow_blank | ||
@matcher.description.should == 'ensure length of size is minimum 3 characters, not allowing nil values, and allowing blank values' | ||
end | ||
|
||
it 'should set less_than_min_length? message' do | ||
@matcher.within(4..5).matches?(@model) | ||
@matcher.failure_message.should == 'Expected Product to be invalid when size length is less than 4 characters' | ||
end | ||
|
||
it 'should set exactly_min_length? message' do | ||
@matcher.should_receive(:less_than_min_length?).and_return(true) | ||
@matcher.within(2..5).matches?(@model) | ||
@matcher.failure_message.should == 'Expected Product to be valid when size length is 2 characters' | ||
end | ||
|
||
it 'should set more_than_max_length? message' do | ||
@matcher.within(3..4).matches?(@model) | ||
@matcher.failure_message.should == 'Expected Product to be invalid when size length is more than 4 characters' | ||
end | ||
|
||
it 'should set exactly_max_length? message' do | ||
@matcher.should_receive(:more_than_max_length?).and_return(true) | ||
@matcher.within(3..6).matches?(@model) | ||
@matcher.failure_message.should == 'Expected Product to be valid when size length is 6 characters' | ||
end | ||
|
||
it 'should set allow_blank? message' do | ||
@matcher.within(3..5).allow_blank.matches?(@model) | ||
@matcher.failure_message.should == 'Expected Product to allow blank values for size' | ||
end | ||
|
||
it 'should set allow_nil? message' do | ||
@matcher.within(3..5).allow_nil.matches?(@model) | ||
@matcher.failure_message.should == 'Expected Product to allow nil values for size' | ||
end | ||
end | ||
|
||
describe 'matcher' do | ||
# Wrap specs without options. Usually a couple specs. | ||
describe 'without options' do | ||
before(:each){ define_and_validate } | ||
|
||
it { should validate_length_of(:size, :within => 3..5) } | ||
it { should_not validate_length_of(:category, :within => 3..5) } | ||
end | ||
|
||
describe "with message option" do | ||
|
||
# if RAILS_VERSION =~ /^2.3/ | ||
# it { should define_and_validate(:message => 'not valid').within(3..5).message('not valid') } | ||
# it { should_not define_and_validate(:message => 'not valid').within(3..5).message('valid') } | ||
# else | ||
# it { should define_and_validate(:too_short => 'not valid', :too_long => 'not valid').within(3..5).message('not valid') } | ||
# it { should_not define_and_validate(:too_short => 'not valid', :too_long => 'not valid').within(3..5).message('valid') } | ||
# end | ||
|
||
it { should define_and_validate(:is => 4, :message => 'not valid').is(4).message('not valid') } | ||
it { should_not define_and_validate(:is => 4, :message => 'not valid').is(4).message('valid') } | ||
end | ||
|
||
describe "with within option" do | ||
it { should define_and_validate(:within => 3..5).within(3..5) } | ||
it { should_not define_and_validate(:within => 3..5).within(2..5) } | ||
it { should_not define_and_validate(:within => 3..5).within(4..5) } | ||
it { should_not define_and_validate(:within => 3..5).within(3..4) } | ||
it { should_not define_and_validate(:within => 3..5).within(3..6) } | ||
end | ||
|
||
describe "with minimum option" do | ||
it { should define_and_validate(:minimum => 3).minimum(3) } | ||
it { should_not define_and_validate(:minimum => 3).minimum(2) } | ||
it { should_not define_and_validate(:minimum => 3).minimum(4) } | ||
end | ||
|
||
describe "with maximum option" do | ||
it { should define_and_validate(:maximum => 3).maximum(3) } | ||
it { should_not define_and_validate(:maximum => 3).maximum(2) } | ||
it { should_not define_and_validate(:maximum => 3).maximum(4) } | ||
end | ||
|
||
describe "with is option" do | ||
it { should define_and_validate(:is => 3).is(3) } | ||
it { should_not define_and_validate(:is => 3).is(2) } | ||
it { should_not define_and_validate(:is => 3).is(4) } | ||
end | ||
|
||
# Those are macros to test optionals which accept only boolean values | ||
create_optional_boolean_specs(:allow_nil, self) | ||
create_optional_boolean_specs(:allow_blank, self) | ||
end | ||
|
||
# In macros we include just a few tests to assure that everything works properly | ||
describe 'macros' do | ||
before(:each) { define_and_validate } | ||
|
||
should_validate_length_of :size, :within => 3..5 | ||
|
||
should_not_validate_length_of :size, :within => 2..5 | ||
should_not_validate_length_of :size, :within => 4..5 | ||
should_not_validate_length_of :size, :within => 3..4 | ||
should_not_validate_length_of :size, :within => 3..6 | ||
|
||
should_validate_length_of :size do |m| | ||
m.within = 3..5 | ||
end | ||
end | ||
end |