mongoid-spec 4.0.1

Sign up to get free protection for your applications and to get access to all the features.
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