mongoid-spec 4.0.1

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.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +373 -0
  4. data/Rakefile +17 -0
  5. data/lib/matchers/accept_nested_attributes.rb +67 -0
  6. data/lib/matchers/allow_mass_assignment.rb +102 -0
  7. data/lib/matchers/associations.rb +330 -0
  8. data/lib/matchers/be_dynamic_document.rb +26 -0
  9. data/lib/matchers/be_mongoid_document.rb +26 -0
  10. data/lib/matchers/be_stored_in.rb +50 -0
  11. data/lib/matchers/have_field.rb +90 -0
  12. data/lib/matchers/have_index_for.rb +63 -0
  13. data/lib/matchers/have_timestamps.rb +61 -0
  14. data/lib/matchers/validations.rb +81 -0
  15. data/lib/matchers/validations/acceptance_of.rb +9 -0
  16. data/lib/matchers/validations/associated.rb +19 -0
  17. data/lib/matchers/validations/confirmation_of.rb +22 -0
  18. data/lib/matchers/validations/custom_validation_of.rb +47 -0
  19. data/lib/matchers/validations/exclusion_of.rb +49 -0
  20. data/lib/matchers/validations/format_of.rb +71 -0
  21. data/lib/matchers/validations/inclusion_of.rb +49 -0
  22. data/lib/matchers/validations/length_of.rb +147 -0
  23. data/lib/matchers/validations/numericality_of.rb +90 -0
  24. data/lib/matchers/validations/presence_of.rb +9 -0
  25. data/lib/matchers/validations/uniqueness_of.rb +82 -0
  26. data/lib/matchers/validations/with_message.rb +27 -0
  27. data/lib/mongoid-rspec.rb +1 -0
  28. data/lib/mongoid/rspec.rb +40 -0
  29. data/lib/mongoid/rspec/version.rb +5 -0
  30. data/spec/models/article.rb +29 -0
  31. data/spec/models/comment.rb +6 -0
  32. data/spec/models/log.rb +9 -0
  33. data/spec/models/movie_article.rb +8 -0
  34. data/spec/models/permalink.rb +5 -0
  35. data/spec/models/person.rb +10 -0
  36. data/spec/models/profile.rb +16 -0
  37. data/spec/models/record.rb +5 -0
  38. data/spec/models/site.rb +9 -0
  39. data/spec/models/user.rb +37 -0
  40. data/spec/spec_helper.rb +35 -0
  41. data/spec/unit/accept_nested_attributes_spec.rb +12 -0
  42. data/spec/unit/associations_spec.rb +42 -0
  43. data/spec/unit/be_dynamic_document_spec.rb +22 -0
  44. data/spec/unit/be_mongoid_document_spec.rb +25 -0
  45. data/spec/unit/be_stored_in.rb +54 -0
  46. data/spec/unit/document_spec.rb +16 -0
  47. data/spec/unit/have_index_for_spec.rb +46 -0
  48. data/spec/unit/have_timestamps_spec.rb +71 -0
  49. data/spec/unit/validations_spec.rb +54 -0
  50. data/spec/validators/ssn_validator.rb +16 -0
  51. metadata +171 -0
@@ -0,0 +1,49 @@
1
+ module Mongoid
2
+ module Matchers
3
+ module Validations
4
+ class ValidateExclusionOfMatcher < HaveValidationMatcher
5
+ def initialize(name)
6
+ super(name, :exclusion)
7
+ end
8
+
9
+ def to_not_allow(*values)
10
+ @not_allowed_values = [values].flatten
11
+ self
12
+ end
13
+
14
+ def matches?(actual)
15
+ return false unless result = super(actual)
16
+
17
+ if @not_allowed_values
18
+ raw_validator_not_allowed_values = @validator.options[:in]
19
+
20
+ validator_not_allowed_values = case raw_validator_not_allowed_values
21
+ when Range then raw_validator_not_allowed_values.to_a
22
+ when Proc then raw_validator_not_allowed_values.call(actual)
23
+ else raw_validator_not_allowed_values end
24
+
25
+ allowed_values = @not_allowed_values - validator_not_allowed_values
26
+ if allowed_values.empty?
27
+ @positive_result_message = @positive_result_message << " not allowing all values mentioned"
28
+ else
29
+ @negative_result_message = @negative_result_message << " allowing the following the ff. values: #{allowed_values.inspect}"
30
+ result = false
31
+ end
32
+ end
33
+
34
+ result
35
+ end
36
+
37
+ def description
38
+ options_desc = []
39
+ options_desc << " not allowing the ff. values: #{@not_allowed_values}" if @not_allowed_values
40
+ super << options_desc.to_sentence
41
+ end
42
+ end
43
+
44
+ def validate_exclusion_of(field)
45
+ ValidateExclusionOfMatcher.new(field)
46
+ end
47
+ end
48
+ end
49
+ 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,49 @@
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.map { |v| v.respond_to?(:to_a) ? v.to_a : v }.flatten
11
+ self
12
+ end
13
+
14
+ def matches?(actual)
15
+ return false unless result = super(actual)
16
+
17
+ if @allowed_values
18
+ raw_validator_allowed_values = @validator.options[:in]
19
+
20
+ validator_allowed_values = case raw_validator_allowed_values
21
+ when Range then raw_validator_allowed_values.to_a
22
+ when Proc then raw_validator_allowed_values.call(actual)
23
+ else raw_validator_allowed_values end
24
+
25
+ not_allowed_values = @allowed_values - validator_allowed_values
26
+ if not_allowed_values.empty?
27
+ @positive_result_message = @positive_result_message << " allowing all values mentioned"
28
+ else
29
+ @negative_result_message = @negative_result_message << " not allowing these values: #{not_allowed_values.inspect}"
30
+ result = false
31
+ end
32
+ end
33
+
34
+ result
35
+ end
36
+
37
+ def description
38
+ options_desc = []
39
+ options_desc << " allowing these values: #{@allowed_values}" if @allowed_values
40
+ super << options_desc.to_sentence
41
+ end
42
+ end
43
+
44
+ def validate_inclusion_of(field)
45
+ ValidateInclusionOfMatcher.new(field)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,147 @@
1
+ module Mongoid
2
+ module Matchers
3
+ module Validations
4
+ class ValidateLengthOfMatcher < HaveValidationMatcher
5
+ include WithMessage
6
+
7
+ def initialize(name)
8
+ super(name, :length)
9
+ end
10
+
11
+ def with_maximum(value)
12
+ @maximum = value
13
+ self
14
+ end
15
+ alias :less_than :with_maximum
16
+
17
+ def with_minimum(value)
18
+ @minimum = value
19
+ self
20
+ end
21
+ alias :greater_than :with_minimum
22
+
23
+ def within(value)
24
+ @within = value
25
+ self
26
+ end
27
+ alias :in :within
28
+
29
+ def as_exactly(value)
30
+ @is = value
31
+ self
32
+ end
33
+ alias :is :as_exactly
34
+
35
+ def with_message(message)
36
+ @expected_message = message
37
+ self
38
+ end
39
+
40
+ def matches?(actual)
41
+ return false unless @result = super(actual)
42
+
43
+ check_maximum if @maximum
44
+ check_minimum if @minimum
45
+ check_range if @within
46
+ check_exact if @is
47
+ check_expected_message if @expected_message
48
+
49
+ @result
50
+ end
51
+
52
+ def description
53
+ options_desc = []
54
+ options_desc << "with minimum of #{@minimum}" if @minimum
55
+ options_desc << "with maximum of #{@maximum}" if @maximum
56
+ options_desc << "within the range of #{@within}" if @within
57
+ options_desc << "as exactly #{@is}" if @is
58
+ options_desc << "with message '#{@expected_message}'" if @expected_message
59
+ super << " #{options_desc.to_sentence}"
60
+ end
61
+
62
+ private
63
+
64
+ def check_maximum
65
+ if actual_max.nil?
66
+ @negative_result_message << " with no maximum"
67
+ @result = false
68
+ elsif actual_max == @maximum
69
+ @positive_result_message << " with maximum of #{@maximum}"
70
+ else
71
+ @negative_result_message << " with maximum of #{actual_max}"
72
+ @result = false
73
+ end
74
+ end
75
+
76
+ def check_minimum
77
+ if actual_min.nil?
78
+ @negative_result_message << " with no minimum"
79
+ @result = false
80
+ elsif actual_min == @minimum
81
+ @positive_result_message << " with minimum of #{@minimum}"
82
+ else
83
+ @negative_result_message << " with minimum of #{actual_min}"
84
+ @result = false
85
+ end
86
+ end
87
+
88
+ def check_range
89
+ min, max = [@within.min, @within.max]
90
+ if !actual_min.nil? and actual_max.nil?
91
+ @negative_result_message << " with no minimum but with maximum of #{actual_max}"
92
+ @result = false
93
+ elsif actual_min.nil? and !actual_max.nil?
94
+ @negative_result_message << " with minimum_of #{actual_min} but no maximum"
95
+ @result = false
96
+ elsif actual_min.nil? and actual_max.nil?
97
+ @negative_result_message << " with no minimum and maximum"
98
+ @result = false
99
+ elsif actual_min == min && actual_max == max
100
+ @positive_result_message << " within the range of #{@within.inspect}"
101
+ else
102
+ @negative_result_message << " within the range of #{(actual_min..actual_max).inspect}"
103
+ @result = false
104
+ end
105
+ end
106
+
107
+ def check_exact
108
+ if actual_is == @is
109
+ @positive_result_message << " as exactly #{@is}"
110
+ else
111
+ @negative_result_message << " as exactly #{actual_is}"
112
+ @result = false
113
+ end
114
+ end
115
+
116
+ def check_expected_message
117
+ actual_message = @validator.options[:message]
118
+ if actual_message.nil?
119
+ @negative_result_message << " with no custom message"
120
+ @result = false
121
+ elsif actual_message == @expected_message
122
+ @positive_result_message << " with custom message '#{@expected_message}'"
123
+ else
124
+ @negative_result_message << " got message '#{actual_message}'"
125
+ @result = false
126
+ end
127
+ end
128
+
129
+ def actual_is
130
+ actual_is = @validator.options[:is]
131
+ end
132
+
133
+ def actual_min
134
+ @validator.options[:minimum] || ((@validator.options[:in] || @validator.options[:within]).try(&:min))
135
+ end
136
+
137
+ def actual_max
138
+ @validator.options[:maximum] || ((@validator.options[:in] || @validator.options[:within]).try(&:max))
139
+ end
140
+ end
141
+
142
+ def validate_length_of(field)
143
+ ValidateLengthOfMatcher.new(field)
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,90 @@
1
+ module Mongoid
2
+ module Matchers
3
+ module Validations
4
+ class ValidateNumericalityOfMatcher < HaveValidationMatcher
5
+ ALLOWED_OPTIONS =
6
+ %i(
7
+ allow_nil
8
+ equal_to
9
+ even
10
+ greater_than
11
+ greater_than_or_equal_to
12
+ less_than
13
+ less_than_or_equal_to
14
+ nil
15
+ odd
16
+ only_integer
17
+ )
18
+
19
+ def initialize(field)
20
+ super(field, :numericality)
21
+ @options = {}
22
+ end
23
+
24
+ def to_allow(options)
25
+ options[:equal_to] = options if options.is_a?(Numeric)
26
+ options[:allow_nil] = options.delete(:nil) if options.has_key?(:nil)
27
+
28
+ if !options.is_a?(Hash) || options.empty? || (options.keys - ALLOWED_OPTIONS).any?
29
+ message =
30
+ "validate_numericality_of#to_allow requires a Hash parameter containing" \
31
+ "any of the following keys: #{ALLOWED_OPTIONS.map(&:inspect).join(", ")}"
32
+ raise ArgumentError, message
33
+ end
34
+
35
+ @options.merge!(options)
36
+ self
37
+ end
38
+
39
+ def matches?(actual)
40
+ return false unless result = super(actual)
41
+
42
+ @options.each do |comparator, expected_value|
43
+ result &= (@validator.options[comparator] == expected_value)
44
+ end
45
+
46
+ @positive_result_message <<= options_message(@validator.options)
47
+ @negative_result_message <<= options_message(@validator.options)
48
+ result
49
+ end
50
+
51
+ def description
52
+ super << options_message(@options)
53
+ end
54
+
55
+ protected
56
+
57
+ def options_message(options)
58
+ type_msg = []
59
+ comp_msg = []
60
+ options.each_pair do |key, value|
61
+ case key
62
+ when :allow_nil
63
+ when :only_integer
64
+ type_msg << "integer" if value
65
+ when :odd, :even
66
+ type_msg << "#{key.to_s}-numbered" if value
67
+ else
68
+ comp_msg << "#{key.to_s.gsub("_", " ")} #{value.inspect}"
69
+ end
70
+ end
71
+ allow_nil = (options[:allow_nil] ? "nil" : "non-nil") if options.has_key?(:allow_nil)
72
+ ["", "allowing", allow_nil, type_msg.any? ? type_msg.to_sentence : nil, "values", comp_msg.any? ? comp_msg.to_sentence : nil].compact.join(" ")
73
+ end
74
+
75
+ def method_missing(m, *args, &block)
76
+ if ALLOWED_OPTIONS.include?(m.to_sym)
77
+ raise ArgumentError, "wrong number of arguments (#{args.length} for 1)" if args.length > 1
78
+ send :to_allow, m.to_sym => args.first
79
+ else
80
+ super
81
+ end
82
+ end
83
+ end
84
+
85
+ def validate_numericality_of(field)
86
+ ValidateNumericalityOfMatcher.new(field)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,9 @@
1
+ module Mongoid
2
+ module Matchers
3
+ module Validations
4
+ def validate_presence_of(field)
5
+ HaveValidationMatcher.new(field, :presence)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,82 @@
1
+ module Mongoid
2
+ module Matchers
3
+ module Validations
4
+ class ValidateUniquenessOfMatcher < HaveValidationMatcher
5
+ include WithMessage
6
+ def initialize(field)
7
+ super(field, :uniqueness)
8
+ end
9
+
10
+ def scoped_to(*scope)
11
+ @scope = [scope].flatten.map(&:to_sym)
12
+ self
13
+ end
14
+ alias_method :scoped_on, :scoped_to
15
+
16
+ def case_insensitive
17
+ @case_insensitive = true
18
+ self
19
+ end
20
+
21
+ def allow_blank?(allow_blank)
22
+ @allow_blank = allow_blank
23
+ self
24
+ end
25
+
26
+ def matches?(actual)
27
+ return false unless @result = super(actual)
28
+
29
+ check_scope if @scope
30
+ check_allow_blank if @allow_blank
31
+ check_case_sensitivity if @case_insensitive
32
+ check_expected_message if @expected_message
33
+
34
+ @result
35
+ end
36
+
37
+ def description
38
+ options_desc = []
39
+ options_desc << " scoped to #{@scope.inspect}" if @scope
40
+ options_desc << " allowing blank values" if @allow_blank
41
+ options_desc << " allowing case insensitive values" if @case_insensitive
42
+ options_desc << " with message '#{@expected_message}'" if @expected_message
43
+ super << options_desc.to_sentence
44
+ end
45
+
46
+ private
47
+
48
+ def check_allow_blank
49
+ if @validator.options[:allow_blank] == @allow_blank
50
+ @positive_result_message << " with blank values allowed"
51
+ else
52
+ @negative_result_message << " with no blank values allowed"
53
+ @result = false
54
+ end
55
+ end
56
+
57
+ def check_scope
58
+ message = " scope to #{@validator.options[:scope]}"
59
+ if [@validator.options[:scope]].flatten.map(&:to_sym) == @scope
60
+ @positive_result_message << message
61
+ else
62
+ @negative_result_message << message
63
+ @result = false
64
+ end
65
+ end
66
+
67
+ def check_case_sensitivity
68
+ if @validator.options[:case_sensitive] == false
69
+ @positive_result_message << " with case insensitive values"
70
+ else
71
+ @negative_result_message << " without case insensitive values"
72
+ @result = false
73
+ end
74
+ end
75
+ end
76
+
77
+ def validate_uniqueness_of(field)
78
+ ValidateUniquenessOfMatcher.new(field)
79
+ end
80
+ end
81
+ end
82
+ end