mongoid-rspec 1.5.0 → 1.6.0
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.
- data/README.md +93 -45
- data/lib/matchers/accept_nested_attributes.rb +65 -0
- data/lib/matchers/document.rb +43 -4
- data/lib/matchers/indexes.rb +9 -9
- data/lib/matchers/validations/inclusion_of.rb +20 -13
- data/lib/matchers/validations/length_of.rb +44 -19
- data/lib/matchers/validations.rb +32 -25
- data/lib/mongoid-rspec/version.rb +1 -1
- data/lib/mongoid-rspec.rb +1 -0
- data/spec/models/article.rb +8 -3
- data/spec/models/user.rb +8 -1
- data/spec/unit/accept_nested_attributes_spec.rb +12 -0
- data/spec/unit/document_spec.rb +8 -5
- data/spec/unit/indexes_spec.rb +1 -0
- data/spec/unit/validations_spec.rb +4 -0
- metadata +27 -9
data/README.md
CHANGED
|
@@ -1,25 +1,43 @@
|
|
|
1
1
|
mongoid-rspec
|
|
2
2
|
=
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
[](https://travis-ci.org/evansagge/mongoid-rspec)
|
|
5
|
+
|
|
6
|
+
http://rubygems.org/gems/mongoid-rspec
|
|
7
|
+
|
|
8
|
+
RSpec matchers for Mongoid 3.x.
|
|
9
|
+
|
|
10
|
+
For Mongoid 2.x, use [mongoid-rspec 1.4.5](http://rubygems.org/gems/mongoid-rspec/versions/1.4.5)
|
|
11
|
+
|
|
12
|
+
Installation
|
|
13
|
+
-
|
|
14
|
+
Add to your Gemfile
|
|
15
|
+
|
|
16
|
+
gem 'mongoid-rspec'
|
|
17
|
+
|
|
18
|
+
Drop in existing or dedicated support file in spec/support (spec/support/mongoid.rb)
|
|
19
|
+
|
|
20
|
+
RSpec.configure do |configuration|
|
|
21
|
+
configuration.include Mongoid::Matchers
|
|
22
|
+
end
|
|
5
23
|
|
|
6
24
|
Association Matchers
|
|
7
25
|
-
|
|
8
26
|
describe User do
|
|
9
27
|
it { should have_many(:articles).with_foreign_key(:author_id) }
|
|
10
|
-
|
|
11
|
-
it { should have_one(:record) }
|
|
12
|
-
|
|
28
|
+
|
|
29
|
+
it { should have_one(:record) }
|
|
30
|
+
|
|
13
31
|
it { should have_many :comments }
|
|
14
|
-
|
|
32
|
+
|
|
15
33
|
#can also specify with_dependent to test if :dependent => :destroy/:destroy_all/:delete is set
|
|
16
34
|
it { should have_many(:comments).with_dependent(:destroy) }
|
|
17
35
|
#can verify autosave is set to true
|
|
18
36
|
it { should have_many(:comments).with_autosave }
|
|
19
|
-
|
|
37
|
+
|
|
20
38
|
it { should embed_one :profile }
|
|
21
39
|
|
|
22
|
-
it { should have_and_belong_to_many(:children) }
|
|
40
|
+
it { should have_and_belong_to_many(:children) }
|
|
23
41
|
it { should have_and_belong_to_many(:children).of_type(User) }
|
|
24
42
|
end
|
|
25
43
|
|
|
@@ -42,6 +60,19 @@ Association Matchers
|
|
|
42
60
|
it { should belong_to(:user).as_inverse_of(:record) }
|
|
43
61
|
end
|
|
44
62
|
|
|
63
|
+
Mass Assignment Matcher
|
|
64
|
+
-
|
|
65
|
+
describe User do
|
|
66
|
+
it { should allow_mass_assignment_of(:login) }
|
|
67
|
+
it { should allow_mass_assignment_of(:email) }
|
|
68
|
+
it { should allow_mass_assignment_of(:age) }
|
|
69
|
+
it { should allow_mass_assignment_of(:password) }
|
|
70
|
+
it { should allow_mass_assignment_of(:password) }
|
|
71
|
+
it { should allow_mass_assignment_of(:role).as(:admin) }
|
|
72
|
+
|
|
73
|
+
it { should_not allow_mass_assignment_of(:role) }
|
|
74
|
+
end
|
|
75
|
+
|
|
45
76
|
Validation Matchers
|
|
46
77
|
-
|
|
47
78
|
describe Site do
|
|
@@ -50,32 +81,33 @@ Validation Matchers
|
|
|
50
81
|
end
|
|
51
82
|
|
|
52
83
|
describe User do
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
84
|
+
it { should validate_presence_of(:login) }
|
|
85
|
+
it { should validate_uniqueness_of(:login).scoped_to(:site) }
|
|
86
|
+
it { should validate_uniqueness_of(:email).case_insensitive.with_message("is already taken") }
|
|
87
|
+
it { should validate_format_of(:login).to_allow("valid_login").not_to_allow("invalid login") }
|
|
88
|
+
it { should validate_associated(:profile) }
|
|
89
|
+
it { should validate_exclusion_of(:login).to_not_allow("super", "index", "edit") }
|
|
90
|
+
it { should validate_inclusion_of(:role).to_allow("admin", "member") }
|
|
91
|
+
it { should validate_confirmation_of(:email) }
|
|
92
|
+
it { should validate_presence_of(:age).on(:create, :update) }
|
|
93
|
+
it { should validate_numericality_of(:age).on(:create, :update) }
|
|
94
|
+
it { should validate_inclusion_of(:age).to_allow(23..42).on([:create, :update]) }
|
|
95
|
+
it { should validate_presence_of(:password).on(:create) }
|
|
96
|
+
it { should validate_presence_of(:provider_uid).on(:create) }
|
|
97
|
+
it { should validate_inclusion_of(:locale).to_allow([:en, :ru]) }
|
|
66
98
|
end
|
|
67
99
|
|
|
68
100
|
describe Article do
|
|
69
101
|
it { should validate_length_of(:title).within(8..16) }
|
|
70
102
|
end
|
|
71
|
-
|
|
103
|
+
|
|
72
104
|
describe Profile do
|
|
73
105
|
it { should validate_numericality_of(:age).greater_than(0) }
|
|
74
|
-
end
|
|
106
|
+
end
|
|
75
107
|
|
|
76
108
|
describe MovieArticle do
|
|
77
109
|
it { should validate_numericality_of(:rating).to_allow(:greater_than => 0).less_than_or_equal_to(5) }
|
|
78
|
-
it { should validate_numericality_of(:classification).to_allow(:even => true, :only_integer => true, :nil => false) }
|
|
110
|
+
it { should validate_numericality_of(:classification).to_allow(:even => true, :only_integer => true, :nil => false) }
|
|
79
111
|
end
|
|
80
112
|
|
|
81
113
|
describe Person do
|
|
@@ -83,43 +115,59 @@ Validation Matchers
|
|
|
83
115
|
# should redefine the kind method to return :custom, i.e. "def self.kind() :custom end"
|
|
84
116
|
it { should custom_validate(:ssn).with_validator(SsnValidator) }
|
|
85
117
|
end
|
|
118
|
+
|
|
119
|
+
Accepts Nested Attributes Matcher
|
|
120
|
+
-
|
|
121
|
+
describe User do
|
|
122
|
+
it { should accept_nested_attributes_for(:articles) }
|
|
123
|
+
it { should accept_nested_attributes_for(:comments) }
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
describe Article do
|
|
127
|
+
it { should accept_nested_attributes_for(:permalink) }
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
Index Matcher
|
|
131
|
+
-
|
|
132
|
+
describe Article do
|
|
133
|
+
it { should have_index_for(published: 1) }
|
|
134
|
+
it { should have_index_for(title: 1).with_options(unique: true, background: true) }
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
describe Profile do
|
|
138
|
+
it { should have_index_for(first_name: 1, last_name: 1) }
|
|
139
|
+
end
|
|
140
|
+
|
|
86
141
|
Others
|
|
87
142
|
-
|
|
88
143
|
describe User do
|
|
89
144
|
it { should have_fields(:email, :login) }
|
|
90
|
-
it { should have_field(:
|
|
145
|
+
it { should have_field(:s).with_alias(:status) }
|
|
91
146
|
it { should have_fields(:birthdate, :registered_at).of_type(DateTime) }
|
|
92
147
|
|
|
93
|
-
it { should
|
|
94
|
-
|
|
148
|
+
it { should be_timestamped_document } # if you're declaring `include
|
|
149
|
+
Mongoid::Timestamps` or any of `include Mongoid::Timestamps::Created` and `Mongoid::Timestamps::Updated`
|
|
150
|
+
it { should be_timestamped_document.with(:created) }
|
|
151
|
+
it { should_not be_timestamped_document.with(:updated) }
|
|
95
152
|
|
|
96
|
-
# useful if you use factory_girl and have Factory(:user) defined for User
|
|
97
|
-
it { should save }
|
|
98
|
-
|
|
99
|
-
it { should be_timestamped_document } # if you're declaring `include Mongoid::Timestamps`
|
|
100
153
|
it { should be_versioned_document } # if you're declaring `include Mongoid::Versioning`
|
|
101
154
|
it { should be_paranoid_document } # if you're declaring `include Mongoid::Paranoia`
|
|
102
155
|
it { should be_multiparameted_document } # if you're declaring `include Mongoid::MultiParameterAttributes`
|
|
103
156
|
end
|
|
104
|
-
|
|
157
|
+
|
|
105
158
|
describe Log do
|
|
106
159
|
it { should be_stored_in :logs }
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
Use
|
|
110
|
-
-
|
|
111
|
-
add in Gemfile
|
|
112
|
-
|
|
113
|
-
gem 'mongoid-rspec'
|
|
114
|
-
|
|
115
|
-
drop in existing or dedicated support file in spec/support (spec/support/mongoid.rb)
|
|
160
|
+
end
|
|
116
161
|
|
|
117
|
-
|
|
118
|
-
|
|
162
|
+
describe Article do
|
|
163
|
+
it { should have_field(:published).of_type(Boolean).with_default_value_of(false) }
|
|
164
|
+
it { should have_field(:allow_comments).of_type(Boolean).with_default_value_of(true) }
|
|
165
|
+
it { should_not have_field(:allow_comments).of_type(Boolean).with_default_value_of(false) }
|
|
166
|
+
it { should_not have_field(:number_of_comments).of_type(Integer).with_default_value_of(1) }
|
|
119
167
|
end
|
|
120
|
-
|
|
168
|
+
|
|
121
169
|
Acknowledgement
|
|
122
170
|
-
|
|
123
|
-
Thanks to [Durran Jordan](https://github.com/durran) for providing the changes necessary to make
|
|
124
|
-
this compatible with mongoid 2.0.0.rc, and for other [contributors](https://github.com/evansagge/mongoid-rspec/contributors)
|
|
171
|
+
Thanks to [Durran Jordan](https://github.com/durran) for providing the changes necessary to make
|
|
172
|
+
this compatible with mongoid 2.0.0.rc, and for other [contributors](https://github.com/evansagge/mongoid-rspec/contributors)
|
|
125
173
|
to this project.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module Mongoid
|
|
2
|
+
module Matchers # :nodoc:
|
|
3
|
+
|
|
4
|
+
# Ensures that the model can accept nested attributes for the specified
|
|
5
|
+
# association.
|
|
6
|
+
#
|
|
7
|
+
# Example:
|
|
8
|
+
# it { should accept_nested_attributes_for(:articles) }
|
|
9
|
+
#
|
|
10
|
+
def accept_nested_attributes_for(attribute)
|
|
11
|
+
AcceptNestedAttributesForMatcher.new(attribute)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class AcceptNestedAttributesForMatcher
|
|
15
|
+
|
|
16
|
+
def initialize(attribute)
|
|
17
|
+
@attribute = attribute.to_s
|
|
18
|
+
@options = {}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def matches?(subject)
|
|
22
|
+
@subject = subject
|
|
23
|
+
match?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def failure_message
|
|
27
|
+
"Expected #{expectation} (#{@problem})"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def negative_failure_message
|
|
31
|
+
"Did not expect #{expectation}"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def description
|
|
35
|
+
description = "accepts_nested_attributes_for :#{@attribute}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
protected
|
|
39
|
+
def match?
|
|
40
|
+
exists?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def exists?
|
|
44
|
+
if config
|
|
45
|
+
true
|
|
46
|
+
else
|
|
47
|
+
@problem = 'is not declared'
|
|
48
|
+
false
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def config
|
|
53
|
+
model_class.nested_attributes["#{@attribute}_attributes"]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def model_class
|
|
57
|
+
@subject.class
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def expectation
|
|
61
|
+
"#{model_class.name} to accept nested attributes for #{@attribute}"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
data/lib/matchers/document.rb
CHANGED
|
@@ -5,10 +5,20 @@ module Mongoid
|
|
|
5
5
|
@attributes = attrs.collect(&:to_s)
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
+
def localized
|
|
9
|
+
@localized = true
|
|
10
|
+
self
|
|
11
|
+
end
|
|
12
|
+
|
|
8
13
|
def of_type(type)
|
|
9
14
|
@type = type
|
|
10
15
|
self
|
|
11
16
|
end
|
|
17
|
+
|
|
18
|
+
def with_alias(field_alias)
|
|
19
|
+
@field_alias = field_alias
|
|
20
|
+
self
|
|
21
|
+
end
|
|
12
22
|
|
|
13
23
|
def with_default_value_of(default)
|
|
14
24
|
@default = default
|
|
@@ -25,11 +35,26 @@ module Mongoid
|
|
|
25
35
|
error << " of type #{@klass.fields[attr].type}"
|
|
26
36
|
end
|
|
27
37
|
|
|
28
|
-
if !@default.nil?
|
|
29
|
-
|
|
38
|
+
if !@default.nil?
|
|
39
|
+
if @klass.fields[attr].default_val.nil?
|
|
40
|
+
error << " with default not set"
|
|
41
|
+
elsif @klass.fields[attr].default_val != @default
|
|
42
|
+
error << " with default value of #{@klass.fields[attr].default_val}"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
if @field_alias and @klass.fields[attr].options[:as] != @field_alias
|
|
47
|
+
error << " with alias #{@klass.fields[attr].options[:as]}"
|
|
30
48
|
end
|
|
31
49
|
|
|
32
50
|
@errors.push("field #{attr.inspect}" << error) unless error.blank?
|
|
51
|
+
|
|
52
|
+
if @localized
|
|
53
|
+
unless @klass.fields[attr].localized?
|
|
54
|
+
@errors.push "is not localized #{attr.inspect}"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
33
58
|
else
|
|
34
59
|
@errors.push "no field named #{attr.inspect}"
|
|
35
60
|
end
|
|
@@ -48,6 +73,7 @@ module Mongoid
|
|
|
48
73
|
def description
|
|
49
74
|
desc = "have #{@attributes.size > 1 ? 'fields' : 'field'} named #{@attributes.collect(&:inspect).to_sentence}"
|
|
50
75
|
desc << " of type #{@type.inspect}" if @type
|
|
76
|
+
desc << " with alias #{@field_alias}" if @field_alias
|
|
51
77
|
desc << " with default value of #{@default.inspect}" if !@default.nil?
|
|
52
78
|
desc
|
|
53
79
|
end
|
|
@@ -92,11 +118,24 @@ end
|
|
|
92
118
|
|
|
93
119
|
RSpec::Matchers.define :be_timestamped_document do
|
|
94
120
|
match do |doc|
|
|
95
|
-
|
|
121
|
+
if [*@timestamped_module].any?
|
|
122
|
+
modules = [*@timestamped_module].map{|m| "Mongoid::Timestamps::#{m.to_s.classify}".constantize }
|
|
123
|
+
(modules - doc.class.included_modules).empty?
|
|
124
|
+
else
|
|
125
|
+
doc.class.included_modules.include?(Mongoid::Timestamps) or
|
|
126
|
+
doc.class.included_modules.include?(Mongoid::Timestamps::Created) or
|
|
127
|
+
doc.class.included_modules.include?(Mongoid::Timestamps::Updated)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
chain :with do |timestamped_module|
|
|
132
|
+
@timestamped_module = timestamped_module
|
|
96
133
|
end
|
|
97
134
|
|
|
98
135
|
description do
|
|
99
|
-
"be a timestamped Mongoid document"
|
|
136
|
+
desc = "be a timestamped Mongoid document"
|
|
137
|
+
desc << " with #{@timestamped_module}" if @timestamped_module
|
|
138
|
+
desc
|
|
100
139
|
end
|
|
101
140
|
end
|
|
102
141
|
|
data/lib/matchers/indexes.rb
CHANGED
|
@@ -2,33 +2,33 @@ module Mongoid
|
|
|
2
2
|
module Matchers
|
|
3
3
|
class HaveIndexForMatcher # :nodoc:
|
|
4
4
|
def initialize(index_fields)
|
|
5
|
-
@index_fields = index_fields
|
|
5
|
+
@index_fields = index_fields.symbolize_keys!
|
|
6
6
|
end
|
|
7
|
-
|
|
8
|
-
def with_options(options = {})
|
|
7
|
+
|
|
8
|
+
def with_options(options = { })
|
|
9
9
|
@options = options
|
|
10
10
|
self
|
|
11
11
|
end
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
def matches?(klass)
|
|
14
|
-
@klass
|
|
14
|
+
@klass = klass.is_a?(Class) ? klass : klass.class
|
|
15
15
|
@errors = []
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
unless @klass.index_options[@index_fields]
|
|
18
18
|
@errors.push "no index for #{@index_fields}"
|
|
19
19
|
else
|
|
20
20
|
if !@options.nil? && !@options.empty?
|
|
21
21
|
@options.each do |option, option_value|
|
|
22
|
-
if @klass.index_options[@index_fields]
|
|
22
|
+
if @klass.index_options[@index_fields][option] != option_value
|
|
23
23
|
@errors.push "index for #{@index_fields.inspect} with options of #{@klass.index_options[@index_fields].inspect}"
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
@errors.empty?
|
|
30
30
|
end
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
def failure_message_for_should
|
|
33
33
|
"Expected #{@klass.inspect} to #{description}, got #{@errors.to_sentence}"
|
|
34
34
|
end
|
|
@@ -1,42 +1,49 @@
|
|
|
1
1
|
module Mongoid
|
|
2
2
|
module Matchers
|
|
3
|
-
module Validations
|
|
3
|
+
module Validations
|
|
4
4
|
class ValidateInclusionOfMatcher < HaveValidationMatcher
|
|
5
5
|
def initialize(name)
|
|
6
6
|
super(name, :inclusion)
|
|
7
7
|
end
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
def to_allow(*values)
|
|
10
10
|
@allowed_values = values.map(&:to_a).flatten
|
|
11
11
|
self
|
|
12
12
|
end
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
def matches?(actual)
|
|
15
15
|
return false unless result = super(actual)
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
if @allowed_values
|
|
18
|
-
|
|
18
|
+
raw_validator_allowed_values = @validator.options[:in]
|
|
19
|
+
|
|
20
|
+
validator_allowed_values = case raw_validator_allowed_values
|
|
21
|
+
when Range then raw_validator_allowed_values.to_a
|
|
22
|
+
when Proc then raw_validator_allowed_values.call(actual)
|
|
23
|
+
else raw_validator_allowed_values end
|
|
24
|
+
|
|
25
|
+
not_allowed_values = @allowed_values - validator_allowed_values
|
|
19
26
|
if not_allowed_values.empty?
|
|
20
27
|
@positive_result_message = @positive_result_message << " allowing all values mentioned"
|
|
21
28
|
else
|
|
22
|
-
@negative_result_message = @negative_result_message << " not allowing
|
|
29
|
+
@negative_result_message = @negative_result_message << " not allowing these values: #{not_allowed_values.inspect}"
|
|
23
30
|
result = false
|
|
24
31
|
end
|
|
25
32
|
end
|
|
26
|
-
|
|
27
|
-
result
|
|
33
|
+
|
|
34
|
+
result
|
|
28
35
|
end
|
|
29
|
-
|
|
36
|
+
|
|
30
37
|
def description
|
|
31
38
|
options_desc = []
|
|
32
|
-
options_desc << " allowing
|
|
39
|
+
options_desc << " allowing these values: #{@allowed_values}" if @allowed_values
|
|
33
40
|
super << options_desc.to_sentence
|
|
34
|
-
end
|
|
41
|
+
end
|
|
35
42
|
end
|
|
36
43
|
|
|
37
44
|
def validate_inclusion_of(field)
|
|
38
45
|
ValidateInclusionOfMatcher.new(field)
|
|
39
|
-
end
|
|
46
|
+
end
|
|
40
47
|
end
|
|
41
48
|
end
|
|
42
|
-
end
|
|
49
|
+
end
|
|
@@ -10,11 +10,13 @@ module Mongoid
|
|
|
10
10
|
@maximum = value
|
|
11
11
|
self
|
|
12
12
|
end
|
|
13
|
+
alias :less_than :with_maximum
|
|
13
14
|
|
|
14
15
|
def with_minimum(value)
|
|
15
16
|
@minimum = value
|
|
16
17
|
self
|
|
17
18
|
end
|
|
19
|
+
alias :greater_than :with_minimum
|
|
18
20
|
|
|
19
21
|
def within(value)
|
|
20
22
|
@within = value
|
|
@@ -41,55 +43,78 @@ module Mongoid
|
|
|
41
43
|
|
|
42
44
|
def description
|
|
43
45
|
options_desc = []
|
|
44
|
-
options_desc << "
|
|
45
|
-
options_desc << "
|
|
46
|
-
options_desc << "
|
|
47
|
-
options_desc << "
|
|
48
|
-
super << options_desc.to_sentence
|
|
46
|
+
options_desc << "with minimum of #{@minimum}" if @minimum
|
|
47
|
+
options_desc << "with maximum of #{@maximum}" if @maximum
|
|
48
|
+
options_desc << "within the range of #{@within}" if @within
|
|
49
|
+
options_desc << "as exactly #{@is}" if @is
|
|
50
|
+
super << " #{options_desc.to_sentence}"
|
|
49
51
|
end
|
|
50
52
|
|
|
51
53
|
private
|
|
52
54
|
|
|
53
55
|
def check_maximum
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
if actual_max.nil?
|
|
57
|
+
@negative_result_message << " with no maximum"
|
|
58
|
+
@result = false
|
|
59
|
+
elsif actual_max == @maximum
|
|
56
60
|
@positive_result_message << " with maximum of #{@maximum}"
|
|
57
61
|
else
|
|
58
|
-
@negative_result_message << " with maximum of #{
|
|
62
|
+
@negative_result_message << " with maximum of #{actual_max}"
|
|
59
63
|
@result = false
|
|
60
64
|
end
|
|
61
65
|
end
|
|
62
66
|
|
|
63
67
|
def check_minimum
|
|
64
|
-
|
|
65
|
-
|
|
68
|
+
if actual_min.nil?
|
|
69
|
+
@negative_result_message << " with no minimum"
|
|
70
|
+
@result = false
|
|
71
|
+
elsif actual_min == @minimum
|
|
66
72
|
@positive_result_message << " with minimum of #{@minimum}"
|
|
67
73
|
else
|
|
68
|
-
@negative_result_message << " with minimum of #{
|
|
74
|
+
@negative_result_message << " with minimum of #{actual_min}"
|
|
69
75
|
@result = false
|
|
70
76
|
end
|
|
71
77
|
end
|
|
72
78
|
|
|
73
79
|
def check_range
|
|
74
80
|
min, max = [@within.min, @within.max]
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
@
|
|
81
|
+
if !actual_min.nil? and actual_max.nil?
|
|
82
|
+
@negative_result_message << " with no minimum but with maximum of #{actual_max}"
|
|
83
|
+
@result = false
|
|
84
|
+
elsif actual_min.nil? and !actual_max.nil?
|
|
85
|
+
@negative_result_message << " with minimum_of #{actual_min} but no maximum"
|
|
86
|
+
@result = false
|
|
87
|
+
elsif actual_min.nil? and actual_max.nil?
|
|
88
|
+
@negative_result_message << " with no minimum and maximum"
|
|
89
|
+
@result = false
|
|
90
|
+
elsif actual_min == min && actual_max == max
|
|
91
|
+
@positive_result_message << " within the range of #{@within.inspect}"
|
|
78
92
|
else
|
|
79
|
-
@negative_result_message << "
|
|
93
|
+
@negative_result_message << " within the range of #{(actual_min..actual_max).inspect}"
|
|
80
94
|
@result = false
|
|
81
95
|
end
|
|
82
96
|
end
|
|
83
97
|
|
|
84
98
|
def check_exact
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
@positive_result_message << " is exactly #{@is}"
|
|
99
|
+
if actual_is == @is
|
|
100
|
+
@positive_result_message << " as exactly #{@is}"
|
|
88
101
|
else
|
|
89
|
-
@negative_result_message << "
|
|
102
|
+
@negative_result_message << " as exactly #{actual_is}"
|
|
90
103
|
@result = false
|
|
91
104
|
end
|
|
92
105
|
end
|
|
106
|
+
|
|
107
|
+
def actual_is
|
|
108
|
+
actual_is = @validator.options[:is]
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def actual_min
|
|
112
|
+
@validator.options[:minimum] || ((@validator.options[:in] || @validator.options[:within]).try(&:min))
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def actual_max
|
|
116
|
+
@validator.options[:maximum] || ((@validator.options[:in] || @validator.options[:within]).try(&:max))
|
|
117
|
+
end
|
|
93
118
|
end
|
|
94
119
|
|
|
95
120
|
def validate_length_of(field)
|
data/lib/matchers/validations.rb
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
module Mongoid
|
|
2
2
|
module Matchers
|
|
3
|
-
module Validations
|
|
4
|
-
|
|
3
|
+
module Validations
|
|
4
|
+
|
|
5
5
|
class HaveValidationMatcher
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
def initialize(field, validation_type)
|
|
8
8
|
@field = field.to_s
|
|
9
9
|
@type = validation_type.to_s
|
|
10
10
|
@options = {}
|
|
11
11
|
end
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
def matches?(actual)
|
|
14
14
|
@klass = actual.is_a?(Class) ? actual : actual.class
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
@validator = @klass.validators_on(@field).detect{|v| v.kind.to_s == @type}
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
if @validator
|
|
19
19
|
@negative_result_message = "#{@type.inspect} validator on #{@field.inspect}"
|
|
20
20
|
@positive_result_message = "#{@type.inspect} validator on #{@field.inspect}"
|
|
@@ -23,37 +23,44 @@ module Mongoid
|
|
|
23
23
|
return false
|
|
24
24
|
end
|
|
25
25
|
@result = true
|
|
26
|
-
check_on if @options[:on]
|
|
26
|
+
check_on if @options[:on]
|
|
27
27
|
@result
|
|
28
28
|
end
|
|
29
|
-
|
|
30
|
-
def failure_message_for_should
|
|
31
|
-
"Expected #{@klass.inspect} to #{description}; instead got #{@negative_result_message}"
|
|
29
|
+
|
|
30
|
+
def failure_message_for_should
|
|
31
|
+
"Expected #{@klass.inspect} to #{description}; instead got #{@negative_result_message}"
|
|
32
32
|
end
|
|
33
|
-
|
|
34
|
-
def failure_message_for_should_not
|
|
35
|
-
"Expected #{@klass.inspect} to not #{description}; instead got #{@positive_result_message}"
|
|
33
|
+
|
|
34
|
+
def failure_message_for_should_not
|
|
35
|
+
"Expected #{@klass.inspect} to not #{description}; instead got #{@positive_result_message}"
|
|
36
36
|
end
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
def description
|
|
39
|
-
"
|
|
39
|
+
desc = "have #{@type.inspect} validator on #{@field.inspect}"
|
|
40
|
+
desc << " on #{@options[:on]}" if @options[:on]
|
|
41
|
+
desc
|
|
40
42
|
end
|
|
41
|
-
|
|
43
|
+
|
|
42
44
|
def on(*on_method)
|
|
43
45
|
@options[:on] = on_method.flatten
|
|
44
46
|
self
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
+
end
|
|
48
|
+
|
|
47
49
|
def check_on
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
@
|
|
50
|
+
validator_on_methods = [@validator.options[:on]].flatten
|
|
51
|
+
|
|
52
|
+
if validator_on_methods.any?
|
|
53
|
+
message = " on methods: #{validator_on_methods}"
|
|
54
|
+
|
|
55
|
+
if (@options[:on] - validator_on_methods).empty?
|
|
56
|
+
@positive_result_message << message
|
|
57
|
+
else
|
|
58
|
+
@negative_result_message << message
|
|
59
|
+
@result = false
|
|
60
|
+
end
|
|
54
61
|
end
|
|
55
62
|
end
|
|
56
|
-
end
|
|
63
|
+
end
|
|
57
64
|
end
|
|
58
65
|
end
|
|
59
66
|
end
|
data/lib/mongoid-rspec.rb
CHANGED
|
@@ -8,6 +8,7 @@ require 'matchers/associations'
|
|
|
8
8
|
require 'matchers/collections'
|
|
9
9
|
require 'matchers/indexes'
|
|
10
10
|
require 'matchers/allow_mass_assignment'
|
|
11
|
+
require 'matchers/accept_nested_attributes'
|
|
11
12
|
require 'matchers/validations'
|
|
12
13
|
require 'matchers/validations/associated'
|
|
13
14
|
require 'matchers/validations/confirmation_of'
|
data/spec/models/article.rb
CHANGED
|
@@ -5,10 +5,11 @@ class Article
|
|
|
5
5
|
include Mongoid::Versioning
|
|
6
6
|
include Mongoid::MultiParameterAttributes
|
|
7
7
|
|
|
8
|
-
field :title
|
|
8
|
+
field :title, :localize => true
|
|
9
9
|
field :content
|
|
10
10
|
field :published, :type => Boolean, :default => false
|
|
11
11
|
field :allow_comments, :type => Boolean, :default => true
|
|
12
|
+
field :number_of_comments, :type => Integer
|
|
12
13
|
|
|
13
14
|
embeds_many :comments
|
|
14
15
|
embeds_one :permalink
|
|
@@ -16,8 +17,12 @@ class Article
|
|
|
16
17
|
|
|
17
18
|
validates :title, :presence => true
|
|
18
19
|
|
|
19
|
-
validates_length_of :title, :
|
|
20
|
+
validates_length_of :title, :within => 8..16
|
|
21
|
+
validates_length_of :content, :minimum => 200
|
|
20
22
|
|
|
21
23
|
index({ title: 1 }, { unique: true, background: true })
|
|
22
24
|
index({ published: 1 })
|
|
23
|
-
|
|
25
|
+
index({ 'permalink._id' => 1 })
|
|
26
|
+
|
|
27
|
+
accepts_nested_attributes_for :permalink
|
|
28
|
+
end
|
data/spec/models/user.rb
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
class User
|
|
2
2
|
include Mongoid::Document
|
|
3
|
+
include Mongoid::Timestamps::Created
|
|
3
4
|
|
|
4
5
|
field :login
|
|
5
6
|
field :email
|
|
6
7
|
field :role
|
|
7
8
|
field :age, type: Integer
|
|
8
9
|
field :password, type: String
|
|
10
|
+
field :provider_uid
|
|
11
|
+
field :locale
|
|
9
12
|
|
|
10
13
|
belongs_to :site, :inverse_of => :users
|
|
11
14
|
has_many :articles, :foreign_key => :author_id
|
|
@@ -20,11 +23,15 @@ class User
|
|
|
20
23
|
validates :role, :presence => true, :inclusion => { :in => ["admin", "moderator", "member"]}
|
|
21
24
|
validates :profile, :presence => true, :associated => true
|
|
22
25
|
validates :age, :presence => true, :numericality => true, :inclusion => { :in => 23..42 }, :on => [:create, :update]
|
|
23
|
-
validates :password, :presence => true, :on => :create
|
|
26
|
+
validates :password, :presence => true, :on => [:create, :update]
|
|
27
|
+
validates :provider_uid, presence: true
|
|
28
|
+
validates :locale, :inclusion => {:in => lambda { |user| [:en, :ru] } }
|
|
24
29
|
|
|
25
30
|
attr_accessible :login, :email, :age, :password
|
|
26
31
|
attr_accessible :role, :as => :admin
|
|
27
32
|
|
|
33
|
+
accepts_nested_attributes_for :articles, :comments
|
|
34
|
+
|
|
28
35
|
def admin?
|
|
29
36
|
false
|
|
30
37
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "AcceptsNestedAttributes" do
|
|
4
|
+
describe User do
|
|
5
|
+
it { should accept_nested_attributes_for(:articles) }
|
|
6
|
+
it { should accept_nested_attributes_for(:comments) }
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe Article do
|
|
10
|
+
it { should accept_nested_attributes_for(:permalink) }
|
|
11
|
+
end
|
|
12
|
+
end
|
data/spec/unit/document_spec.rb
CHANGED
|
@@ -3,15 +3,18 @@ require 'spec_helper'
|
|
|
3
3
|
describe "Document" do
|
|
4
4
|
describe User do
|
|
5
5
|
it { should have_fields(:email, :login) }
|
|
6
|
+
it { should be_timestamped_document }
|
|
7
|
+
it { should be_timestamped_document.with(:created) }
|
|
8
|
+
it { should_not be_timestamped_document.with(:updated) }
|
|
6
9
|
end
|
|
7
|
-
|
|
10
|
+
|
|
8
11
|
describe Article do
|
|
9
12
|
it { should have_field(:published).of_type(Boolean).with_default_value_of(false) }
|
|
10
|
-
it { should have_field(:allow_comments).of_type(Boolean).with_default_value_of(true) }
|
|
13
|
+
it { should have_field(:allow_comments).of_type(Boolean).with_default_value_of(true) }
|
|
14
|
+
it { should belong_to(:author) }
|
|
15
|
+
it { should have_field(:title).localized }
|
|
11
16
|
it { should_not have_field(:allow_comments).of_type(Boolean).with_default_value_of(false) }
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
describe Article do
|
|
17
|
+
it { should_not have_field(:number_of_comments).of_type(Integer).with_default_value_of(1) }
|
|
15
18
|
it { should be_mongoid_document }
|
|
16
19
|
it { should be_versioned_document }
|
|
17
20
|
it { should be_timestamped_document }
|
data/spec/unit/indexes_spec.rb
CHANGED
|
@@ -19,6 +19,8 @@ describe "Validations" do
|
|
|
19
19
|
it { should validate_numericality_of(:age).on(:create, :update) }
|
|
20
20
|
it { should validate_inclusion_of(:age).to_allow(23..42).on([:create, :update]) }
|
|
21
21
|
it { should validate_presence_of(:password).on(:create) }
|
|
22
|
+
it { should validate_presence_of(:provider_uid).on(:create) }
|
|
23
|
+
it { should validate_inclusion_of(:locale).to_allow([:en, :ru]) }
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
describe Profile do
|
|
@@ -28,6 +30,8 @@ describe "Validations" do
|
|
|
28
30
|
|
|
29
31
|
describe Article do
|
|
30
32
|
it { should validate_length_of(:title).within(8..16) }
|
|
33
|
+
it { should_not validate_length_of(:content).greater_than(200).less_than(16) }
|
|
34
|
+
it { should validate_length_of(:content).greater_than(200) }
|
|
31
35
|
end
|
|
32
36
|
|
|
33
37
|
describe MovieArticle do
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mongoid-rspec
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.6.0
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,11 +9,11 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
12
|
+
date: 2013-01-27 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: rake
|
|
16
|
-
requirement:
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
17
|
none: false
|
|
18
18
|
requirements:
|
|
19
19
|
- - ! '>='
|
|
@@ -21,10 +21,15 @@ dependencies:
|
|
|
21
21
|
version: '0'
|
|
22
22
|
type: :runtime
|
|
23
23
|
prerelease: false
|
|
24
|
-
version_requirements:
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ! '>='
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '0'
|
|
25
30
|
- !ruby/object:Gem::Dependency
|
|
26
31
|
name: mongoid
|
|
27
|
-
requirement:
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
28
33
|
none: false
|
|
29
34
|
requirements:
|
|
30
35
|
- - ! '>='
|
|
@@ -32,10 +37,15 @@ dependencies:
|
|
|
32
37
|
version: 3.0.1
|
|
33
38
|
type: :runtime
|
|
34
39
|
prerelease: false
|
|
35
|
-
version_requirements:
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ! '>='
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: 3.0.1
|
|
36
46
|
- !ruby/object:Gem::Dependency
|
|
37
47
|
name: rspec
|
|
38
|
-
requirement:
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
39
49
|
none: false
|
|
40
50
|
requirements:
|
|
41
51
|
- - ! '>='
|
|
@@ -43,7 +53,12 @@ dependencies:
|
|
|
43
53
|
version: '2.9'
|
|
44
54
|
type: :runtime
|
|
45
55
|
prerelease: false
|
|
46
|
-
version_requirements:
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
none: false
|
|
58
|
+
requirements:
|
|
59
|
+
- - ! '>='
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '2.9'
|
|
47
62
|
description: RSpec matches for Mongoid models, including association and validation
|
|
48
63
|
matchers
|
|
49
64
|
email: evansagge@gmail.com
|
|
@@ -60,6 +75,7 @@ files:
|
|
|
60
75
|
- LICENSE
|
|
61
76
|
- README.md
|
|
62
77
|
- Rakefile
|
|
78
|
+
- lib/matchers/accept_nested_attributes.rb
|
|
63
79
|
- lib/matchers/allow_mass_assignment.rb
|
|
64
80
|
- lib/matchers/associations.rb
|
|
65
81
|
- lib/matchers/collections.rb
|
|
@@ -91,6 +107,7 @@ files:
|
|
|
91
107
|
- spec/models/site.rb
|
|
92
108
|
- spec/models/user.rb
|
|
93
109
|
- spec/spec_helper.rb
|
|
110
|
+
- spec/unit/accept_nested_attributes_spec.rb
|
|
94
111
|
- spec/unit/allow_mass_assignment_spec.rb
|
|
95
112
|
- spec/unit/associations_spec.rb
|
|
96
113
|
- spec/unit/collections_spec.rb
|
|
@@ -118,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
118
135
|
version: '0'
|
|
119
136
|
requirements: []
|
|
120
137
|
rubyforge_project: mongoid-rspec
|
|
121
|
-
rubygems_version: 1.8.
|
|
138
|
+
rubygems_version: 1.8.24
|
|
122
139
|
signing_key:
|
|
123
140
|
specification_version: 3
|
|
124
141
|
summary: RSpec matchers for Mongoid
|
|
@@ -134,6 +151,7 @@ test_files:
|
|
|
134
151
|
- spec/models/site.rb
|
|
135
152
|
- spec/models/user.rb
|
|
136
153
|
- spec/spec_helper.rb
|
|
154
|
+
- spec/unit/accept_nested_attributes_spec.rb
|
|
137
155
|
- spec/unit/allow_mass_assignment_spec.rb
|
|
138
156
|
- spec/unit/associations_spec.rb
|
|
139
157
|
- spec/unit/collections_spec.rb
|