mongoid-rspec-multi-db 1.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +4 -0
- data/.rvmrc +1 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +117 -0
- data/Rakefile +17 -0
- data/lib/matchers/associations.rb +215 -0
- data/lib/matchers/collections.rb +9 -0
- data/lib/matchers/document.rb +111 -0
- data/lib/matchers/indexes.rb +51 -0
- data/lib/matchers/validations.rb +42 -0
- data/lib/matchers/validations/associated.rb +19 -0
- data/lib/matchers/validations/confirmation_of.rb +9 -0
- data/lib/matchers/validations/format_of.rb +71 -0
- data/lib/matchers/validations/inclusion_of.rb +42 -0
- data/lib/matchers/validations/length_of.rb +100 -0
- data/lib/matchers/validations/numericality_of.rb +74 -0
- data/lib/matchers/validations/presence_of.rb +9 -0
- data/lib/matchers/validations/uniqueness_of.rb +99 -0
- data/lib/mongoid-rspec.rb +24 -0
- data/lib/mongoid-rspec/version.rb +5 -0
- data/mongoid-rspec.gemspec +28 -0
- data/spec/models/article.rb +23 -0
- data/spec/models/comment.rb +6 -0
- data/spec/models/log.rb +4 -0
- data/spec/models/movie_article.rb +7 -0
- data/spec/models/permalink.rb +5 -0
- data/spec/models/profile.rb +18 -0
- data/spec/models/record.rb +5 -0
- data/spec/models/site.rb +10 -0
- data/spec/models/user.rb +24 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/unit/associations_spec.rb +47 -0
- data/spec/unit/collections_spec.rb +7 -0
- data/spec/unit/document_spec.rb +20 -0
- data/spec/unit/indexes_spec.rb +12 -0
- data/spec/unit/validations_spec.rb +32 -0
- metadata +134 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Matchers
|
3
|
+
class HaveIndexForMatcher # :nodoc:
|
4
|
+
def initialize(index_fields)
|
5
|
+
@index_fields = index_fields
|
6
|
+
end
|
7
|
+
|
8
|
+
def with_options(options = {})
|
9
|
+
@options = options
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def matches?(klass)
|
14
|
+
@klass = klass.is_a?(Class) ? klass : klass.class
|
15
|
+
@errors = []
|
16
|
+
|
17
|
+
if @klass.index_options[@index_fields].nil?
|
18
|
+
@errors.push "no index for #{@index_fields}"
|
19
|
+
else
|
20
|
+
if !@options.nil? && !@options.empty?
|
21
|
+
@options.each do |option, option_value|
|
22
|
+
if @klass.index_options[@index_fields].include?(option) && @klass.index_options[@index_fields][option] != option_value
|
23
|
+
@errors.push "index for #{@index_fields.inspect} with options of #{@klass.index_options[@index_fields].inspect}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
@errors.empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
def failure_message_for_should
|
33
|
+
"Expected #{@klass.inspect} to #{description}, got #{@errors.to_sentence}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def failure_message_for_should_not
|
37
|
+
"Expected #{@klass.inspect} to not #{description}, got #{@klass.inspect} to #{description}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def description
|
41
|
+
desc = "have an index for #{@index_fields.inspect}"
|
42
|
+
desc << " with options of #{@options.inspect}" if @options
|
43
|
+
desc
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def have_index_for(index_fields)
|
48
|
+
HaveIndexForMatcher.new(index_fields)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Matchers
|
3
|
+
module Validations
|
4
|
+
|
5
|
+
class HaveValidationMatcher
|
6
|
+
|
7
|
+
def initialize(field, validation_type)
|
8
|
+
@field = field.to_s
|
9
|
+
@type = validation_type.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def matches?(actual)
|
13
|
+
@klass = actual.is_a?(Class) ? actual : actual.class
|
14
|
+
|
15
|
+
@validator = @klass.validators_on(@field).detect{|v| v.kind.to_s == @type }
|
16
|
+
|
17
|
+
if @validator
|
18
|
+
@negative_result_message = "#{@type.inspect} validator on #{@field.inspect}"
|
19
|
+
@positive_result_message = "#{@type.inspect} validator on #{@field.inspect}"
|
20
|
+
else
|
21
|
+
@negative_result_message = "no #{@type.inspect} validator on #{@field.inspect}"
|
22
|
+
return false
|
23
|
+
end
|
24
|
+
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def failure_message_for_should
|
29
|
+
"Expected #{@klass.inspect} to #{description}; instead got #{@negative_result_message}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def failure_message_for_should_not
|
33
|
+
"Expected #{@klass.inspect} to not #{description}; instead got #{@positive_result_message}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def description
|
37
|
+
"validate #{@type} of #{@field.inspect}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Matchers
|
3
|
+
module Validations
|
4
|
+
class ValidateAssociatedMatcher < HaveValidationMatcher
|
5
|
+
def initialize(name)
|
6
|
+
super(name, :associated)
|
7
|
+
end
|
8
|
+
|
9
|
+
def description
|
10
|
+
"validate associated #{@field.inspect}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate_associated(association_name)
|
15
|
+
ValidateAssociatedMatcher.new(association_name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Matchers
|
3
|
+
module Validations
|
4
|
+
class ValidateFormatOfMatcher < HaveValidationMatcher
|
5
|
+
def initialize(field)
|
6
|
+
super(field, :format)
|
7
|
+
end
|
8
|
+
|
9
|
+
def with_format(format)
|
10
|
+
@format = format
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_allow(valid_value)
|
15
|
+
@valid_value = valid_value
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def not_to_allow(invalid_value)
|
20
|
+
@invalid_value = invalid_value
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def matches?(actual)
|
25
|
+
return false unless result = super(actual)
|
26
|
+
|
27
|
+
if @format
|
28
|
+
if @validator.options[:with] == @format
|
29
|
+
@positive_result_message = @positive_result_message << " with format #{@validator.options[:format].inspect}"
|
30
|
+
else
|
31
|
+
@negative_result_message = @negative_result_message << " with format #{@validator.options[:format].inspect}"
|
32
|
+
result = false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
if @valid_value
|
37
|
+
if @validator.options[:with] =~ @valid_value
|
38
|
+
@positive_result_message = @positive_result_message << " with #{@valid_value.inspect} as a valid value"
|
39
|
+
else
|
40
|
+
@negative_result_message = @negative_result_message << " with #{@valid_value.inspect} as an invalid value"
|
41
|
+
result = false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
if @invalid_value
|
46
|
+
if !(@invalid_value =~ @validator.options[:with])
|
47
|
+
@positive_result_message = @positive_result_message << " with #{@invalid_value.inspect} as an invalid value"
|
48
|
+
else
|
49
|
+
@negative_result_message = @negative_result_message << " with #{@invalid_value.inspect} as a valid value"
|
50
|
+
result = false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
result
|
55
|
+
end
|
56
|
+
|
57
|
+
def description
|
58
|
+
options_desc = []
|
59
|
+
options_desc << " with format #{@format.inspect}" if @format
|
60
|
+
options_desc << " allowing the value #{@valid_value.inspect}" if @valid_value
|
61
|
+
options_desc << " not allowing the value #{@invalid_value.inspect}" if @invalid_value
|
62
|
+
super << options_desc.to_sentence
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def validate_format_of(field)
|
67
|
+
ValidateFormatOfMatcher.new(field)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Matchers
|
3
|
+
module Validations
|
4
|
+
class ValidateInclusionOfMatcher < HaveValidationMatcher
|
5
|
+
def initialize(name)
|
6
|
+
super(name, :inclusion)
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_allow(*values)
|
10
|
+
@allowed_values = [values].flatten
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def matches?(actual)
|
15
|
+
return false unless result = super(actual)
|
16
|
+
|
17
|
+
if @allowed_values
|
18
|
+
not_allowed_values = @allowed_values - @validator.options[:in]
|
19
|
+
if not_allowed_values.empty?
|
20
|
+
@positive_result_message = @positive_result_message << " allowing all values mentioned"
|
21
|
+
else
|
22
|
+
@negative_result_message = @negative_result_message << " not allowing the following the ff. values: #{not_allowed_values.inspect}"
|
23
|
+
result = false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
result
|
28
|
+
end
|
29
|
+
|
30
|
+
def description
|
31
|
+
options_desc = []
|
32
|
+
options_desc << " allowing the ff. values: #{@allowed_values}" if @allowed_values
|
33
|
+
super << options_desc.to_sentence
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate_inclusion_of(field)
|
38
|
+
ValidateInclusionOfMatcher.new(field)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Matchers
|
3
|
+
module Validations
|
4
|
+
class ValidateLengthOfMatcher < HaveValidationMatcher
|
5
|
+
def initialize(name)
|
6
|
+
super(name, :length)
|
7
|
+
end
|
8
|
+
|
9
|
+
def with_maximum(value)
|
10
|
+
@maximum = value
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def with_minimum(value)
|
15
|
+
@minimum = value
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def within(value)
|
20
|
+
@within = value
|
21
|
+
self
|
22
|
+
end
|
23
|
+
alias :in :within
|
24
|
+
|
25
|
+
def as_exactly(value)
|
26
|
+
@is = value
|
27
|
+
self
|
28
|
+
end
|
29
|
+
alias :is :as_exactly
|
30
|
+
|
31
|
+
def matches?(actual)
|
32
|
+
return false unless @result = super(actual)
|
33
|
+
|
34
|
+
check_maximum if @maximum
|
35
|
+
check_minimum if @minimum
|
36
|
+
check_range if @within
|
37
|
+
check_exact if @is
|
38
|
+
|
39
|
+
@result
|
40
|
+
end
|
41
|
+
|
42
|
+
def description
|
43
|
+
options_desc = []
|
44
|
+
options_desc << " with maximum #{@maximum}" if @maximum
|
45
|
+
options_desc << " with minimum #{@minimum}" if @minimum
|
46
|
+
options_desc << " within range #{@within}" if @within
|
47
|
+
options_desc << " as exactly #{@is}" if @is
|
48
|
+
super << options_desc.to_sentence
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def check_maximum
|
54
|
+
actual = @validator.options[:maximum]
|
55
|
+
if actual == @maximum
|
56
|
+
@positive_result_message << " with maximum of #{@maximum}"
|
57
|
+
else
|
58
|
+
@negative_result_message << " with maximum of #{actual}"
|
59
|
+
@result = false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def check_minimum
|
64
|
+
actual = @validator.options[:minimum]
|
65
|
+
if actual == @minimum
|
66
|
+
@positive_result_message << " with minimum of #{@minimum}"
|
67
|
+
else
|
68
|
+
@negative_result_message << " with minimum of #{actual}"
|
69
|
+
@result = false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def check_range
|
74
|
+
min, max = [@within.min, @within.max]
|
75
|
+
actual = @validator.options
|
76
|
+
if actual[:minimum] == min && actual[:maximum] == max
|
77
|
+
@positive_result_message << " with range #{@within.inspect}"
|
78
|
+
else
|
79
|
+
@negative_result_message << " with range #{(actual[:minimum]..actual[:maximum]).inspect}"
|
80
|
+
@result = false
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def check_exact
|
85
|
+
actual = @validator.options[:is]
|
86
|
+
if actual == @is
|
87
|
+
@positive_result_message << " is exactly #{@is}"
|
88
|
+
else
|
89
|
+
@negative_result_message << " is exactly #{actual}"
|
90
|
+
@result = false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def validate_length_of(field)
|
96
|
+
ValidateLengthOfMatcher.new(field)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Matchers
|
3
|
+
module Validations
|
4
|
+
class ValidateNumericalityOfMatcher < HaveValidationMatcher
|
5
|
+
@@allowed_options = [:equal_to, :greater_than, :greater_than_or_equal_to, :less_than, :less_than_or_equal_to,
|
6
|
+
:even, :odd, :only_integer, :allow_nil, :nil]
|
7
|
+
|
8
|
+
def initialize(field)
|
9
|
+
super(field, :numericality)
|
10
|
+
@options = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_allow(options)
|
14
|
+
options[:equal_to] = options if options.is_a?(Numeric)
|
15
|
+
options[:allow_nil] = options.delete(:nil) if options.has_key?(:nil)
|
16
|
+
raise ArgumentError, "validate_numericality_of#to_allow requires a Hash parameter containing any of the following keys: " <<
|
17
|
+
@@allowed_options.map(&:inspect).join(", ") if !options.is_a?(Hash) or options.empty? or (options.keys - @@allowed_options).any?
|
18
|
+
@options.merge!(options)
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def matches?(actual)
|
23
|
+
return false unless result = super(actual)
|
24
|
+
|
25
|
+
@@allowed_options.each do |comparator|
|
26
|
+
if @options.has_key?(comparator) and !([:even, :odd, :only_integer].include?(comparator) and !@validator.options.include?(comparator))
|
27
|
+
result &= (@validator.options[comparator] == @options[comparator])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
@positive_result_message <<= options_message(@validator.options)
|
31
|
+
@negative_result_message <<= options_message(@validator.options)
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
def description
|
36
|
+
super << options_message(@options)
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def options_message(options)
|
42
|
+
type_msg = []
|
43
|
+
comp_msg = []
|
44
|
+
options.each_pair do |key, value|
|
45
|
+
case key
|
46
|
+
when :allow_nil
|
47
|
+
when :only_integer
|
48
|
+
type_msg << "integer" if value
|
49
|
+
when :odd, :even
|
50
|
+
type_msg << "#{key.to_s}-numbered" if value
|
51
|
+
else
|
52
|
+
comp_msg << "#{key.to_s.gsub("_", " ")} #{value.inspect}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
allow_nil = (options[:allow_nil] ? "nil" : "non-nil") if options.has_key?(:allow_nil)
|
56
|
+
["", "allowing", allow_nil, type_msg.any? ? type_msg.to_sentence : nil, "values", comp_msg.any? ? comp_msg.to_sentence : nil].compact.join(" ")
|
57
|
+
end
|
58
|
+
|
59
|
+
def method_missing(m, *args, &block)
|
60
|
+
if @@allowed_options.include?(m.to_sym)
|
61
|
+
raise ArgumentError, "wrong number of arguments (#{args.length} for 1)" if args.length > 1
|
62
|
+
send :to_allow, m.to_sym => args.first
|
63
|
+
else
|
64
|
+
super
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def validate_numericality_of(field)
|
70
|
+
ValidateNumericalityOfMatcher.new(field)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Matchers
|
3
|
+
module Validations
|
4
|
+
class ValidateUniquenessOfMatcher < HaveValidationMatcher
|
5
|
+
def initialize(field)
|
6
|
+
super(field, :uniqueness)
|
7
|
+
end
|
8
|
+
|
9
|
+
def scoped_to(*scope)
|
10
|
+
@scope = [scope].flatten
|
11
|
+
self
|
12
|
+
end
|
13
|
+
alias_method :scoped_on, :scoped_to
|
14
|
+
|
15
|
+
def case_insensitive
|
16
|
+
@case_insensitive = true
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def allow_blank?(allow_blank)
|
21
|
+
@allow_blank = allow_blank
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def with_message(message)
|
26
|
+
@expected_message = message
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def matches?(actual)
|
31
|
+
return false unless @result = super(actual)
|
32
|
+
|
33
|
+
check_scope if @scope
|
34
|
+
check_allow_blank if @allow_blank
|
35
|
+
check_case_sensitivity if @case_insensitive
|
36
|
+
check_expected_message if @expected_message
|
37
|
+
|
38
|
+
@result
|
39
|
+
end
|
40
|
+
|
41
|
+
def description
|
42
|
+
options_desc = []
|
43
|
+
options_desc << " scoped to #{@scope.inspect}" if @scope
|
44
|
+
options_desc << " allowing blank values" if @allow_blank
|
45
|
+
options_desc << " allowing case insensitive values" if @case_insensitive
|
46
|
+
options_desc << " with message '#{@expected_message}'" if @case_insensitive
|
47
|
+
super << options_desc.to_sentence
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def check_allow_blank
|
53
|
+
if @validator.options[:allow_blank] == @allow_blank
|
54
|
+
@positive_result_message << " with blank values allowed"
|
55
|
+
else
|
56
|
+
@negative_result_message << " with no blank values allowed"
|
57
|
+
@result = false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def check_scope
|
62
|
+
message = "scope to #{@validator.options[:scope]}"
|
63
|
+
if [@validator.options[:scope]].flatten == @scope
|
64
|
+
@positive_result_message << message
|
65
|
+
else
|
66
|
+
@negative_result_message << message
|
67
|
+
@result = false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def check_case_sensitivity
|
72
|
+
if @validator.options[:case_sensitive] == false
|
73
|
+
@positive_result_message << " with case insensitive values"
|
74
|
+
else
|
75
|
+
@negative_result_message << " without case insensitive values"
|
76
|
+
@result = false
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def check_expected_message
|
81
|
+
actual_message = @validator.options[:message]
|
82
|
+
if actual_message.nil?
|
83
|
+
@negative_result_message << " with no custom message"
|
84
|
+
@result = false
|
85
|
+
elsif actual_message == @expected_message
|
86
|
+
@positive_result_message << " with custom message '#{@expected_message}'"
|
87
|
+
else
|
88
|
+
@negative_result_message << " got message '#{actual_message}'"
|
89
|
+
@result = false
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def validate_uniqueness_of(field)
|
95
|
+
ValidateUniquenessOfMatcher.new(field)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|