mongoid-rspec 2.1.0 → 4.1.0

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