mongoid4-rspec 1.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +6 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +21 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +207 -0
- data/Rakefile +17 -0
- data/lib/matchers/accept_nested_attributes.rb +67 -0
- data/lib/matchers/allow_mass_assignment.rb +101 -0
- data/lib/matchers/associations.rb +316 -0
- data/lib/matchers/collections.rb +9 -0
- data/lib/matchers/document.rb +163 -0
- data/lib/matchers/indexes.rb +84 -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 +9 -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 +74 -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 +33 -0
- data/lib/mongoid-rspec/version.rb +5 -0
- data/mongoid-rspec.gemspec +25 -0
- data/mongoid4-rspec.gemspec +25 -0
- data/spec/models/article.rb +29 -0
- data/spec/models/comment.rb +6 -0
- data/spec/models/log.rb +4 -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 +36 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/unit/accept_nested_attributes_spec.rb +12 -0
- data/spec/unit/associations_spec.rb +42 -0
- data/spec/unit/collections_spec.rb +7 -0
- data/spec/unit/document_spec.rb +21 -0
- data/spec/unit/indexes_spec.rb +13 -0
- data/spec/unit/validations_spec.rb +52 -0
- data/spec/validators/ssn_validator.rb +16 -0
- metadata +137 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Matchers
|
3
|
+
module Validations
|
4
|
+
class ValidateNumericalityOfMatcher < HaveValidationMatcher
|
5
|
+
@@allowed_options = [:equal_to, :greater_than, :greater_than_or_equal_to, :less_than, :less_than_or_equal_to,
|
6
|
+
:even, :odd, :only_integer, :allow_nil, :nil]
|
7
|
+
|
8
|
+
def initialize(field)
|
9
|
+
super(field, :numericality)
|
10
|
+
@options = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_allow(options)
|
14
|
+
options[:equal_to] = options if options.is_a?(Numeric)
|
15
|
+
options[:allow_nil] = options.delete(:nil) if options.has_key?(:nil)
|
16
|
+
raise ArgumentError, "validate_numericality_of#to_allow requires a Hash parameter containing any of the following keys: " <<
|
17
|
+
@@allowed_options.map(&:inspect).join(", ") if !options.is_a?(Hash) or options.empty? or (options.keys - @@allowed_options).any?
|
18
|
+
@options.merge!(options)
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def matches?(actual)
|
23
|
+
return false unless result = super(actual)
|
24
|
+
|
25
|
+
@@allowed_options.each do |comparator|
|
26
|
+
if @options.has_key?(comparator) and !([:even, :odd, :only_integer].include?(comparator) and !@validator.options.include?(comparator))
|
27
|
+
result &= (@validator.options[comparator] == @options[comparator])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
@positive_result_message <<= options_message(@validator.options)
|
31
|
+
@negative_result_message <<= options_message(@validator.options)
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
def description
|
36
|
+
super << options_message(@options)
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def options_message(options)
|
42
|
+
type_msg = []
|
43
|
+
comp_msg = []
|
44
|
+
options.each_pair do |key, value|
|
45
|
+
case key
|
46
|
+
when :allow_nil
|
47
|
+
when :only_integer
|
48
|
+
type_msg << "integer" if value
|
49
|
+
when :odd, :even
|
50
|
+
type_msg << "#{key.to_s}-numbered" if value
|
51
|
+
else
|
52
|
+
comp_msg << "#{key.to_s.gsub("_", " ")} #{value.inspect}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
allow_nil = (options[:allow_nil] ? "nil" : "non-nil") if options.has_key?(:allow_nil)
|
56
|
+
["", "allowing", allow_nil, type_msg.any? ? type_msg.to_sentence : nil, "values", comp_msg.any? ? comp_msg.to_sentence : nil].compact.join(" ")
|
57
|
+
end
|
58
|
+
|
59
|
+
def method_missing(m, *args, &block)
|
60
|
+
if @@allowed_options.include?(m.to_sym)
|
61
|
+
raise ArgumentError, "wrong number of arguments (#{args.length} for 1)" if args.length > 1
|
62
|
+
send :to_allow, m.to_sym => args.first
|
63
|
+
else
|
64
|
+
super
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def validate_numericality_of(field)
|
70
|
+
ValidateNumericalityOfMatcher.new(field)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Matchers
|
3
|
+
module Validations
|
4
|
+
class ValidateUniquenessOfMatcher < HaveValidationMatcher
|
5
|
+
include WithMessage
|
6
|
+
def initialize(field)
|
7
|
+
super(field, :uniqueness)
|
8
|
+
end
|
9
|
+
|
10
|
+
def scoped_to(*scope)
|
11
|
+
@scope = [scope].flatten.map(&:to_sym)
|
12
|
+
self
|
13
|
+
end
|
14
|
+
alias_method :scoped_on, :scoped_to
|
15
|
+
|
16
|
+
def case_insensitive
|
17
|
+
@case_insensitive = true
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def allow_blank?(allow_blank)
|
22
|
+
@allow_blank = allow_blank
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def matches?(actual)
|
27
|
+
return false unless @result = super(actual)
|
28
|
+
|
29
|
+
check_scope if @scope
|
30
|
+
check_allow_blank if @allow_blank
|
31
|
+
check_case_sensitivity if @case_insensitive
|
32
|
+
check_expected_message if @expected_message
|
33
|
+
|
34
|
+
@result
|
35
|
+
end
|
36
|
+
|
37
|
+
def description
|
38
|
+
options_desc = []
|
39
|
+
options_desc << " scoped to #{@scope.inspect}" if @scope
|
40
|
+
options_desc << " allowing blank values" if @allow_blank
|
41
|
+
options_desc << " allowing case insensitive values" if @case_insensitive
|
42
|
+
options_desc << " with message '#{@expected_message}'" if @expected_message
|
43
|
+
super << options_desc.to_sentence
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def check_allow_blank
|
49
|
+
if @validator.options[:allow_blank] == @allow_blank
|
50
|
+
@positive_result_message << " with blank values allowed"
|
51
|
+
else
|
52
|
+
@negative_result_message << " with no blank values allowed"
|
53
|
+
@result = false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def check_scope
|
58
|
+
message = " scope to #{@validator.options[:scope]}"
|
59
|
+
if [@validator.options[:scope]].flatten.map(&:to_sym) == @scope
|
60
|
+
@positive_result_message << message
|
61
|
+
else
|
62
|
+
@negative_result_message << message
|
63
|
+
@result = false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def check_case_sensitivity
|
68
|
+
if @validator.options[:case_sensitive] == false
|
69
|
+
@positive_result_message << " with case insensitive values"
|
70
|
+
else
|
71
|
+
@negative_result_message << " without case insensitive values"
|
72
|
+
@result = false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def validate_uniqueness_of(field)
|
78
|
+
ValidateUniquenessOfMatcher.new(field)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -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,33 @@
|
|
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_model"
|
8
|
+
require 'matchers/document'
|
9
|
+
require 'matchers/associations'
|
10
|
+
require 'matchers/collections'
|
11
|
+
require 'matchers/indexes'
|
12
|
+
require 'matchers/allow_mass_assignment'
|
13
|
+
require 'matchers/accept_nested_attributes'
|
14
|
+
require 'matchers/validations'
|
15
|
+
require 'matchers/validations/with_message'
|
16
|
+
require 'matchers/validations/associated'
|
17
|
+
require 'matchers/validations/confirmation_of'
|
18
|
+
require 'matchers/validations/exclusion_of'
|
19
|
+
require 'matchers/validations/format_of'
|
20
|
+
require 'matchers/validations/inclusion_of'
|
21
|
+
require 'matchers/validations/length_of'
|
22
|
+
require 'matchers/validations/numericality_of'
|
23
|
+
require 'matchers/validations/presence_of'
|
24
|
+
require 'matchers/validations/uniqueness_of'
|
25
|
+
require 'matchers/validations/acceptance_of'
|
26
|
+
require 'matchers/validations/custom_validation_of'
|
27
|
+
|
28
|
+
module Mongoid
|
29
|
+
module Matchers
|
30
|
+
include Mongoid::Matchers::Associations
|
31
|
+
include Mongoid::Matchers::Validations
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "mongoid-rspec/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "mongoid-rspec"
|
7
|
+
s.version = Mongoid::Rspec::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Evan Sagge"]
|
10
|
+
s.email = %q{evansagge@gmail.com}
|
11
|
+
s.homepage = %q{http://github.com/evansagge/mongoid-rspec}
|
12
|
+
s.summary = %q{RSpec matchers for Mongoid}
|
13
|
+
s.description = %q{RSpec matches for Mongoid models, including association and validation matchers}
|
14
|
+
|
15
|
+
s.rubyforge_project = "mongoid-rspec"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency 'rake'
|
23
|
+
s.add_dependency 'mongoid', '~> 4.0.0.beta2'
|
24
|
+
s.add_dependency 'rspec', '>= 2.14'
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "mongoid-rspec/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "mongoid4-rspec"
|
7
|
+
s.version = Mongoid::Rspec::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Francesco Boffa", "Evan Sagge"]
|
10
|
+
s.email = %q{fra.boffa@gmail.com evansagge@gmail.com}
|
11
|
+
s.homepage = %q{http://github.com/aomega08/mongoid4-rspec}
|
12
|
+
s.summary = %q{RSpec matchers for Mongoid 4}
|
13
|
+
s.description = %q{RSpec matches for Mongoid 4 models, including association and validation matchers}
|
14
|
+
|
15
|
+
s.rubyforge_project = "mongoid-rspec"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency 'rake'
|
23
|
+
s.add_dependency 'mongoid', '~> 4.0.0.beta2'
|
24
|
+
s.add_dependency 'rspec', '>= 2.14'
|
25
|
+
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
|
13
|
+
embeds_one :permalink
|
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,36 @@
|
|
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
|
18
|
+
|
19
|
+
embeds_one :profile
|
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 :provider_uid, presence: true
|
29
|
+
validates :locale, inclusion: { in: ->(user) { [:en, :ru] } }
|
30
|
+
|
31
|
+
accepts_nested_attributes_for :articles, :comments
|
32
|
+
|
33
|
+
def admin?
|
34
|
+
false
|
35
|
+
end
|
36
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
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.configure do |config|
|
18
|
+
config.connect_to("mongoid-rspec-test")
|
19
|
+
end
|
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
|
+
end
|