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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2db94999da51dbfed3ab87f523aa9d5a28608918
4
+ data.tar.gz: 95298ae001c5e3dce8a60f1f224dc6a197042f3d
5
+ SHA512:
6
+ metadata.gz: 28cf8f5ec27d608d91f6de5f2ba455447f01e9a2610db82aa6601b6ffd61d983cf721365f98d81d0653a46b391240a8e6f15cddc00f907485912cf149cd55eaa
7
+ data.tar.gz: 90ca7b34ab2492dffde3add00cf94b3b7444b20198feb8844d284f6b16ec1d6d586d08df76b4d4dddd52e89a8a01cf11fe6c73d91488005899322b40b9dfa217
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Evan Sagge
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,373 @@
1
+ # [mongoid-rspec]
2
+
3
+ [![Build Status][travis_badge]][travis]
4
+ [![Gem Version][rubygems_badge]][rubygems]
5
+ [![Code Climate][codeclimate_badge]][codeclimate]
6
+
7
+ mongoid-rspec provides a collection of RSpec-compatible matchers that help to test Mongoid documents.
8
+
9
+ ## Installation
10
+
11
+ Drop this line into your Gemfile:
12
+
13
+ ```ruby
14
+ group :test do
15
+ gem 'mongoid-rspec'
16
+ end
17
+
18
+ ```
19
+
20
+ ### Compatibility
21
+
22
+ There's no stable version, that provides support for Mongoid 6. But for a time being you can use HEAD version:
23
+
24
+ ```ruby
25
+ gem 'mongoid-rspec', github: 'mongoid-rspec/mongoid-rspec'
26
+ ```
27
+
28
+ If you're using old version of mongoid, then you have to specify particular vesrion of mongoid-rspec. Use compatibility matrix to find out, which version suits your case.
29
+
30
+
31
+ | mongoid version | mongoid-rspec version |
32
+ |-----------------|-------------------------|
33
+ | 5.x | [3.0.0][mongoid5] |
34
+ | 4.x | [2.1.0][mongoid4] |
35
+ | 3.x | [1.13.0][mongoid3] |
36
+ | 2.x | [1.4.5][mongoid2] |
37
+
38
+ ## Configuration
39
+
40
+ ### Rails
41
+
42
+ Add to your `rails_helper.rb` file
43
+
44
+ ```ruby
45
+ require 'mongoid-rspec'
46
+
47
+ RSpec.configure do |config|
48
+ config.include Mongoid::Matchers, type: :model
49
+ end
50
+ ```
51
+
52
+ ### Other
53
+
54
+ Add to your `spec_helper.rb` file
55
+
56
+ ```ruby
57
+ require 'mongoid-rspec'
58
+
59
+ RSpec.configure do |config|
60
+ config.include Mongoid::Matchers
61
+ end
62
+ ```
63
+
64
+ ## Matchers
65
+
66
+ ### be_mongoid_document
67
+
68
+ ```ruby
69
+ class Post
70
+ include Mongoid::Document
71
+ end
72
+
73
+ RSpec.describe Post, type: :model do
74
+ it { is_expected.to be_mongoid_document }
75
+ end
76
+ ```
77
+
78
+ ### be_dynamic_document
79
+
80
+ ```ruby
81
+ class User
82
+ include Mongoid::Document
83
+ include Mongoid::Attributes::Dynamic
84
+ end
85
+
86
+ RSpec.describe User, type: :model do
87
+ it { is_expected.to be_dynamic_document }
88
+ end
89
+ ```
90
+
91
+ ### have_timestamps
92
+
93
+ With full timestamps
94
+
95
+ ```ruby
96
+ class Log
97
+ include Mongoid::Document
98
+ include Mongoid::Timestamps
99
+ end
100
+
101
+ RSpec.describe Log, type: :model do
102
+ it { is_expected.to have_timestamps }
103
+ end
104
+ ```
105
+
106
+ With short timestamps
107
+ ```ruby
108
+ class User
109
+ include Mongoid::Document
110
+ include Mongoid::Timestamps::Short
111
+ end
112
+
113
+ RSpec.describe User, type: :model do
114
+ it { is_expected.to have_timestamps.shortened }
115
+ end
116
+ ```
117
+
118
+ With only creating or updating timestamps
119
+ ```ruby
120
+ class Admin
121
+ include Mongoid::Document
122
+ include Mongoid::Timestamps::Create
123
+ include Mongoid::Timestamps::Update
124
+ end
125
+
126
+ RSpec.describe Admin, type: :model do
127
+ it { is_expected.to have_timestamps.for(:creating) }
128
+ it { is_expected.to have_timestamps.for(:updating) }
129
+ end
130
+ ```
131
+
132
+ With short creating or updating timestamps
133
+ ```ruby
134
+ class Post
135
+ include Mongoid::Document
136
+ include Mongoid::Timestamps::Create::Short
137
+ end
138
+
139
+ RSpec.describe Short, type: :model do
140
+ it { is_expected.to have_timestamps.for(:creating).shortened }
141
+ end
142
+ ```
143
+
144
+ ### be_stored_in
145
+
146
+ ```ruby
147
+ class Post
148
+ include Mongoid::Document
149
+
150
+ store_in database: 'db1', collection: 'messages', client: 'secondary'
151
+ end
152
+
153
+ RSpec.describe Post, type: :model do
154
+ it { is_expected.to be_stored_in(database: 'db1', collection: 'messages', client: 'secondary') }
155
+ end
156
+ ```
157
+
158
+ It checks only those options, that you specify. For instance, test in example below will pass, even though expectation contains only `database` option
159
+
160
+ ```ruby
161
+ class Comment
162
+ include Mongoid::Document
163
+
164
+ store_in database: 'db2', collection: 'messages'
165
+ end
166
+
167
+ RSpec.describe Comment, type: :model do
168
+ it { is_expected.to be_stored_in(database: 'db2') }
169
+ end
170
+ ```
171
+
172
+ It works fine with lambdas and procs.
173
+ ```ruby
174
+ class User
175
+ include Mongoid::Document
176
+
177
+ store_in database: ->{ Thread.current[:database] }
178
+ end
179
+
180
+ RSpec.describe Post, type: :model do
181
+ it do
182
+ Thread.current[:database] = 'db3'
183
+ is_expected.to be_stored_in(database: 'db3')
184
+
185
+ Thread.current[:database] = 'db4'
186
+ is_expected.to be_stored_in(database: 'db4')
187
+ end
188
+ end
189
+ ```
190
+
191
+ ### have_index_for
192
+
193
+ ```ruby
194
+ class Article
195
+ index({ title: 1 }, { unique: true, background: true, drop_dups: true })
196
+ index({ title: 1, created_at: -1 })
197
+ index({ category: 1 })
198
+ end
199
+
200
+ RSpec.describe Article, type: :model do
201
+ it do
202
+ is_expected
203
+ .to have_index_for(title: 1)
204
+ .with_options(unique: true, background: true, drop_dups: true)
205
+ end
206
+ it { is_expected.to have_index_for(title: 1, created_at: -1) }
207
+ it { is_expected.to have_index_for(category: 1) }
208
+ end
209
+ ```
210
+
211
+ ### Field Matchers
212
+
213
+ ```ruby
214
+ RSpec.describe Article do
215
+ it { is_expected.to have_field(:published).of_type(Boolean).with_default_value_of(false) }
216
+ it { is_expected.to have_field(:allow_comments).of_type(Boolean).with_default_value_of(true) }
217
+ it { is_expected.not_to have_field(:allow_comments).of_type(Boolean).with_default_value_of(false) }
218
+ it { is_expected.not_to have_field(:number_of_comments).of_type(Integer).with_default_value_of(1) }
219
+ end
220
+
221
+ RSpec.describe User do
222
+ it { is_expected.to have_fields(:email, :login) }
223
+ it { is_expected.to have_field(:s).with_alias(:status) }
224
+ it { is_expected.to have_fields(:birthdate, :registered_at).of_type(DateTime) }
225
+ end
226
+ ```
227
+
228
+ ### Association Matchers
229
+
230
+ ```ruby
231
+ RSpec.describe User do
232
+ it { is_expected.to have_many(:articles).with_foreign_key(:author_id).ordered_by(:title) }
233
+
234
+ it { is_expected.to have_one(:record) }
235
+ #can verify autobuild is set to true
236
+ it { is_expected.to have_one(:record).with_autobuild }
237
+
238
+ it { is_expected.to have_many :comments }
239
+
240
+ #can also specify with_dependent to test if :dependent => :destroy/:destroy_all/:delete is set
241
+ it { is_expected.to have_many(:comments).with_dependent(:destroy) }
242
+ #can verify autosave is set to true
243
+ it { is_expected.to have_many(:comments).with_autosave }
244
+
245
+ it { is_expected.to embed_one :profile }
246
+
247
+ it { is_expected.to have_and_belong_to_many(:children) }
248
+ it { is_expected.to have_and_belong_to_many(:children).of_type(User) }
249
+ end
250
+
251
+ RSpec.describe Profile do
252
+ it { is_expected.to be_embedded_in(:user).as_inverse_of(:profile) }
253
+ end
254
+
255
+ RSpec.describe Article do
256
+ it { is_expected.to belong_to(:author).of_type(User).as_inverse_of(:articles) }
257
+ it { is_expected.to belong_to(:author).of_type(User).as_inverse_of(:articles).with_index }
258
+ it { is_expected.to embed_many(:comments) }
259
+ end
260
+
261
+ RSpec.describe Comment do
262
+ it { is_expected.to be_embedded_in(:article).as_inverse_of(:comments) }
263
+ it { is_expected.to belong_to(:user).as_inverse_of(:comments) }
264
+ end
265
+
266
+ RSpec.describe Record do
267
+ it { is_expected.to belong_to(:user).as_inverse_of(:record) }
268
+ end
269
+
270
+ RSpec.describe Site do
271
+ it { is_expected.to have_many(:users).as_inverse_of(:site).ordered_by(:email.asc).with_counter_cache }
272
+ end
273
+ ```
274
+
275
+ ### Validation Matchers
276
+
277
+ ```ruby
278
+ RSpec.describe Site do
279
+ it { is_expected.to validate_presence_of(:name) }
280
+ it { is_expected.to validate_uniqueness_of(:name) }
281
+ end
282
+
283
+ RSpec.describe User do
284
+ it { is_expected.to validate_presence_of(:login) }
285
+ it { is_expected.to validate_uniqueness_of(:login).scoped_to(:site) }
286
+ it { is_expected.to validate_uniqueness_of(:email).case_insensitive.with_message("is already taken") }
287
+ it { is_expected.to validate_format_of(:login).to_allow("valid_login").not_to_allow("invalid login") }
288
+ it { is_expected.to validate_associated(:profile) }
289
+ it { is_expected.to validate_exclusion_of(:login).to_not_allow("super", "index", "edit") }
290
+ it { is_expected.to validate_inclusion_of(:role).to_allow("admin", "member") }
291
+ it { is_expected.to validate_confirmation_of(:email) }
292
+ it { is_expected.to validate_presence_of(:age).on(:create, :update) }
293
+ it { is_expected.to validate_numericality_of(:age).on(:create, :update) }
294
+ it { is_expected.to validate_inclusion_of(:age).to_allow(23..42).on([:create, :update]) }
295
+ it { is_expected.to validate_presence_of(:password).on(:create) }
296
+ it { is_expected.to validate_presence_of(:provider_uid).on(:create) }
297
+ it { is_expected.to validate_inclusion_of(:locale).to_allow([:en, :ru]) }
298
+ end
299
+
300
+ RSpec.describe Article do
301
+ it { is_expected.to validate_length_of(:title).within(8..16) }
302
+ end
303
+
304
+ RSpec.describe Profile do
305
+ it { is_expected.to validate_numericality_of(:age).greater_than(0) }
306
+ end
307
+
308
+ RSpec.describe MovieArticle do
309
+ it { is_expected.to validate_numericality_of(:rating).to_allow(:greater_than => 0).less_than_or_equal_to(5) }
310
+ it { is_expected.to validate_numericality_of(:classification).to_allow(:even => true, :only_integer => true, :nil => false) }
311
+ end
312
+
313
+ RSpec.describe Person do
314
+ # in order to be able to use the custom_validate matcher, the custom validator class (in this case SsnValidator)
315
+ # should redefine the kind method to return :custom, i.e. "def self.kind() :custom end"
316
+ it { is_expected.to custom_validate(:ssn).with_validator(SsnValidator) }
317
+ end
318
+ ```
319
+
320
+ ### Mass Assignment Matcher
321
+
322
+ ```ruby
323
+ RSpec.describe User do
324
+ it { is_expected.to allow_mass_assignment_of(:login) }
325
+ it { is_expected.to allow_mass_assignment_of(:email) }
326
+ it { is_expected.to allow_mass_assignment_of(:age) }
327
+ it { is_expected.to allow_mass_assignment_of(:password) }
328
+ it { is_expected.to allow_mass_assignment_of(:password) }
329
+ it { is_expected.to allow_mass_assignment_of(:role).as(:admin) }
330
+
331
+ it { is_expected.not_to allow_mass_assignment_of(:role) }
332
+ end
333
+ ```
334
+
335
+ ### Accepts Nested Attributes Matcher
336
+
337
+ ```ruby
338
+ RSpec.describe User do
339
+ it { is_expected.to accept_nested_attributes_for(:articles) }
340
+ it { is_expected.to accept_nested_attributes_for(:comments) }
341
+ end
342
+
343
+ RSpec.describe Article do
344
+ it { is_expected.to accept_nested_attributes_for(:permalink) }
345
+ end
346
+ ```
347
+
348
+ ## Known issues
349
+
350
+ accept_nested_attributes_for matcher must test options [issue 91](https://github.com/mongoid-rspec/mongoid-rspec/issues/91).
351
+
352
+ ## Acknowledgement
353
+
354
+ Thanks to [Durran Jordan][durran] for providing the changes necessary to make
355
+ this compatible with mongoid 2.0.0.rc, and for other [contributors](https://github.com/mongoid-rspec/mongoid-rspec/contributors)
356
+ to this project.
357
+
358
+ [mongoid-rspec]: https://github.com/mongoid-rspec/mongoid-rspec "A collection of RSpec-compatible matchers that help to test Mongoid documents."
359
+
360
+ [durran]: https://github.com/durran
361
+ [mongoid2]: https://rubygems.org/gems/mongoid-rspec/versions/1.4.5
362
+ [mongoid3]: https://rubygems.org/gems/mongoid-rspec/versions/1.13.0
363
+ [mongoid4]: https://rubygems.org/gems/mongoid-rspec/versions/2.1.0
364
+ [mongoid5]: https://rubygems.org/gems/mongoid-rspec/versions/3.0.0
365
+
366
+ [travis_badge]: http://img.shields.io/travis/mongoid-rspec/mongoid-rspec.svg?style=flat
367
+ [travis]: https://travis-ci.org/mongoid-rspec/mongoid-rspec
368
+
369
+ [rubygems_badge]: http://img.shields.io/gem/v/mongoid-rspec.svg?style=flat
370
+ [rubygems]: http://rubygems.org/gems/mongoid-rspec
371
+
372
+ [codeclimate_badge]: http://img.shields.io/codeclimate/github/mongoid-rspec/mongoid-rspec.svg?style=flat
373
+ [codeclimate]: https://codeclimate.com/github/mongoid-rspec/mongoid-rspec
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ require 'bundler'
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ require 'rspec/core/rake_task'
7
+
8
+ task :default => :spec
9
+
10
+ RSpec::Core::RakeTask.new(:spec) do |spec|
11
+ spec.pattern = "./spec/**/*_spec.rb"
12
+ end
13
+
14
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
15
+ spec.pattern = "./spec/**/*_spec.rb"
16
+ spec.rcov = true
17
+ end
@@ -0,0 +1,67 @@
1
+ module Mongoid
2
+ module Matchers # :nodoc:
3
+
4
+ # Ensures that the model can accept nested attributes for the specified
5
+ # association.
6
+ #
7
+ # Example:
8
+ # it { should accept_nested_attributes_for(:articles) }
9
+ #
10
+ def accept_nested_attributes_for(attribute)
11
+ AcceptNestedAttributesForMatcher.new(attribute)
12
+ end
13
+
14
+ class AcceptNestedAttributesForMatcher
15
+
16
+ def initialize(attribute)
17
+ @attribute = attribute.to_s
18
+ @options = {}
19
+ end
20
+
21
+ def matches?(subject)
22
+ @subject = subject
23
+ match?
24
+ end
25
+
26
+ def failure_message
27
+ "Expected #{expectation} (#{@problem})"
28
+ end
29
+
30
+ def negative_failure_message
31
+ "Did not expect #{expectation}"
32
+ end
33
+
34
+ alias :failure_message_when_negated :negative_failure_message
35
+
36
+ def description
37
+ description = "accepts_nested_attributes_for :#{@attribute}"
38
+ end
39
+
40
+ protected
41
+ def match?
42
+ exists?
43
+ end
44
+
45
+ def exists?
46
+ if config
47
+ true
48
+ else
49
+ @problem = 'is not declared'
50
+ false
51
+ end
52
+ end
53
+
54
+ def config
55
+ model_class.nested_attributes["#{@attribute}_attributes"]
56
+ end
57
+
58
+ def model_class
59
+ @subject.class
60
+ end
61
+
62
+ def expectation
63
+ "#{model_class.name} to accept nested attributes for #{@attribute}"
64
+ end
65
+ end
66
+ end
67
+ end