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.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +373 -0
- data/Rakefile +17 -0
- data/lib/matchers/accept_nested_attributes.rb +67 -0
- data/lib/matchers/allow_mass_assignment.rb +102 -0
- data/lib/matchers/associations.rb +330 -0
- data/lib/matchers/be_dynamic_document.rb +26 -0
- data/lib/matchers/be_mongoid_document.rb +26 -0
- data/lib/matchers/be_stored_in.rb +50 -0
- data/lib/matchers/have_field.rb +90 -0
- data/lib/matchers/have_index_for.rb +63 -0
- data/lib/matchers/have_timestamps.rb +61 -0
- data/lib/matchers/validations.rb +81 -0
- data/lib/matchers/validations/acceptance_of.rb +9 -0
- data/lib/matchers/validations/associated.rb +19 -0
- data/lib/matchers/validations/confirmation_of.rb +22 -0
- data/lib/matchers/validations/custom_validation_of.rb +47 -0
- data/lib/matchers/validations/exclusion_of.rb +49 -0
- data/lib/matchers/validations/format_of.rb +71 -0
- data/lib/matchers/validations/inclusion_of.rb +49 -0
- data/lib/matchers/validations/length_of.rb +147 -0
- data/lib/matchers/validations/numericality_of.rb +90 -0
- data/lib/matchers/validations/presence_of.rb +9 -0
- data/lib/matchers/validations/uniqueness_of.rb +82 -0
- data/lib/matchers/validations/with_message.rb +27 -0
- data/lib/mongoid-rspec.rb +1 -0
- data/lib/mongoid/rspec.rb +40 -0
- data/lib/mongoid/rspec/version.rb +5 -0
- data/spec/models/article.rb +29 -0
- data/spec/models/comment.rb +6 -0
- data/spec/models/log.rb +9 -0
- data/spec/models/movie_article.rb +8 -0
- data/spec/models/permalink.rb +5 -0
- data/spec/models/person.rb +10 -0
- data/spec/models/profile.rb +16 -0
- data/spec/models/record.rb +5 -0
- data/spec/models/site.rb +9 -0
- data/spec/models/user.rb +37 -0
- data/spec/spec_helper.rb +35 -0
- data/spec/unit/accept_nested_attributes_spec.rb +12 -0
- data/spec/unit/associations_spec.rb +42 -0
- data/spec/unit/be_dynamic_document_spec.rb +22 -0
- data/spec/unit/be_mongoid_document_spec.rb +25 -0
- data/spec/unit/be_stored_in.rb +54 -0
- data/spec/unit/document_spec.rb +16 -0
- data/spec/unit/have_index_for_spec.rb +46 -0
- data/spec/unit/have_timestamps_spec.rb +71 -0
- data/spec/unit/validations_spec.rb +54 -0
- data/spec/validators/ssn_validator.rb +16 -0
- metadata +171 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Matchers
|
3
|
+
module Validations
|
4
|
+
module WithMessage
|
5
|
+
def with_message(message)
|
6
|
+
@expected_message = message
|
7
|
+
self
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def check_expected_message
|
13
|
+
actual_message = @validator.options[:message]
|
14
|
+
if actual_message.nil?
|
15
|
+
@negative_result_message << " with no custom message"
|
16
|
+
@result = false
|
17
|
+
elsif actual_message == @expected_message
|
18
|
+
@positive_result_message << " with custom message '#{@expected_message}'"
|
19
|
+
else
|
20
|
+
@negative_result_message << " got message '#{actual_message}'"
|
21
|
+
@result = false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'mongoid/rspec'
|
@@ -0,0 +1,40 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
require 'mongoid'
|
4
|
+
require 'rspec/core'
|
5
|
+
require 'rspec/expectations'
|
6
|
+
require 'rspec/mocks'
|
7
|
+
require 'active_support/core_ext/hash/keys'
|
8
|
+
require 'active_support/core_ext/hash/transform_values'
|
9
|
+
require 'active_support/core_ext/object/blank'
|
10
|
+
require 'active_support/core_ext/string/inflections'
|
11
|
+
|
12
|
+
require 'matchers/associations'
|
13
|
+
require 'matchers/allow_mass_assignment'
|
14
|
+
require 'matchers/accept_nested_attributes'
|
15
|
+
require 'matchers/validations'
|
16
|
+
require 'matchers/validations/with_message'
|
17
|
+
require 'matchers/validations/associated'
|
18
|
+
require 'matchers/validations/confirmation_of'
|
19
|
+
require 'matchers/validations/exclusion_of'
|
20
|
+
require 'matchers/validations/format_of'
|
21
|
+
require 'matchers/validations/inclusion_of'
|
22
|
+
require 'matchers/validations/length_of'
|
23
|
+
require 'matchers/validations/numericality_of'
|
24
|
+
require 'matchers/validations/presence_of'
|
25
|
+
require 'matchers/validations/uniqueness_of'
|
26
|
+
require 'matchers/validations/acceptance_of'
|
27
|
+
require 'matchers/validations/custom_validation_of'
|
28
|
+
require 'matchers/be_mongoid_document'
|
29
|
+
require 'matchers/be_dynamic_document'
|
30
|
+
require 'matchers/be_stored_in'
|
31
|
+
require 'matchers/have_field'
|
32
|
+
require 'matchers/have_index_for'
|
33
|
+
require 'matchers/have_timestamps'
|
34
|
+
|
35
|
+
module Mongoid
|
36
|
+
module Matchers
|
37
|
+
include Mongoid::Matchers::Associations
|
38
|
+
include Mongoid::Matchers::Validations
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,29 @@
|
|
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
|
+
|
12
|
+
embeds_many :comments, cascade_callbacks: true, inverse_of: :article
|
13
|
+
embeds_one :permalink, inverse_of: :linkable
|
14
|
+
belongs_to :author, class_name: 'User', inverse_of: :articles, index: true
|
15
|
+
|
16
|
+
validates :title, presence: true
|
17
|
+
|
18
|
+
validates_inclusion_of :status, in: [:pending], on: :create
|
19
|
+
validates_inclusion_of :status, in: [:approved, :rejected ], on: :update
|
20
|
+
|
21
|
+
validates_length_of :title, within: 8..16
|
22
|
+
validates_length_of :content, minimum: 200
|
23
|
+
|
24
|
+
index({ title: 1 }, { unique: true, background: true, drop_dups: true })
|
25
|
+
index({ published: 1 })
|
26
|
+
index({ 'permalink._id' => 1 })
|
27
|
+
|
28
|
+
accepts_nested_attributes_for :permalink
|
29
|
+
end
|
data/spec/models/log.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
class MovieArticle < Article
|
2
|
+
|
3
|
+
field :rating, type: Float
|
4
|
+
field :classification, type: Integer
|
5
|
+
|
6
|
+
validates :rating, numericality: { greater_than: 0, less_than_or_equal_to: 5 }
|
7
|
+
validates :classification, numericality: { even: true, only_integer: true, allow_nil: false }
|
8
|
+
end
|
@@ -0,0 +1,16 @@
|
|
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
|
data/spec/models/site.rb
ADDED
data/spec/models/user.rb
ADDED
@@ -0,0 +1,37 @@
|
|
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: ["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: ["admin", "moderator", "member"] }
|
24
|
+
validates :profile, presence: true, associated: true
|
25
|
+
validates :age, presence: true, numericality: true, inclusion: { in: 23..42 }, on: [:create, :update]
|
26
|
+
validates :password, presence: true, on: [: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) { [: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
ADDED
@@ -0,0 +1,35 @@
|
|
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
|
+
|
17
|
+
Mongoid::Config.connect_to('mongoid-rspec-test')
|
18
|
+
Mongo::Logger.logger.level = ::Logger::INFO
|
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
|
@@ -0,0 +1,12 @@
|
|
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
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe "Associations" do
|
4
|
+
describe User do
|
5
|
+
it { is_expected.to have_many(:articles).with_foreign_key(:author_id).ordered_by(:title) }
|
6
|
+
|
7
|
+
it { is_expected.to have_one(:record).as_inverse_of(:user).with_autobuild }
|
8
|
+
|
9
|
+
it { is_expected.to have_many(:comments).with_dependent(:destroy).with_autosave }
|
10
|
+
|
11
|
+
it { is_expected.to embed_one(:profile).as_inverse_of(:user) }
|
12
|
+
|
13
|
+
it { is_expected.to have_and_belong_to_many(:children).of_type(User) }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe Profile do
|
17
|
+
it { is_expected.to be_embedded_in(:user).as_inverse_of(:profile) }
|
18
|
+
end
|
19
|
+
|
20
|
+
describe Article do
|
21
|
+
it { is_expected.to belong_to(:author).of_type(User).as_inverse_of(:articles).with_index }
|
22
|
+
it { is_expected.to embed_many(:comments).as_inverse_of(:article).with_cascading_callbacks }
|
23
|
+
it { is_expected.to embed_one(:permalink).as_inverse_of(:linkable) }
|
24
|
+
end
|
25
|
+
|
26
|
+
describe Comment do
|
27
|
+
it { is_expected.to be_embedded_in(:article).as_inverse_of(:comments).with_polymorphism }
|
28
|
+
it { is_expected.to belong_to(:user).as_inverse_of(:comments) }
|
29
|
+
end
|
30
|
+
|
31
|
+
describe Record do
|
32
|
+
it { is_expected.to belong_to(:user).as_inverse_of(:record) }
|
33
|
+
end
|
34
|
+
|
35
|
+
describe Permalink do
|
36
|
+
it { is_expected.to be_embedded_in(:linkable).as_inverse_of(:link) }
|
37
|
+
end
|
38
|
+
|
39
|
+
describe Site do
|
40
|
+
it { is_expected.to have_many(:users).as_inverse_of(:site).ordered_by(:email.desc).with_counter_cache }
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,22 @@
|
|
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
|
+
|
13
|
+
context 'when model doesn\'t include Mongoid::Document' do
|
14
|
+
subject do
|
15
|
+
Class.new do
|
16
|
+
include Mongoid::Document
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it { is_expected.to be_mongoid_document }
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
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
|
+
|
15
|
+
context 'when model doesn\'t include Mongoid::Attributes::Dynamic' do
|
16
|
+
subject do
|
17
|
+
Class.new do
|
18
|
+
include Mongoid::Document
|
19
|
+
include Mongoid::Attributes::Dynamic
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it { is_expected.to be_dynamic_document }
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,54 @@
|
|
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
|
@@ -0,0 +1,16 @@
|
|
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
|
+
it { is_expected.to have_field(:published).of_type(Mongoid::Boolean).with_default_value_of(false) }
|
10
|
+
it { is_expected.to have_field(:allow_comments).of_type(Mongoid::Boolean).with_default_value_of(true) }
|
11
|
+
it { is_expected.to belong_to(:author) }
|
12
|
+
it { is_expected.to have_field(:title).localized }
|
13
|
+
it { is_expected.not_to have_field(:allow_comments).of_type(Mongoid::Boolean).with_default_value_of(false) }
|
14
|
+
it { is_expected.not_to have_field(:number_of_comments).of_type(Integer).with_default_value_of(1) }
|
15
|
+
end
|
16
|
+
end
|