mongoid-rspec 2.1.0 → 4.1.0

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 (66) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE +1 -1
  3. data/README.md +222 -102
  4. data/Rakefile +8 -5
  5. data/lib/matchers/accept_nested_attributes.rb +22 -23
  6. data/lib/matchers/allow_mass_assignment.rb +12 -12
  7. data/lib/matchers/associations.rb +85 -49
  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 +55 -0
  11. data/lib/matchers/have_field.rb +90 -0
  12. data/lib/matchers/have_timestamps.rb +61 -0
  13. data/lib/matchers/indexes/have_index_for.rb +16 -0
  14. data/lib/matchers/indexes/v3/have_index_for.rb +59 -0
  15. data/lib/matchers/indexes/v4/have_index_for.rb +54 -0
  16. data/lib/matchers/validations.rb +30 -11
  17. data/lib/matchers/validations/absence_of.rb +11 -0
  18. data/lib/matchers/validations/associated.rb +1 -1
  19. data/lib/matchers/validations/confirmation_of.rb +7 -1
  20. data/lib/matchers/validations/custom_validation_of.rb +1 -4
  21. data/lib/matchers/validations/exclusion_of.rb +5 -5
  22. data/lib/matchers/validations/format_of.rb +2 -2
  23. data/lib/matchers/validations/inclusion_of.rb +5 -5
  24. data/lib/matchers/validations/length_of.rb +13 -35
  25. data/lib/matchers/validations/numericality_of.rb +32 -16
  26. data/lib/matchers/validations/presence_of.rb +1 -1
  27. data/lib/matchers/validations/uniqueness_of.rb +7 -10
  28. data/lib/mongoid-rspec.rb +1 -33
  29. data/lib/mongoid/rspec.rb +46 -0
  30. data/lib/mongoid/rspec/version.rb +5 -0
  31. data/spec/models/article.rb +9 -6
  32. data/spec/models/comment.rb +1 -1
  33. data/spec/models/log.rb +3 -3
  34. data/spec/models/message.rb +17 -0
  35. data/spec/models/movie_article.rb +1 -2
  36. data/spec/models/person.rb +1 -1
  37. data/spec/models/profile.rb +2 -2
  38. data/spec/models/record.rb +1 -1
  39. data/spec/models/site.rb +5 -1
  40. data/spec/models/user.rb +12 -10
  41. data/spec/spec_helper.rb +12 -10
  42. data/spec/unit/accept_nested_attributes_spec.rb +1 -1
  43. data/spec/unit/associations_spec.rb +19 -7
  44. data/spec/unit/be_dynamic_document_spec.rb +21 -0
  45. data/spec/unit/be_mongoid_document_spec.rb +25 -0
  46. data/spec/unit/be_stored_in.rb +54 -0
  47. data/spec/unit/document_spec.rb +5 -14
  48. data/spec/unit/have_index_for_spec.rb +46 -0
  49. data/spec/unit/have_timestamps_spec.rb +71 -0
  50. data/spec/unit/validations_spec.rb +23 -14
  51. data/spec/validators/ssn_validator.rb +6 -6
  52. metadata +119 -43
  53. data/.document +0 -5
  54. data/.gitignore +0 -6
  55. data/.ruby-gemset +0 -1
  56. data/.ruby-version +0 -1
  57. data/.travis.yml +0 -10
  58. data/Gemfile +0 -4
  59. data/lib/matchers/collections.rb +0 -9
  60. data/lib/matchers/document.rb +0 -173
  61. data/lib/matchers/indexes.rb +0 -69
  62. data/lib/matchers/validations/with_message.rb +0 -27
  63. data/lib/mongoid-rspec/version.rb +0 -5
  64. data/mongoid-rspec.gemspec +0 -25
  65. data/spec/unit/collections_spec.rb +0 -7
  66. data/spec/unit/indexes_spec.rb +0 -17
@@ -3,7 +3,7 @@ module Mongoid
3
3
  module Matchers
4
4
  class AllowMassAssignmentOfMatcher # :nodoc:
5
5
  attr_reader :failure_message, :negative_failure_message
6
- alias :failure_message_when_negated :negative_failure_message
6
+ alias failure_message_when_negated negative_failure_message
7
7
 
8
8
  def initialize(attribute)
9
9
  @attribute = attribute.to_s
@@ -12,7 +12,7 @@ module Mongoid
12
12
 
13
13
  def as(role)
14
14
  if active_model_less_than_3_1?
15
- raise "You can specify role only in Rails 3.1 or greater"
15
+ raise 'You can specify role only in Rails 3.1 or greater'
16
16
  end
17
17
  @options[:role] = role
18
18
  self
@@ -25,20 +25,20 @@ module Mongoid
25
25
  @negative_failure_message = "#{@attribute} was made accessible"
26
26
  else
27
27
  if protected_attributes.empty?
28
- @negative_failure_message = "no attributes were protected"
28
+ @negative_failure_message = 'no attributes were protected'
29
29
  else
30
- @negative_failure_message = "#{class_name} is protecting " <<
31
- "#{protected_attributes.to_a.to_sentence}, " <<
32
- "but not #{@attribute}."
30
+ @negative_failure_message = "#{class_name} is protecting " \
31
+ "#{protected_attributes.to_a.to_sentence}, " \
32
+ "but not #{@attribute}."
33
33
  end
34
34
  end
35
35
  true
36
36
  else
37
- if whitelisting?
38
- @failure_message = "Expected #{@attribute} to be accessible"
39
- else
40
- @failure_message = "Did not expect #{@attribute} to be protected"
41
- end
37
+ @failure_message = if whitelisting?
38
+ "Expected #{@attribute} to be accessible"
39
+ else
40
+ "Did not expect #{@attribute} to be protected"
41
+ end
42
42
  false
43
43
  end
44
44
  end
@@ -62,7 +62,7 @@ module Mongoid
62
62
  end
63
63
 
64
64
  def whitelisting?
65
- authorizer.kind_of?(::ActiveModel::MassAssignmentSecurity::WhiteList)
65
+ authorizer.is_a?(::ActiveModel::MassAssignmentSecurity::WhiteList)
66
66
  end
67
67
 
68
68
  def attr_mass_assignable?
@@ -1,16 +1,29 @@
1
- require 'mongoid/relations'
1
+ if Mongoid::Compatibility::Version.mongoid7_or_newer?
2
+ require 'mongoid/association'
3
+ else
4
+ require 'mongoid/relations'
5
+ end
2
6
 
3
7
  module Mongoid
4
8
  module Matchers
5
9
  module Associations
6
-
7
- HAS_MANY = Mongoid::Relations::Referenced::Many
8
- HAS_AND_BELONGS_TO_MANY = Mongoid::Relations::Referenced::ManyToMany
9
- HAS_ONE = Mongoid::Relations::Referenced::One
10
- BELONGS_TO = Mongoid::Relations::Referenced::In
11
- EMBEDS_MANY = Mongoid::Relations::Embedded::Many
12
- EMBEDS_ONE = Mongoid::Relations::Embedded::One
13
- EMBEDDED_IN = Mongoid::Relations::Embedded::In
10
+ if Mongoid::Compatibility::Version.mongoid7_or_newer?
11
+ HAS_MANY = Mongoid::Association::Referenced::HasMany
12
+ HAS_AND_BELONGS_TO_MANY = Mongoid::Association::Referenced::HasAndBelongsToMany
13
+ HAS_ONE = Mongoid::Association::Referenced::HasOne
14
+ BELONGS_TO = Mongoid::Association::Referenced::BelongsTo
15
+ EMBEDS_MANY = Mongoid::Association::Embedded::EmbedsMany
16
+ EMBEDS_ONE = Mongoid::Association::Embedded::EmbedsOne
17
+ EMBEDDED_IN = Mongoid::Association::Embedded::EmbeddedIn
18
+ else
19
+ HAS_MANY = Mongoid::Relations::Referenced::Many
20
+ HAS_AND_BELONGS_TO_MANY = Mongoid::Relations::Referenced::ManyToMany
21
+ HAS_ONE = Mongoid::Relations::Referenced::One
22
+ BELONGS_TO = Mongoid::Relations::Referenced::In
23
+ EMBEDS_MANY = Mongoid::Relations::Embedded::Many
24
+ EMBEDS_ONE = Mongoid::Relations::Embedded::One
25
+ EMBEDDED_IN = Mongoid::Relations::Embedded::In
26
+ end
14
27
 
15
28
  class HaveAssociationMatcher
16
29
  def initialize(name, association_type)
@@ -28,7 +41,6 @@ module Mongoid
28
41
  end
29
42
 
30
43
  def as_inverse_of(association_inverse_name)
31
- raise "#{@association[:type].inspect} does not respond to :inverse_of" unless [HAS_MANY, HAS_AND_BELONGS_TO_MANY, BELONGS_TO, EMBEDDED_IN].include?(@association[:type])
32
44
  @association[:inverse_of] = association_inverse_name.to_s
33
45
  @expectation_message << " which is an inverse of #{@association[:inverse_of].inspect}"
34
46
  self
@@ -39,7 +51,7 @@ module Mongoid
39
51
  @association[:order] = association_field_name.to_s
40
52
  @expectation_message << " ordered by #{@association[:order].inspect}"
41
53
 
42
- if association_field_name.is_a? Origin::Key
54
+ if association_field_name.is_a? association_kind_of
43
55
  @association[:order_operator] = association_field_name.operator
44
56
  @expectation_message << " #{order_way(@association[:order_operator])}"
45
57
  end
@@ -49,43 +61,43 @@ module Mongoid
49
61
 
50
62
  def with_dependent(method_name)
51
63
  @association[:dependent] = method_name
52
- @expectation_message << " which specifies dependent as #{@association[:dependent].to_s}"
64
+ @expectation_message << " which specifies dependent as #{@association[:dependent]}"
53
65
  self
54
66
  end
55
67
 
56
68
  def with_autosave
57
69
  @association[:autosave] = true
58
- @expectation_message << " which specifies autosave as #{@association[:autosave].to_s}"
70
+ @expectation_message << " which specifies autosave as #{@association[:autosave]}"
59
71
  self
60
72
  end
61
73
 
62
74
  def with_index
63
75
  @association[:index] = true
64
- @expectation_message << " which specifies index as #{@association[:index].to_s}"
76
+ @expectation_message << " which specifies index as #{@association[:index]}"
65
77
  self
66
78
  end
67
79
 
68
80
  def with_autobuild
69
81
  @association[:autobuild] = true
70
- @expectation_message << " which specifies autobuild as #{@association[:autobuild].to_s}"
82
+ @expectation_message << " which specifies autobuild as #{@association[:autobuild]}"
71
83
  self
72
84
  end
73
85
 
74
86
  def with_polymorphism
75
87
  @association[:polymorphic] = true
76
- @expectation_message << " which specifies polymorphic as #{@association[:polymorphic].to_s}"
88
+ @expectation_message << " which specifies polymorphic as #{@association[:polymorphic]}"
77
89
  self
78
90
  end
79
91
 
80
92
  def with_cascading_callbacks
81
93
  @association[:cascade_callbacks] = true
82
- @expectation_message << " which specifies cascade_callbacks as #{@association[:cascade_callbacks].to_s}"
94
+ @expectation_message << " which specifies cascade_callbacks as #{@association[:cascade_callbacks]}"
83
95
  self
84
96
  end
85
97
 
86
98
  def cyclic
87
99
  @association[:cyclic] = true
88
- @expectation_message << " which specifies cyclic as #{@association[:cyclic].to_s}"
100
+ @expectation_message << " which specifies cyclic as #{@association[:cyclic]}"
89
101
  self
90
102
  end
91
103
 
@@ -103,7 +115,13 @@ module Mongoid
103
115
 
104
116
  def with_counter_cache
105
117
  @association[:counter_cache] = true
106
- @expectation_message << " which specifies counter_cache as #{@association[:counter_cache].to_s}"
118
+ @expectation_message << " which specifies counter_cache as #{@association[:counter_cache]}"
119
+ self
120
+ end
121
+
122
+ def with_optional
123
+ @association[:optional] = true
124
+ @expectation_message << " which specifies optional as #{@association[:optional]}"
107
125
  self
108
126
  end
109
127
 
@@ -118,7 +136,11 @@ module Mongoid
118
136
  @positive_result_message = "association named #{@association[:name]}"
119
137
  end
120
138
 
121
- relation = metadata.relation
139
+ relation = if Mongoid::Compatibility::Version.mongoid7_or_newer?
140
+ metadata.class
141
+ else
142
+ metadata.relation
143
+ end
122
144
  if relation != @association[:type]
123
145
  @negative_result_message = "#{@actual.inspect} #{type_description(relation, false)} #{@association[:name]}"
124
146
  return false
@@ -126,7 +148,7 @@ module Mongoid
126
148
  @positive_result_message = "#{@actual.inspect} #{type_description(relation, false)} #{@association[:name]}"
127
149
  end
128
150
 
129
- if !@association[:class].nil? and @association[:class] != metadata.klass
151
+ if !@association[:class].nil? && (@association[:class] != metadata.klass)
130
152
  @negative_result_message = "#{@positive_result_message} of type #{metadata.klass.inspect}"
131
153
  return false
132
154
  else
@@ -224,11 +246,11 @@ module Mongoid
224
246
  end
225
247
 
226
248
  if @association[:index]
227
- if metadata.index != true
249
+ if metadata.indexed?
250
+ @positive_result_message = "#{@positive_result_message} which set index"
251
+ else
228
252
  @negative_result_message = "#{@positive_result_message} which did not set index"
229
253
  return false
230
- else
231
- @positive_result_message = "#{@positive_result_message} which set index"
232
254
  end
233
255
  end
234
256
 
@@ -250,7 +272,16 @@ module Mongoid
250
272
  end
251
273
  end
252
274
 
253
- return true
275
+ if @association[:optional]
276
+ if metadata.options[:optional] != true
277
+ @negative_result_message = "#{@positive_result_message} which did not set optional"
278
+ return false
279
+ else
280
+ @positive_result_message = "#{@positive_result_message} which set optional"
281
+ end
282
+ end
283
+
284
+ true
254
285
  end
255
286
 
256
287
  def failure_message_for_should
@@ -261,8 +292,8 @@ module Mongoid
261
292
  "Expected #{@actual.inspect} to not #{@expectation_message}, got #{@positive_result_message}"
262
293
  end
263
294
 
264
- alias :failure_message :failure_message_for_should
265
- alias :failure_message_when_negated :failure_message_for_should_not
295
+ alias failure_message failure_message_for_should
296
+ alias failure_message_when_negated failure_message_for_should_not
266
297
 
267
298
  def description
268
299
  @expectation_message
@@ -271,29 +302,34 @@ module Mongoid
271
302
  def type_description(type = nil, passive = true)
272
303
  type ||= @association[:type]
273
304
  case type.name
274
- when EMBEDS_ONE.name
275
- (passive ? 'embed' : 'embeds') << ' one'
276
- when EMBEDS_MANY.name
277
- (passive ? 'embed' : 'embeds') << ' many'
278
- when EMBEDDED_IN.name
279
- (passive ? 'be' : 'is') << ' embedded in'
280
- when HAS_ONE.name
281
- (passive ? 'reference' : 'references') << ' one'
282
- when HAS_MANY.name
283
- (passive ? 'reference' : 'references') << ' many'
284
- when HAS_AND_BELONGS_TO_MANY.name
285
- (passive ? 'reference' : 'references') << ' and referenced in many'
286
- when BELONGS_TO.name
287
- (passive ? 'be referenced in' : 'referenced in')
288
- else
289
- raise "Unknown association type '%s'" % type
305
+ when EMBEDS_ONE.name
306
+ (passive ? 'embed' : 'embeds') << ' one'
307
+ when EMBEDS_MANY.name
308
+ (passive ? 'embed' : 'embeds') << ' many'
309
+ when EMBEDDED_IN.name
310
+ (passive ? 'be' : 'is') << ' embedded in'
311
+ when HAS_ONE.name
312
+ (passive ? 'reference' : 'references') << ' one'
313
+ when HAS_MANY.name
314
+ (passive ? 'reference' : 'references') << ' many'
315
+ when HAS_AND_BELONGS_TO_MANY.name
316
+ (passive ? 'reference' : 'references') << ' and referenced in many'
317
+ when BELONGS_TO.name
318
+ (passive ? 'be referenced in' : 'referenced in')
319
+ else
320
+ raise format("Unknown association type '%s'", type)
290
321
  end
291
322
  end
292
323
 
293
324
  private
294
- def order_way(operator)
295
- [nil, "ascending", "descending"][operator]
296
- end
325
+
326
+ def order_way(operator)
327
+ [nil, 'ascending', 'descending'][operator]
328
+ end
329
+
330
+ def association_kind_of
331
+ Mongoid::Compatibility::Version.mongoid5_or_older? ? Origin::Key : Mongoid::Criteria::Queryable::Key
332
+ end
297
333
  end
298
334
 
299
335
  def embed_one(association_name)
@@ -311,12 +347,12 @@ module Mongoid
311
347
  def have_one_related(association_name)
312
348
  HaveAssociationMatcher.new(association_name, HAS_ONE)
313
349
  end
314
- alias :have_one :have_one_related
350
+ alias have_one have_one_related
315
351
 
316
352
  def have_many_related(association_name)
317
353
  HaveAssociationMatcher.new(association_name, HAS_MANY)
318
354
  end
319
- alias :have_many :have_many_related
355
+ alias have_many have_many_related
320
356
 
321
357
  def have_and_belong_to_many(association_name)
322
358
  HaveAssociationMatcher.new(association_name, HAS_AND_BELONGS_TO_MANY)
@@ -325,7 +361,7 @@ module Mongoid
325
361
  def belong_to_related(association_name)
326
362
  HaveAssociationMatcher.new(association_name, BELONGS_TO)
327
363
  end
328
- alias :belong_to :belong_to_related
364
+ alias belong_to belong_to_related
329
365
  end
330
366
  end
331
367
  end
@@ -0,0 +1,26 @@
1
+ module Mongoid
2
+ module Matchers
3
+ def be_dynamic_document
4
+ BeDynamicDocument.new
5
+ end
6
+
7
+ class BeDynamicDocument
8
+ def matches?(actual)
9
+ @model = actual.is_a?(Class) ? actual : actual.class
10
+ @model.included_modules.include?(Mongoid::Attributes::Dynamic)
11
+ end
12
+
13
+ def description
14
+ 'include Mongoid::Attributes::Dynamic'
15
+ end
16
+
17
+ def failure_message
18
+ "expect #{@model.inspect} class to #{description}"
19
+ end
20
+
21
+ def failure_message_when_negated
22
+ "expect #{@model.inspect} class to not #{description}"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ module Mongoid
2
+ module Matchers
3
+ def be_mongoid_document
4
+ BeMongoidDocument.new
5
+ end
6
+
7
+ class BeMongoidDocument
8
+ def matches?(actual)
9
+ @model = actual.is_a?(Class) ? actual : actual.class
10
+ @model.included_modules.include?(Mongoid::Document)
11
+ end
12
+
13
+ def description
14
+ 'include Mongoid::Document'
15
+ end
16
+
17
+ def failure_message
18
+ "expect #{@model.inspect} class to #{description}"
19
+ end
20
+
21
+ def failure_message_when_negated
22
+ "expect #{@model.inspect} class to not #{description}"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,55 @@
1
+ module Mongoid
2
+ module Matchers
3
+ def be_stored_in(options)
4
+ BeStoredIn.new(options)
5
+ end
6
+
7
+ class BeStoredIn
8
+ def initialize(expected)
9
+ @expected_options = expected.transform_values { |v| v.to_sym rescue v }.symbolize_keys
10
+ end
11
+
12
+ def matches?(actual)
13
+ @model = actual.is_a?(Class) ? actual : actual.class
14
+ actual_options == @expected_options
15
+ end
16
+
17
+ def description
18
+ "be stored in #{@expected_options.inspect}"
19
+ end
20
+
21
+ def failure_message
22
+ "Expected #{@model.inspect} to #{description}, got #{actual_options.inspect}"
23
+ end
24
+
25
+ def failure_message_when_negated
26
+ "Expected #{@model.inspect} not to #{description}, got #{actual_options.inspect}"
27
+ end
28
+
29
+ private
30
+
31
+ def actual_options
32
+ @actual_options ||= begin
33
+ hash = @model.storage_options.slice(*@expected_options.keys)
34
+ hash.each do |option, value|
35
+ hash[option] =
36
+ if value.is_a?(Proc)
37
+ evaluated_value = @model.persistence_context.send("#{option}_name")
38
+ begin
39
+ evaluated_value.to_sym
40
+ rescue StandardError
41
+ evaluated_value
42
+ end
43
+ else
44
+ begin
45
+ value.to_sym
46
+ rescue StandardError
47
+ value
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,90 @@
1
+ module Mongoid
2
+ module Matchers
3
+ class HaveField # :nodoc:
4
+ def initialize(*attrs)
5
+ @attributes = attrs.collect(&:to_s)
6
+ end
7
+
8
+ def localized
9
+ @localized = true
10
+ self
11
+ end
12
+
13
+ def of_type(type)
14
+ @type = type
15
+ self
16
+ end
17
+
18
+ def with_alias(field_alias)
19
+ @field_alias = field_alias
20
+ self
21
+ end
22
+
23
+ def with_default_value_of(default)
24
+ @default = default
25
+ self
26
+ end
27
+
28
+ def matches?(klass)
29
+ @klass = klass.is_a?(Class) ? klass : klass.class
30
+ @errors = []
31
+ @attributes.each do |attr|
32
+ if @klass.fields.include?(attr)
33
+ error = ''
34
+ if @type && (@klass.fields[attr].type != @type)
35
+ error << " of type #{@klass.fields[attr].type}"
36
+ end
37
+
38
+ unless @default.nil?
39
+ if @klass.fields[attr].default_val.nil?
40
+ error << ' with default not set'
41
+ elsif @klass.fields[attr].default_val != @default
42
+ error << " with default value of #{@klass.fields[attr].default_val}"
43
+ end
44
+ end
45
+
46
+ if @field_alias && (@klass.fields[attr].options[:as] != @field_alias)
47
+ error << " with alias #{@klass.fields[attr].options[:as]}"
48
+ end
49
+
50
+ @errors.push("field #{attr.inspect}" << error) unless error.blank?
51
+
52
+ if @localized
53
+ unless @klass.fields[attr].localized?
54
+ @errors.push "is not localized #{attr.inspect}"
55
+ end
56
+ end
57
+
58
+ else
59
+ @errors.push "no field named #{attr.inspect}"
60
+ end
61
+ end
62
+ @errors.empty?
63
+ end
64
+
65
+ def failure_message_for_should
66
+ "Expected #{@klass.inspect} to #{description}, got #{@errors.to_sentence}"
67
+ end
68
+
69
+ def failure_message_for_should_not
70
+ "Expected #{@klass.inspect} to not #{description}, got #{@klass.inspect} to #{description}"
71
+ end
72
+
73
+ alias failure_message failure_message_for_should
74
+ alias failure_message_when_negated failure_message_for_should_not
75
+
76
+ def description
77
+ desc = "have #{@attributes.size > 1 ? 'fields' : 'field'} named #{@attributes.collect(&:inspect).to_sentence}"
78
+ desc << " of type #{@type.inspect}" if @type
79
+ desc << " with alias #{@field_alias}" if @field_alias
80
+ desc << " with default value of #{@default.inspect}" unless @default.nil?
81
+ desc
82
+ end
83
+ end
84
+
85
+ def have_field(*args)
86
+ HaveField.new(*args)
87
+ end
88
+ alias have_fields have_field
89
+ end
90
+ end