mongoid-rspec 4.0.1 → 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
- SHA1:
3
- metadata.gz: 801c33ba9bd350eeb1595c57509601084b983ae5
4
- data.tar.gz: 1f47a9a328b9d58e5cdaaebf7dbfd91420ed4ca7
2
+ SHA256:
3
+ metadata.gz: 711f91347b02d3d6982a72b6946bb781ea07dba16f858109da01166c7a768ecf
4
+ data.tar.gz: 58e81131678e670e5a7b63385122fa316afadb18d49749c3544a4e5e1898d3fc
5
5
  SHA512:
6
- metadata.gz: 91cf1c6e8b0d356bbece0657fe9f5cf1df218f8ec5fa9171a96dd2cef02781654390bcd47f6bea9e62192564d144c1489541dcb54bcc016c596e73578f1b4d18
7
- data.tar.gz: af5c81412000da22a464b6982dab00e652b34c052ca46cc3fb596439c3e7dde204851b769dbd28b788ffcd67e2331dc847455b613b226ae2cf2a7e2f2a4a0d82
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) }
@@ -261,6 +289,10 @@ end
261
289
  RSpec.describe Site do
262
290
  it { is_expected.to have_many(:users).as_inverse_of(:site).ordered_by(:email.asc).with_counter_cache }
263
291
  end
292
+
293
+ RSpec.describe Message do
294
+ it { is_expected.to belong_to(:user).with_optional }
295
+ end
264
296
  ```
265
297
 
266
298
  ### Validation Matchers
@@ -311,6 +343,22 @@ RSpec.describe Person do
311
343
  # should redefine the kind method to return :custom, i.e. "def self.kind() :custom end"
312
344
  it { is_expected.to custom_validate(:ssn).with_validator(SsnValidator) }
313
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
314
362
  ```
315
363
 
316
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]
@@ -51,7 +51,7 @@ module Mongoid
51
51
  @association[:order] = association_field_name.to_s
52
52
  @expectation_message << " ordered by #{@association[:order].inspect}"
53
53
 
54
- if association_field_name.is_a? Mongoid::Criteria::Queryable::Key
54
+ if association_field_name.is_a? association_kind_of
55
55
  @association[:order_operator] = association_field_name.operator
56
56
  @expectation_message << " #{order_way(@association[:order_operator])}"
57
57
  end
@@ -119,6 +119,18 @@ 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
+
128
+ def with_optional
129
+ @association[:optional] = true
130
+ @expectation_message << " which specifies optional as #{@association[:optional]}"
131
+ self
132
+ end
133
+
122
134
  def matches?(actual)
123
135
  @actual = actual.is_a?(Class) ? actual : actual.class
124
136
  metadata = @actual.relations[@association[:name]]
@@ -266,6 +278,24 @@ module Mongoid
266
278
  end
267
279
  end
268
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
+
290
+ if @association[:optional]
291
+ if metadata.options[:optional] != true
292
+ @negative_result_message = "#{@positive_result_message} which did not set optional"
293
+ return false
294
+ else
295
+ @positive_result_message = "#{@positive_result_message} which set optional"
296
+ end
297
+ end
298
+
269
299
  true
270
300
  end
271
301
 
@@ -311,6 +341,10 @@ module Mongoid
311
341
  def order_way(operator)
312
342
  [nil, 'ascending', 'descending'][operator]
313
343
  end
344
+
345
+ def association_kind_of
346
+ Mongoid::Compatibility::Version.mongoid5_or_older? ? Origin::Key : Mongoid::Criteria::Queryable::Key
347
+ end
314
348
  end
315
349
 
316
350
  def embed_one(association_name)
@@ -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.0.1'.freeze
3
+ VERSION = '4.2.0'.freeze
4
4
  end
5
5
  end
data/lib/mongoid/rspec.rb CHANGED
@@ -6,7 +6,7 @@ require 'rspec/core'
6
6
  require 'rspec/expectations'
7
7
  require 'rspec/mocks'
8
8
  require 'active_support/core_ext/hash/keys'
9
- require 'active_support/core_ext/hash/transform_values' if Mongoid::Compatibility::Version.mongoid4_or_newer?
9
+ require 'active_support/core_ext/hash/transform_values' if Mongoid::Compatibility::Version.mongoid4_or_newer? && ActiveSupport.version < Gem::Version.new('6')
10
10
  require 'active_support/core_ext/object/blank'
11
11
  require 'active_support/core_ext/string/inflections'
12
12
 
metadata CHANGED
@@ -1,70 +1,118 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.1
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: 2018-06-18 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
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '2.0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '2.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: mongoid-danger
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '0.2'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '0.2'
42
+ - !ruby/object:Gem::Dependency
43
+ name: pry
16
44
  requirement: !ruby/object:Gem::Requirement
17
45
  requirements:
18
46
  - - ">="
19
47
  - !ruby/object:Gem::Version
20
- version: 3.0.0
21
- type: :runtime
48
+ version: '0'
49
+ type: :development
22
50
  prerelease: false
23
51
  version_requirements: !ruby/object:Gem::Requirement
24
52
  requirements:
25
53
  - - ">="
26
54
  - !ruby/object:Gem::Version
27
- version: 3.0.0
55
+ version: '0'
28
56
  - !ruby/object:Gem::Dependency
29
- name: mongoid
57
+ name: rails
30
58
  requirement: !ruby/object:Gem::Requirement
31
59
  requirements:
32
60
  - - ">="
33
61
  - !ruby/object:Gem::Version
34
- version: '3.1'
35
- type: :runtime
62
+ version: '0'
63
+ type: :development
36
64
  prerelease: false
37
65
  version_requirements: !ruby/object:Gem::Requirement
38
66
  requirements:
39
67
  - - ">="
40
68
  - !ruby/object:Gem::Version
41
- version: '3.1'
69
+ version: '0'
42
70
  - !ruby/object:Gem::Dependency
43
71
  name: rspec
44
72
  requirement: !ruby/object:Gem::Requirement
45
73
  requirements:
46
- - - "~>"
74
+ - - ">="
47
75
  - !ruby/object:Gem::Version
48
- version: '3.3'
49
- type: :runtime
76
+ version: '0'
77
+ type: :development
50
78
  prerelease: false
51
79
  version_requirements: !ruby/object:Gem::Requirement
52
80
  requirements:
53
- - - "~>"
81
+ - - ">="
54
82
  - !ruby/object:Gem::Version
55
- version: '3.3'
83
+ version: '0'
56
84
  - !ruby/object:Gem::Dependency
57
- name: rake
85
+ name: rubocop
58
86
  requirement: !ruby/object:Gem::Requirement
59
87
  requirements:
60
88
  - - "~>"
61
89
  - !ruby/object:Gem::Version
62
- version: '10.0'
90
+ version: 1.36.0
63
91
  type: :development
64
92
  prerelease: false
65
93
  version_requirements: !ruby/object:Gem::Requirement
66
94
  requirements:
67
95
  - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: 1.36.0
98
+ - !ruby/object:Gem::Dependency
99
+ name: mongoid
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '3.0'
105
+ - - "<"
106
+ - !ruby/object:Gem::Version
107
+ version: '10.0'
108
+ type: :runtime
109
+ prerelease: false
110
+ version_requirements: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '3.0'
115
+ - - "<"
68
116
  - !ruby/object:Gem::Version
69
117
  version: '10.0'
70
118
  - !ruby/object:Gem::Dependency
@@ -118,33 +166,12 @@ files:
118
166
  - lib/mongoid-rspec.rb
119
167
  - lib/mongoid/rspec.rb
120
168
  - lib/mongoid/rspec/version.rb
121
- - spec/models/article.rb
122
- - spec/models/comment.rb
123
- - spec/models/log.rb
124
- - spec/models/message.rb
125
- - spec/models/movie_article.rb
126
- - spec/models/permalink.rb
127
- - spec/models/person.rb
128
- - spec/models/profile.rb
129
- - spec/models/record.rb
130
- - spec/models/site.rb
131
- - spec/models/user.rb
132
- - spec/spec_helper.rb
133
- - spec/unit/accept_nested_attributes_spec.rb
134
- - spec/unit/associations_spec.rb
135
- - spec/unit/be_dynamic_document_spec.rb
136
- - spec/unit/be_mongoid_document_spec.rb
137
- - spec/unit/be_stored_in.rb
138
- - spec/unit/document_spec.rb
139
- - spec/unit/have_index_for_spec.rb
140
- - spec/unit/have_timestamps_spec.rb
141
- - spec/unit/validations_spec.rb
142
- - spec/validators/ssn_validator.rb
143
169
  homepage: http://github.com/mongoid-rspec/mongoid-rspec
144
170
  licenses:
145
171
  - MIT
146
- metadata: {}
147
- post_install_message:
172
+ metadata:
173
+ rubygems_mfa_required: 'true'
174
+ post_install_message:
148
175
  rdoc_options: []
149
176
  require_paths:
150
177
  - lib
@@ -152,38 +179,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
152
179
  requirements:
153
180
  - - ">="
154
181
  - !ruby/object:Gem::Version
155
- version: '2.2'
182
+ version: '2.6'
156
183
  required_rubygems_version: !ruby/object:Gem::Requirement
157
184
  requirements:
158
185
  - - ">="
159
186
  - !ruby/object:Gem::Version
160
187
  version: 1.3.6
161
188
  requirements: []
162
- rubyforge_project: mongoid-rspec
163
- rubygems_version: 2.6.13
164
- signing_key:
189
+ rubygems_version: 3.5.10
190
+ signing_key:
165
191
  specification_version: 4
166
192
  summary: RSpec matchers for Mongoid
167
- test_files:
168
- - spec/models/article.rb
169
- - spec/models/comment.rb
170
- - spec/models/log.rb
171
- - spec/models/message.rb
172
- - spec/models/movie_article.rb
173
- - spec/models/permalink.rb
174
- - spec/models/person.rb
175
- - spec/models/profile.rb
176
- - spec/models/record.rb
177
- - spec/models/site.rb
178
- - spec/models/user.rb
179
- - spec/spec_helper.rb
180
- - spec/unit/accept_nested_attributes_spec.rb
181
- - spec/unit/associations_spec.rb
182
- - spec/unit/be_dynamic_document_spec.rb
183
- - spec/unit/be_mongoid_document_spec.rb
184
- - spec/unit/be_stored_in.rb
185
- - spec/unit/document_spec.rb
186
- - spec/unit/have_index_for_spec.rb
187
- - spec/unit/have_timestamps_spec.rb
188
- - spec/unit/validations_spec.rb
189
- - 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,11 +0,0 @@
1
- class Message
2
- include Mongoid::Document
3
-
4
- field :identifier
5
- field :from
6
- field :to
7
-
8
- validates :identifier, uniqueness: { message: 'uniqueness' }
9
- validates :from, presence: { message: 'required' }
10
- validates :to, format: { with: /[a-z]+/, message: 'format' }
11
- 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,37 +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_and_belongs_to_many :children, class_name: 'User'
17
- has_one :record, autobuild: true, inverse_of: :user
18
-
19
- embeds_one :profile, inverse_of: :user
20
-
21
- validates :login, presence: true, uniqueness: { scope: :site }, format: { with: /\A[\w\-]+\z/ }, exclusion: { in: %w[super index edit] }
22
- validates :email, uniqueness: { case_sensitive: false, scope: :site, message: 'is already taken' }, confirmation: true
23
- validates :role, presence: true, inclusion: { in: %w[admin moderator member] }
24
- validates :profile, presence: true, associated: true
25
- validates :age, presence: true, numericality: true, inclusion: { in: 23..42 }, on: %i[create update]
26
- validates :password, presence: true, on: %i[create update]
27
- validates :password, exclusion: { in: ->(_user) { ['password'] } }
28
- validates :password, confirmation: { message: 'Password confirmation must match given password' }
29
- validates :provider_uid, presence: true
30
- validates :locale, inclusion: { in: ->(_user) { %i[en ru] } }
31
-
32
- accepts_nested_attributes_for :articles, :comments
33
-
34
- def admin?
35
- false
36
- end
37
- end
data/spec/spec_helper.rb DELETED
@@ -1,36 +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'
14
- require 'rspec/core'
15
- require 'rspec/expectations'
16
- require 'mongoid/compatibility'
17
-
18
- Mongoid::Config.connect_to('mongoid-rspec-test') if Mongoid::Compatibility::Version.mongoid3_or_newer?
19
- Mongo::Logger.logger.level = ::Logger::INFO if Mongoid::Compatibility::Version.mongoid5_or_newer?
20
-
21
- Dir[File.join(MODELS, '*.rb')].sort.each { |file| require File.basename(file) }
22
-
23
- require 'mongoid-rspec'
24
-
25
- RSpec.configure do |config|
26
- config.include RSpec::Matchers
27
- config.include Mongoid::Matchers
28
- config.mock_with :rspec
29
- config.after :all do
30
- Mongoid::Config.purge!
31
- end
32
- config.after :suite do
33
- print "\n# Mongoid v#{Mongoid::VERSION}"
34
- end
35
- config.disable_monkey_patching!
36
- 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,48 +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?
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
- 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