mongoid-rspec 4.1.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c59448b4e72ebb718332a28e7ddf77de5b792a09ea273b75959930e2c6c2918
4
- data.tar.gz: b1818ed7a513db7a4e31bcdd5a492504a75becfc866dd95505192da1db7a56cc
3
+ metadata.gz: 711f91347b02d3d6982a72b6946bb781ea07dba16f858109da01166c7a768ecf
4
+ data.tar.gz: 58e81131678e670e5a7b63385122fa316afadb18d49749c3544a4e5e1898d3fc
5
5
  SHA512:
6
- metadata.gz: 995c284d71146d52d554e8eff18e48605e76546ebce9428674d1fcefe4c560a73973651f4eb4496d21a839fb35944c37f98cc21eb78ddd1e1eea80a57d1392c4
7
- data.tar.gz: a2e400ead572f31c614a294f1d5d10116e08fa6f152b2f58cf112da45608a3d72be2c5893ceb035c8a6f514af8ef55bcfdffd0a55a81a2e0f97ad43fd0699cf2
6
+ metadata.gz: 7aab1843f0f0b8778916039f3ef8b0f89e815bbc9cfafe0d7244a903df8c524ec6e990914478d6cd403b5b9e81e885b007850fe58cbf78841d989a472e98cdb2
7
+ data.tar.gz: 3e068496db19d24acfd05ff8ac630ecd41ccab1606e6597ddf0d0bf5969296dd7e1f2f5cf3a7a847801b44c84363e784908024a392317b7d1a95825f2c66bf9f
data/README.md CHANGED
@@ -1,10 +1,17 @@
1
1
  # [mongoid-rspec](https://github.com/mongoid/mongoid-rspec "A collection of RSpec-compatible matchers that help to test Mongoid documents.")
2
2
 
3
- [![Build Status](https://travis-ci.org/mongoid/mongoid-rspec.svg?branch=master)](https://travis-ci.org/mongoid/mongoid-rspec)
4
3
  [![Gem Version](https://badge.fury.io/rb/mongoid-rspec.svg)](https://badge.fury.io/rb/mongoid-rspec)
4
+ [![Test Status](https://github.com/mongoid/mongoid-rspec/workflows/Test/badge.svg)](https://github.com/mongoid/mongoid-rspec/actions)
5
+ [![Rubocop Status](https://github.com/mongoid/mongoid-rspec/workflows/Rubocop/badge.svg)](https://github.com/mongoid/mongoid-rspec/actions)
5
6
 
6
7
  The mongoid-rspec library provides a collection of RSpec-compatible matchers that help to test Mongoid documents.
7
8
 
9
+ [Tested](https://github.com/mongoid/mongoid-locker/actions) against:
10
+ - MRI: `2.6.x`, `2.7.x`, `3.0.x`, `3.1.x`, `3.2.x`
11
+ - Mongoid: `4`, `5`, `6`, `7`, `8`, `9`
12
+
13
+ See [.github/workflows/rspec.yml](.github/workflows/rspec.yml) for the latest test matrix.
14
+
8
15
  ## Installation
9
16
 
10
17
  Drop this line into your Gemfile:
@@ -18,7 +25,7 @@ end
18
25
 
19
26
  ## Compatibility
20
27
 
21
- This gem is compatible with Mongoid 3, 4, 5, 6 and 7.
28
+ This gem is compatible with Mongoid 3, 4, 5, 6, 7, 8, 9.
22
29
 
23
30
  ## Configuration
24
31
 
@@ -181,7 +188,7 @@ end
181
188
 
182
189
  ```ruby
183
190
  class Article
184
- index({ title: 1 }, { unique: true, background: true, drop_dups: true })
191
+ index({ title: 1 }, { unique: true, background: true })
185
192
  index({ title: 1, created_at: -1 })
186
193
  index({ category: 1 })
187
194
  end
@@ -190,7 +197,7 @@ RSpec.describe Article, type: :model do
190
197
  it do
191
198
  is_expected
192
199
  .to have_index_for(title: 1)
193
- .with_options(unique: true, background: true, drop_dups: true)
200
+ .with_options(unique: true, background: true)
194
201
  end
195
202
  it { is_expected.to have_index_for(title: 1, created_at: -1) }
196
203
  it { is_expected.to have_index_for(category: 1) }
@@ -201,9 +208,9 @@ end
201
208
 
202
209
  ```ruby
203
210
  RSpec.describe Article do
204
- it { is_expected.to have_field(:published).of_type(Boolean).with_default_value_of(false) }
205
- it { is_expected.to have_field(:allow_comments).of_type(Boolean).with_default_value_of(true) }
206
- it { is_expected.not_to have_field(:allow_comments).of_type(Boolean).with_default_value_of(false) }
211
+ it { is_expected.to have_field(:published).of_type(Mongoid::Boolean).with_default_value_of(false) }
212
+ it { is_expected.to have_field(:allow_comments).of_type(Mongoid::Boolean).with_default_value_of(true) }
213
+ it { is_expected.not_to have_field(:allow_comments).of_type(Mongoid::Boolean).with_default_value_of(false) }
207
214
  it { is_expected.not_to have_field(:number_of_comments).of_type(Integer).with_default_value_of(1) }
208
215
  end
209
216
 
@@ -249,6 +256,27 @@ RSpec.describe Article do
249
256
  it { is_expected.to embed_many(:comments) }
250
257
  end
251
258
 
259
+ # when the touch option is provided, then we can also verify that it is set
260
+
261
+ # by default, with_touch matches true when no parameters are provided
262
+ describe Article do
263
+ it { is_expected.to belong_to(:author).of_type(User).as_inverse_of(:articles).with_index.with_touch }
264
+ end
265
+
266
+ # parameters are supported for explicit matching
267
+ describe Comment do
268
+ it { is_expected.to be_embedded_in(:article).as_inverse_of(:comments).with_polymorphism.with_touch(true) }
269
+ end
270
+
271
+ describe Permalink do
272
+ it { is_expected.to be_embedded_in(:linkable).as_inverse_of(:link).with_touch(false) }
273
+ end
274
+
275
+ # touch can also take a symbol representing a field on the parent to touch
276
+ describe Record do
277
+ it { is_expected.to belong_to(:user).as_inverse_of(:record).with_touch(:record_updated_at) }
278
+ end
279
+
252
280
  RSpec.describe Comment do
253
281
  it { is_expected.to be_embedded_in(:article).as_inverse_of(:comments) }
254
282
  it { is_expected.to belong_to(:user).as_inverse_of(:comments) }
@@ -315,6 +343,22 @@ RSpec.describe Person do
315
343
  # should redefine the kind method to return :custom, i.e. "def self.kind() :custom end"
316
344
  it { is_expected.to custom_validate(:ssn).with_validator(SsnValidator) }
317
345
  end
346
+
347
+ # If you're using validators with if/unless conditionals, spec subject must be object instance
348
+ # This is supported on Mongoid 4 and newer
349
+ Rspec.describe User do
350
+ context 'when user has `admin` role' do
351
+ subject { User.new(role: 'admin') }
352
+
353
+ it { is_expected.to validate_length_of(:password).greater_than(20) }
354
+ end
355
+
356
+ context 'when user does not have `admin` role' do
357
+ subject { User.new(role: 'member') }
358
+
359
+ it { is_expected.not_to validate_length_of(:password) }
360
+ end
361
+ end
318
362
  ```
319
363
 
320
364
  ### Mass Assignment Matcher
data/Rakefile CHANGED
@@ -14,7 +14,4 @@ RSpec::Core::RakeTask.new(:rcov) do |spec|
14
14
  spec.rcov = true
15
15
  end
16
16
 
17
- require 'rubocop/rake_task'
18
- RuboCop::RakeTask.new(:rubocop)
19
-
20
- task default: %i[rubocop spec]
17
+ task default: %i[spec]
@@ -119,6 +119,12 @@ module Mongoid
119
119
  self
120
120
  end
121
121
 
122
+ def with_touch(touch = true)
123
+ @association[:touch] = touch
124
+ @expectation_message << " which specifies touch as #{@association[:touch]}"
125
+ self
126
+ end
127
+
122
128
  def with_optional
123
129
  @association[:optional] = true
124
130
  @expectation_message << " which specifies optional as #{@association[:optional]}"
@@ -272,6 +278,15 @@ module Mongoid
272
278
  end
273
279
  end
274
280
 
281
+ unless @association[:touch].nil?
282
+ if metadata.options[:touch] != @association[:touch]
283
+ @negative_result_message = "#{@positive_result_message} which sets touch as #{metadata.options[:touch].inspect}"
284
+ return false
285
+ else
286
+ @positive_result_message = "#{@positive_result_message} which sets touch as #{metadata.options[:touch].inspect}"
287
+ end
288
+ end
289
+
275
290
  if @association[:optional]
276
291
  if metadata.options[:optional] != true
277
292
  @negative_result_message = "#{@positive_result_message} which did not set optional"
@@ -44,7 +44,7 @@ module Mongoid
44
44
  private
45
45
 
46
46
  MAPPINGS = {
47
- dropDups: :drop_dups
47
+ dropDups: :drop_dups # Deprecated from MongoDB 3.0
48
48
  }.freeze
49
49
 
50
50
  def denormalising_options(opts)
@@ -12,7 +12,8 @@ module Mongoid
12
12
  @klass = actual.is_a?(Class) ? actual : actual.class
13
13
 
14
14
  @validator = @klass.validators_on(@field).detect do |v|
15
- (v.kind.to_s == @type) && (!v.options[:on] || on_options_matches?(v))
15
+ (v.kind.to_s == @type) && (!v.options[:on] || on_options_matches?(v)) &&
16
+ if_condition_matches?(actual, v) && unless_condition_matches?(actual, v)
16
17
  end
17
18
 
18
19
  if @validator
@@ -59,6 +60,31 @@ module Mongoid
59
60
 
60
61
  private
61
62
 
63
+ def if_condition_matches?(actual, validator)
64
+ return true unless validator.options[:if]
65
+
66
+ check_condition actual, validator.options[:if]
67
+ end
68
+
69
+ def unless_condition_matches?(actual, validator)
70
+ return true unless validator.options[:unless]
71
+
72
+ !check_condition actual, validator.options[:unless]
73
+ end
74
+
75
+ def check_condition(actual, filter)
76
+ raise ArgumentError, 'Spec subject must be object instance when testing validators with if/unless condition.' if actual.is_a?(Class)
77
+
78
+ case filter
79
+ when Symbol
80
+ actual.send filter
81
+ when ::Proc
82
+ actual.instance_exec(&filter)
83
+ else
84
+ raise ArgumentError, "Unexpected filter: #{filter.inspect}"
85
+ end
86
+ end
87
+
62
88
  def check_on
63
89
  validator_on_methods = [@validator.options[:on]].flatten
64
90
 
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  module RSpec
3
- VERSION = '4.1.0'.freeze
3
+ VERSION = '4.2.0'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,128 +1,134 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Sagge
8
8
  - Rodrigo Pinto
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-06-12 00:00:00.000000000 Z
12
+ date: 2024-06-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: activesupport
15
+ name: appraisal
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ">="
18
+ - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: 3.0.0
21
- type: :runtime
20
+ version: '2.0'
21
+ type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - ">="
25
+ - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: 3.0.0
27
+ version: '2.0'
28
28
  - !ruby/object:Gem::Dependency
29
- name: mongoid
29
+ name: mongoid-danger
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ">="
32
+ - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: '3.1'
35
- type: :runtime
34
+ version: '0.2'
35
+ type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - ">="
39
+ - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: '3.1'
41
+ version: '0.2'
42
42
  - !ruby/object:Gem::Dependency
43
- name: mongoid-compatibility
43
+ name: pry
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
46
  - - ">="
47
47
  - !ruby/object:Gem::Version
48
- version: 0.5.1
49
- type: :runtime
48
+ version: '0'
49
+ type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
53
  - - ">="
54
54
  - !ruby/object:Gem::Version
55
- version: 0.5.1
55
+ version: '0'
56
56
  - !ruby/object:Gem::Dependency
57
- name: rspec-core
57
+ name: rails
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - "~>"
60
+ - - ">="
61
61
  - !ruby/object:Gem::Version
62
- version: '3.3'
63
- type: :runtime
62
+ version: '0'
63
+ type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - "~>"
67
+ - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: '3.3'
69
+ version: '0'
70
70
  - !ruby/object:Gem::Dependency
71
- name: rspec-expectations
71
+ name: rspec
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
- - - "~>"
74
+ - - ">="
75
75
  - !ruby/object:Gem::Version
76
- version: '3.3'
77
- type: :runtime
76
+ version: '0'
77
+ type: :development
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
81
- - - "~>"
81
+ - - ">="
82
82
  - !ruby/object:Gem::Version
83
- version: '3.3'
83
+ version: '0'
84
84
  - !ruby/object:Gem::Dependency
85
- name: rspec-mocks
85
+ name: rubocop
86
86
  requirement: !ruby/object:Gem::Requirement
87
87
  requirements:
88
88
  - - "~>"
89
89
  - !ruby/object:Gem::Version
90
- version: '3.3'
91
- type: :runtime
90
+ version: 1.36.0
91
+ type: :development
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
95
  - - "~>"
96
96
  - !ruby/object:Gem::Version
97
- version: '3.3'
97
+ version: 1.36.0
98
98
  - !ruby/object:Gem::Dependency
99
- name: appraisal
99
+ name: mongoid
100
100
  requirement: !ruby/object:Gem::Requirement
101
101
  requirements:
102
- - - "~>"
102
+ - - ">="
103
103
  - !ruby/object:Gem::Version
104
- version: '2.2'
105
- type: :development
104
+ version: '3.0'
105
+ - - "<"
106
+ - !ruby/object:Gem::Version
107
+ version: '10.0'
108
+ type: :runtime
106
109
  prerelease: false
107
110
  version_requirements: !ruby/object:Gem::Requirement
108
111
  requirements:
109
- - - "~>"
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '3.0'
115
+ - - "<"
110
116
  - !ruby/object:Gem::Version
111
- version: '2.2'
117
+ version: '10.0'
112
118
  - !ruby/object:Gem::Dependency
113
- name: rake
119
+ name: mongoid-compatibility
114
120
  requirement: !ruby/object:Gem::Requirement
115
121
  requirements:
116
- - - "~>"
122
+ - - ">="
117
123
  - !ruby/object:Gem::Version
118
- version: '10.0'
119
- type: :development
124
+ version: 0.5.1
125
+ type: :runtime
120
126
  prerelease: false
121
127
  version_requirements: !ruby/object:Gem::Requirement
122
128
  requirements:
123
- - - "~>"
129
+ - - ">="
124
130
  - !ruby/object:Gem::Version
125
- version: '10.0'
131
+ version: 0.5.1
126
132
  description: RSpec matches for Mongoid models, including association and validation
127
133
  matchers.
128
134
  email: evansagge@gmail.com contato@rodrigopinto.me
@@ -160,33 +166,12 @@ files:
160
166
  - lib/mongoid-rspec.rb
161
167
  - lib/mongoid/rspec.rb
162
168
  - lib/mongoid/rspec/version.rb
163
- - spec/models/article.rb
164
- - spec/models/comment.rb
165
- - spec/models/log.rb
166
- - spec/models/message.rb
167
- - spec/models/movie_article.rb
168
- - spec/models/permalink.rb
169
- - spec/models/person.rb
170
- - spec/models/profile.rb
171
- - spec/models/record.rb
172
- - spec/models/site.rb
173
- - spec/models/user.rb
174
- - spec/spec_helper.rb
175
- - spec/unit/accept_nested_attributes_spec.rb
176
- - spec/unit/associations_spec.rb
177
- - spec/unit/be_dynamic_document_spec.rb
178
- - spec/unit/be_mongoid_document_spec.rb
179
- - spec/unit/be_stored_in.rb
180
- - spec/unit/document_spec.rb
181
- - spec/unit/have_index_for_spec.rb
182
- - spec/unit/have_timestamps_spec.rb
183
- - spec/unit/validations_spec.rb
184
- - spec/validators/ssn_validator.rb
185
169
  homepage: http://github.com/mongoid-rspec/mongoid-rspec
186
170
  licenses:
187
171
  - MIT
188
- metadata: {}
189
- post_install_message:
172
+ metadata:
173
+ rubygems_mfa_required: 'true'
174
+ post_install_message:
190
175
  rdoc_options: []
191
176
  require_paths:
192
177
  - lib
@@ -194,37 +179,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
194
179
  requirements:
195
180
  - - ">="
196
181
  - !ruby/object:Gem::Version
197
- version: '2.2'
182
+ version: '2.6'
198
183
  required_rubygems_version: !ruby/object:Gem::Requirement
199
184
  requirements:
200
185
  - - ">="
201
186
  - !ruby/object:Gem::Version
202
187
  version: 1.3.6
203
188
  requirements: []
204
- rubygems_version: 3.1.3
205
- signing_key:
189
+ rubygems_version: 3.5.10
190
+ signing_key:
206
191
  specification_version: 4
207
192
  summary: RSpec matchers for Mongoid
208
- test_files:
209
- - spec/spec_helper.rb
210
- - spec/unit/associations_spec.rb
211
- - spec/unit/be_dynamic_document_spec.rb
212
- - spec/unit/validations_spec.rb
213
- - spec/unit/be_stored_in.rb
214
- - spec/unit/have_index_for_spec.rb
215
- - spec/unit/accept_nested_attributes_spec.rb
216
- - spec/unit/document_spec.rb
217
- - spec/unit/be_mongoid_document_spec.rb
218
- - spec/unit/have_timestamps_spec.rb
219
- - spec/models/article.rb
220
- - spec/models/movie_article.rb
221
- - spec/models/record.rb
222
- - spec/models/site.rb
223
- - spec/models/message.rb
224
- - spec/models/permalink.rb
225
- - spec/models/profile.rb
226
- - spec/models/comment.rb
227
- - spec/models/person.rb
228
- - spec/models/log.rb
229
- - spec/models/user.rb
230
- - spec/validators/ssn_validator.rb
193
+ test_files: []
@@ -1,32 +0,0 @@
1
- class Article
2
- include Mongoid::Document
3
- include Mongoid::Timestamps
4
-
5
- field :title, localize: true
6
- field :content
7
- field :published, type: Boolean, default: false
8
- field :allow_comments, type: Boolean, default: true
9
- field :number_of_comments, type: Integer
10
- field :status, type: Symbol
11
- field :deletion_date, type: DateTime, default: nil
12
-
13
- embeds_many :comments, cascade_callbacks: true, inverse_of: :article
14
- embeds_one :permalink, inverse_of: :linkable
15
- belongs_to :author, class_name: 'User', inverse_of: :articles, index: true
16
-
17
- validates :title, presence: true
18
-
19
- validates_inclusion_of :status, in: [:pending], on: :create
20
- validates_inclusion_of :status, in: %i[approved rejected], on: :update
21
-
22
- validates_length_of :title, within: 8..16
23
- validates_length_of :content, minimum: 200
24
-
25
- validates_absence_of :deletion_date if Mongoid::Compatibility::Version.mongoid4_or_newer?
26
-
27
- index({ title: 1 }, unique: true, background: true, drop_dups: true)
28
- index(published: 1)
29
- index('permalink._id' => 1)
30
-
31
- accepts_nested_attributes_for :permalink
32
- end
@@ -1,6 +0,0 @@
1
- class Comment
2
- include Mongoid::Document
3
-
4
- embedded_in :article, inverse_of: :comments, polymorphic: true
5
- belongs_to :user, inverse_of: :comments
6
- end
data/spec/models/log.rb DELETED
@@ -1,9 +0,0 @@
1
- class Log
2
- include Mongoid::Document
3
- include Mongoid::Timestamps
4
- include Mongoid::Attributes::Dynamic if Mongoid::Compatibility::Version.mongoid4_or_newer?
5
-
6
- store_in collection: 'logs'
7
-
8
- index({ created_at: 1 }, bucket_size: 100, expire_after_seconds: 3600)
9
- end
@@ -1,17 +0,0 @@
1
- class Message
2
- include Mongoid::Document
3
-
4
- field :identifier
5
- field :from
6
- field :to
7
-
8
- if Mongoid::Compatibility::Version.mongoid6_or_newer?
9
- belongs_to :user, optional: true
10
- else
11
- belongs_to :user
12
- end
13
-
14
- validates :identifier, uniqueness: { message: 'uniqueness' }
15
- validates :from, presence: { message: 'required' }
16
- validates :to, format: { with: /[a-z]+/, message: 'format' }
17
- end
@@ -1,7 +0,0 @@
1
- class MovieArticle < Article
2
- field :rating, type: Float
3
- field :classification, type: Integer
4
-
5
- validates :rating, numericality: { greater_than: 0, less_than_or_equal_to: 5 }
6
- validates :classification, numericality: { even: true, only_integer: true, allow_nil: false }
7
- end
@@ -1,5 +0,0 @@
1
- class Permalink
2
- include Mongoid::Document
3
-
4
- embedded_in :linkable, inverse_of: :link
5
- end
@@ -1,10 +0,0 @@
1
- require 'ssn_validator.rb'
2
-
3
- class Person
4
- include Mongoid::Document
5
-
6
- field :name
7
- field :ssn
8
-
9
- validates :ssn, ssn: true
10
- end
@@ -1,16 +0,0 @@
1
- class Profile
2
- include Mongoid::Document
3
-
4
- field :first_name
5
- field :last_name
6
- field :age
7
- field :hobbies, type: Array, default: []
8
-
9
- embedded_in :user, inverse_of: :profile
10
-
11
- validates :age, numericality: { greater_than: 0 }
12
- validates :terms_of_service, acceptance: true
13
- validates :hobbies, length: { minimum: 1, message: 'requires at least one hobby' }
14
-
15
- index(first_name: 1, last_name: 1)
16
- end
@@ -1,5 +0,0 @@
1
- class Record
2
- include Mongoid::Document
3
-
4
- belongs_to :user, inverse_of: :record
5
- end
data/spec/models/site.rb DELETED
@@ -1,13 +0,0 @@
1
- class Site
2
- include Mongoid::Document
3
-
4
- field :name
5
-
6
- if Mongoid::Compatibility::Version.mongoid6_or_older?
7
- has_many :users, inverse_of: :site, order: :email.desc, counter_cache: true
8
- else
9
- has_many :users, inverse_of: :site, order: :email.desc
10
- end
11
-
12
- validates :name, presence: true, uniqueness: true
13
- end
data/spec/models/user.rb DELETED
@@ -1,38 +0,0 @@
1
- class User
2
- include Mongoid::Document
3
- include Mongoid::Timestamps::Created
4
-
5
- field :login
6
- field :email
7
- field :role
8
- field :age, type: Integer
9
- field :password, type: String
10
- field :provider_uid
11
- field :locale
12
-
13
- belongs_to :site, inverse_of: :users
14
- has_many :articles, foreign_key: :author_id, order: :title
15
- has_many :comments, dependent: :destroy, autosave: true
16
- has_many :messages, dependent: :destroy
17
- has_and_belongs_to_many :children, class_name: 'User'
18
- has_one :record, autobuild: true, inverse_of: :user
19
-
20
- embeds_one :profile, inverse_of: :user
21
-
22
- validates :login, presence: true, uniqueness: { scope: :site }, format: { with: /\A[\w\-]+\z/ }, exclusion: { in: %w[super index edit] }
23
- validates :email, uniqueness: { case_sensitive: false, scope: :site, message: 'is already taken' }, confirmation: true
24
- validates :role, presence: true, inclusion: { in: %w[admin moderator member] }
25
- validates :profile, presence: true, associated: true
26
- validates :age, presence: true, numericality: true, inclusion: { in: 23..42 }, on: %i[create update]
27
- validates :password, presence: true, on: %i[create update]
28
- validates :password, exclusion: { in: ->(_user) { ['password'] } }
29
- validates :password, confirmation: { message: 'Password confirmation must match given password' }
30
- validates :provider_uid, presence: true
31
- validates :locale, inclusion: { in: ->(_user) { %i[en ru] } }
32
-
33
- accepts_nested_attributes_for :articles, :comments
34
-
35
- def admin?
36
- false
37
- end
38
- end
data/spec/spec_helper.rb DELETED
@@ -1,35 +0,0 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
3
- MODELS = File.join(File.dirname(__FILE__), 'models')
4
- $LOAD_PATH.unshift(MODELS)
5
- VALIDATORS = File.join(File.dirname(__FILE__), 'validators')
6
- $LOAD_PATH.unshift(VALIDATORS)
7
-
8
- require 'rubygems'
9
- require 'bundler'
10
- Bundler.setup
11
-
12
- require 'mongoid'
13
- require 'rspec/core'
14
- require 'rspec/expectations'
15
- require 'mongoid/compatibility'
16
-
17
- Mongoid::Config.connect_to('mongoid-rspec-test') if Mongoid::Compatibility::Version.mongoid3_or_newer?
18
- Mongo::Logger.logger.level = ::Logger::INFO if Mongoid::Compatibility::Version.mongoid5_or_newer?
19
-
20
- Dir[File.join(MODELS, '*.rb')].sort.each { |file| require File.basename(file) }
21
-
22
- require 'mongoid-rspec'
23
-
24
- RSpec.configure do |config|
25
- config.include RSpec::Matchers
26
- config.include Mongoid::Matchers
27
- config.mock_with :rspec
28
- config.after :all do
29
- Mongoid::Config.purge!
30
- end
31
- config.after :suite do
32
- print "\n# Mongoid v#{Mongoid::VERSION}"
33
- end
34
- config.disable_monkey_patching!
35
- end
@@ -1,12 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe 'AcceptsNestedAttributes' do
4
- describe User do
5
- it { is_expected.to accept_nested_attributes_for(:articles) }
6
- it { is_expected.to accept_nested_attributes_for(:comments) }
7
- end
8
-
9
- describe Article do
10
- it { is_expected.to accept_nested_attributes_for(:permalink) }
11
- end
12
- end
@@ -1,54 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe 'Associations' do
4
- describe User do
5
- if Mongoid::Compatibility::Version.mongoid6_or_newer?
6
- it { is_expected.to have_many(:articles).with_foreign_key(:author_id).ordered_by(:title) }
7
- end
8
-
9
- it { is_expected.to have_one(:record).as_inverse_of(:user).with_autobuild }
10
-
11
- it { is_expected.to have_many(:comments).with_dependent(:destroy).with_autosave }
12
-
13
- it { is_expected.to embed_one(:profile).as_inverse_of(:user) }
14
-
15
- it { is_expected.to have_and_belong_to_many(:children).of_type(User) }
16
- end
17
-
18
- describe Profile do
19
- it { is_expected.to be_embedded_in(:user).as_inverse_of(:profile) }
20
- end
21
-
22
- describe Article do
23
- it { is_expected.to belong_to(:author).of_type(User).as_inverse_of(:articles).with_index }
24
- it { is_expected.to embed_many(:comments).as_inverse_of(:article).with_cascading_callbacks }
25
- it { is_expected.to embed_one(:permalink).as_inverse_of(:linkable) }
26
- end
27
-
28
- describe Comment do
29
- it { is_expected.to be_embedded_in(:article).as_inverse_of(:comments).with_polymorphism }
30
- it { is_expected.to belong_to(:user).as_inverse_of(:comments) }
31
- end
32
-
33
- describe Record do
34
- it { is_expected.to belong_to(:user).as_inverse_of(:record) }
35
- end
36
-
37
- describe Permalink do
38
- it { is_expected.to be_embedded_in(:linkable).as_inverse_of(:link) }
39
- end
40
-
41
- describe Site do
42
- if Mongoid::Compatibility::Version.mongoid6_or_older?
43
- it { is_expected.to have_many(:users).as_inverse_of(:site).ordered_by(:email.desc).with_counter_cache }
44
- elsif Mongoid::Compatibility::Version.mongoid7_or_newer?
45
- it { is_expected.to have_many(:users).as_inverse_of(:site).ordered_by(:email.desc) }
46
- end
47
- end
48
-
49
- describe Message do
50
- if Mongoid::Compatibility::Version.mongoid6_or_newer?
51
- it { is_expected.to belong_to(:user).with_optional }
52
- end
53
- end
54
- end
@@ -1,21 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Mongoid::Matchers::BeDynamicDocument do
4
- context 'when model does\'t include Mongoid::Document' do
5
- subject do
6
- Class.new
7
- end
8
-
9
- it { is_expected.not_to be_mongoid_document }
10
- end
11
-
12
- context 'when model doesn\'t include Mongoid::Document' do
13
- subject do
14
- Class.new do
15
- include Mongoid::Document
16
- end
17
- end
18
-
19
- it { is_expected.to be_mongoid_document }
20
- end
21
- end
@@ -1,25 +0,0 @@
1
- require 'spec_helper'
2
- if Mongoid::Compatibility::Version.mongoid4_or_newer?
3
- RSpec.describe Mongoid::Matchers::BeMongoidDocument do
4
- context 'when model does\'t include Mongoid::Attributes::Dynamic' do
5
- subject do
6
- Class.new do
7
- include Mongoid::Document
8
- end
9
- end
10
-
11
- it { is_expected.not_to be_dynamic_document }
12
- end
13
-
14
- context 'when model doesn\'t include Mongoid::Attributes::Dynamic' do
15
- subject do
16
- Class.new do
17
- include Mongoid::Document
18
- include Mongoid::Attributes::Dynamic
19
- end
20
- end
21
-
22
- it { is_expected.to be_dynamic_document }
23
- end
24
- end
25
- end
@@ -1,54 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Mongoid::Matchers::BeStoredIn do
4
- subject do
5
- Class.new do
6
- include Mongoid::Document
7
- store_in collection: 'citizens', database: 'other', client: 'secondary'
8
- end
9
- end
10
-
11
- it 'detects storage options' do
12
- is_expected.to be_stored_in(collection: 'citizens', database: 'other', client: 'secondary')
13
- end
14
-
15
- it 'detects even part of storage options' do
16
- is_expected.to be_stored_in(database: 'other')
17
- is_expected.to be_stored_in(client: 'secondary')
18
- is_expected.to be_stored_in(collection: 'citizens')
19
- is_expected.to be_stored_in(collection: 'citizens', database: 'other')
20
- is_expected.to be_stored_in(database: 'other', client: 'secondary')
21
- is_expected.to be_stored_in(collection: 'citizens', client: 'secondary')
22
- end
23
-
24
- it 'detects differences' do
25
- is_expected.not_to be_stored_in(collection: 'aliens')
26
- end
27
-
28
- context 'when models has storage options defined via blocks, procs or lambdas' do
29
- subject do
30
- Class.new do
31
- include Mongoid::Document
32
- store_in database: -> { Thread.current[:database] }
33
- end
34
- end
35
-
36
- before do
37
- Thread.current[:database] = 'db1981'
38
- end
39
-
40
- it 'detects storage options' do
41
- is_expected.to be_stored_in(database: 'db1981')
42
- end
43
-
44
- it 'reflects changes in storage options' do
45
- is_expected.to be_stored_in(database: 'db1981')
46
- Thread.current[:database] = 'db2200'
47
- is_expected.to be_stored_in(database: 'db2200')
48
- end
49
-
50
- it 'detects differences' do
51
- is_expected.not_to be_stored_in(database: 'other')
52
- end
53
- end
54
- end
@@ -1,17 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe 'Document' do
4
- describe User do
5
- it { is_expected.to have_fields(:email, :login) }
6
- end
7
-
8
- describe Article do
9
- klass_boolean = Mongoid::Compatibility::Version.mongoid4_or_newer? ? Mongoid::Boolean : Boolean
10
- it { is_expected.to have_field(:published).of_type(klass_boolean).with_default_value_of(false) }
11
- it { is_expected.to have_field(:allow_comments).of_type(klass_boolean).with_default_value_of(true) }
12
- it { is_expected.to belong_to(:author) }
13
- it { is_expected.to have_field(:title).localized }
14
- it { is_expected.not_to have_field(:allow_comments).of_type(klass_boolean).with_default_value_of(false) }
15
- it { is_expected.not_to have_field(:number_of_comments).of_type(Integer).with_default_value_of(1) }
16
- end
17
- end
@@ -1,46 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Mongoid::Matchers::HaveIndexFor do
4
- subject do
5
- Class.new do
6
- include Mongoid::Document
7
-
8
- field :fizz, as: :buzz, type: String
9
-
10
- index(foo: 1)
11
- index({ bar: 1 }, unique: true, background: true, drop_dups: true)
12
- index(foo: 1, bar: -1)
13
- index('baz._id' => 1)
14
- index(buzz: 1)
15
- end
16
- end
17
-
18
- it 'detects an index for singular field key' do
19
- is_expected.to have_index_for(foo: 1)
20
- end
21
-
22
- it 'detects an index for multipple fields key' do
23
- is_expected.to have_index_for(foo: 1, bar: -1)
24
- end
25
-
26
- it 'detects an index with options' do
27
- is_expected
28
- .to have_index_for(bar: 1)
29
- .with_options(unique: true, background: true, drop_dups: true)
30
- end
31
-
32
- it 'detects an index with only part of options' do
33
- is_expected
34
- .to have_index_for(bar: 1)
35
- .with_options(unique: true)
36
- end
37
-
38
- it 'detects an index for string key' do
39
- is_expected.to have_index_for('baz._id' => 1)
40
- end
41
-
42
- it 'detect an index for aliased fields' do
43
- is_expected.to have_index_for(fizz: 1)
44
- is_expected.to have_index_for(buzz: 1) if Mongoid::Compatibility::Version.mongoid4_or_newer?
45
- end
46
- end
@@ -1,71 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Mongoid::Matchers::HaveTimestamps do
4
- context 'when model includes Mongoid::Timestamps' do
5
- subject do
6
- Class.new do
7
- include Mongoid::Document
8
- include Mongoid::Timestamps
9
- end
10
- end
11
-
12
- it { is_expected.to have_timestamps }
13
- end
14
-
15
- context 'when model includes Mongoid::Timestamps::Short' do
16
- subject do
17
- Class.new do
18
- include Mongoid::Document
19
- include Mongoid::Timestamps::Short
20
- end
21
- end
22
-
23
- it { is_expected.to have_timestamps.shortened }
24
- end
25
-
26
- context 'when model includes Mongoid::Timestamps::Updated' do
27
- subject do
28
- Class.new do
29
- include Mongoid::Document
30
- include Mongoid::Timestamps::Updated
31
- end
32
- end
33
-
34
- it { is_expected.to have_timestamps.for(:updating) }
35
- end
36
-
37
- context 'when model includes Mongoid::Timestamps::Updated::Short' do
38
- subject do
39
- Class.new do
40
- include Mongoid::Document
41
- include Mongoid::Timestamps::Updated::Short
42
- end
43
- end
44
-
45
- it { is_expected.to have_timestamps.for(:updating).shortened }
46
- it { is_expected.to have_timestamps.shortened.for(:updating) }
47
- end
48
-
49
- context 'when model includes Mongoid::Timestamps::Created' do
50
- subject do
51
- Class.new do
52
- include Mongoid::Document
53
- include Mongoid::Timestamps::Created
54
- end
55
- end
56
-
57
- it { is_expected.to have_timestamps.for(:creating) }
58
- end
59
-
60
- context 'when model includes Mongoid::Timestamps::Created::Short' do
61
- subject do
62
- Class.new do
63
- include Mongoid::Document
64
- include Mongoid::Timestamps::Created::Short
65
- end
66
- end
67
-
68
- it { is_expected.to have_timestamps.for(:creating).shortened }
69
- it { is_expected.to have_timestamps.shortened.for(:creating) }
70
- end
71
- end
@@ -1,61 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe 'Validations' do
4
- describe Site do
5
- it { is_expected.to validate_presence_of(:name) }
6
- it { is_expected.to validate_uniqueness_of(:name) }
7
- end
8
-
9
- describe User do
10
- it { is_expected.to validate_presence_of(:login) }
11
- it { is_expected.to validate_uniqueness_of(:login).scoped_to(:site) }
12
- it { is_expected.to validate_uniqueness_of(:email).case_insensitive.with_message('is already taken') }
13
- it { is_expected.to validate_format_of(:login).to_allow('valid_login').not_to_allow('invalid login') }
14
- it { is_expected.to validate_associated(:profile) }
15
- it { is_expected.to validate_exclusion_of(:login).to_not_allow('super', 'index', 'edit') }
16
- it { is_expected.to validate_exclusion_of(:password).to_not_allow('password') }
17
- it { is_expected.to validate_inclusion_of(:role).to_allow('admin', 'member') }
18
- it { is_expected.to validate_inclusion_of(:role).to_allow(%w[admin member]) }
19
- it { is_expected.to validate_confirmation_of(:email) }
20
- it { is_expected.to validate_presence_of(:age).on(:create, :update) }
21
- it { is_expected.to validate_numericality_of(:age).on(:create, :update) }
22
- it { is_expected.to validate_inclusion_of(:age).to_allow(23..42).on(%i[create update]) }
23
- it { is_expected.to validate_presence_of(:password).on(:create) }
24
- it { is_expected.to validate_confirmation_of(:password).with_message('Password confirmation must match given password') }
25
- it { is_expected.to validate_presence_of(:provider_uid).on(:create) }
26
- it { is_expected.to validate_inclusion_of(:locale).to_allow(%i[en ru]) }
27
- end
28
-
29
- describe Profile do
30
- it { is_expected.to validate_numericality_of(:age).greater_than(0) }
31
- it { is_expected.not_to validate_numericality_of(:age).greater_than(0).only_integer(true) }
32
- it { is_expected.to validate_acceptance_of(:terms_of_service) }
33
- it { is_expected.to validate_length_of(:hobbies).with_minimum(1).with_message('requires at least one hobby') }
34
- end
35
-
36
- describe Article do
37
- it { is_expected.to validate_length_of(:title).within(8..16) }
38
- it { is_expected.not_to validate_length_of(:content).greater_than(200).less_than(16) }
39
- it { is_expected.to validate_length_of(:content).greater_than(200) }
40
- it { is_expected.to validate_inclusion_of(:status).to_allow([:pending]).on(:create) }
41
- it { is_expected.to validate_inclusion_of(:status).to_allow(%i[approved rejected]).on(:update) }
42
- it { is_expected.to validate_absence_of(:deletion_date) } if Mongoid::Compatibility::Version.mongoid4_or_newer?
43
- end
44
-
45
- describe MovieArticle do
46
- it { is_expected.to validate_numericality_of(:rating).greater_than(0) }
47
- it { is_expected.to validate_numericality_of(:rating).to_allow(greater_than: 0).less_than_or_equal_to(5) }
48
- it { is_expected.to validate_numericality_of(:classification).to_allow(even: true, only_integer: true, nil: false) }
49
- end
50
-
51
- describe Person do
52
- it { is_expected.to custom_validate(:ssn).with_validator(SsnValidator) }
53
- it { is_expected.not_to custom_validate(:name) }
54
- end
55
-
56
- describe Message do
57
- it { is_expected.to validate_uniqueness_of(:identifier).with_message('uniqueness') }
58
- it { is_expected.to validate_presence_of(:from).with_message('required') }
59
- it { is_expected.to validate_format_of(:to).with_message('format') }
60
- end
61
- end
@@ -1,16 +0,0 @@
1
- class SsnValidator < ActiveModel::EachValidator
2
- def validate_each(record, attribute, value)
3
- unless valid_ssn?(record, attribute, value)
4
- record.errors[attribute] << "#{value} is not a valid Social Security Number"
5
- end
6
- end
7
-
8
- def self.kind
9
- :custom
10
- end
11
-
12
- def valid_ssn?(_record, _attribute, _value)
13
- # irrelevant here how validation is done
14
- true
15
- end
16
- end