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 CHANGED
@@ -1,25 +1,43 @@
1
1
  mongoid-rspec
2
2
  =
3
3
 
4
- RSpec matchers for Mongoid.
4
+ [![Build Status](https://secure.travis-ci.org/evansagge/mongoid-rspec.png?branch=master)](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
- it { should validate_presence_of(:login) }
54
- it { should validate_uniqueness_of(:login).scoped_to(:site) }
55
- it { should validate_uniqueness_of(:email).case_insensitive.with_message("is already taken") }
56
- it { should validate_format_of(:login).to_allow("valid_login").not_to_allow("invalid login") }
57
- it { should validate_associated(:profile) }
58
- it { should validate_exclusion_of(:login).to_not_allow("super", "index", "edit") }
59
- it { should validate_inclusion_of(:role).to_allow("admin", "member") }
60
- it { should validate_confirmation_of(:email) }
61
- it { should validate_presence_of(:age).on(:create, :update) }
62
- # The on matcher can take var args or an array. Validations do not fail if on is not specified.
63
- it { should validate_numericality_of(:age).on(:create, :update) }
64
- it { should validate_inclusion_of(:age).to_allow(23..42).on([:create, :update]) }
65
- it { should validate_presence_of(:password).on(:create) }
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(:active).of_type(Boolean).with_default_value_of(false) }
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 have_index_for(:last_name) }
94
- it { should have_index_for(:email).with_options(:unique => true) }
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
- RSpec.configure do |configuration|
118
- configuration.include Mongoid::Matchers
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
@@ -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? and !@klass.fields[attr].default_val.nil? and @klass.fields[attr].default_val != @default
29
- error << " with default value of #{@klass.fields[attr].default_val}"
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
- doc.class.included_modules.include?(Mongoid::Timestamps)
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
 
@@ -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 = klass.is_a?(Class) ? klass : klass.class
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].include?(option) && @klass.index_options[@index_fields][option] != option_value
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
- not_allowed_values = @allowed_values - @validator.options[:in].to_a
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 the following the ff. values: #{not_allowed_values.inspect}"
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 the ff. values: #{@allowed_values}" if @allowed_values
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 << " with maximum #{@maximum}" if @maximum
45
- options_desc << " with minimum #{@minimum}" if @minimum
46
- options_desc << " within range #{@within}" if @within
47
- options_desc << " as exactly #{@is}" if @is
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
- actual = @validator.options[:maximum]
55
- if actual == @maximum
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 #{actual}"
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
- actual = @validator.options[:minimum]
65
- if actual == @minimum
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 #{actual}"
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
- actual = @validator.options
76
- if actual[:minimum] == min && actual[:maximum] == max
77
- @positive_result_message << " with range #{@within.inspect}"
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 << " with range #{(actual[:minimum]..actual[:maximum]).inspect}"
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
- actual = @validator.options[:is]
86
- if actual == @is
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 << " is exactly #{actual}"
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)
@@ -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
- "validate #{@type} of #{@field.inspect}"
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
- message = " on methods: #{@validator.options[:on]}"
49
- if [@validator.options[:on]].flatten == @options[:on]
50
- @positive_result_message << message
51
- else
52
- @negative_result_message << message
53
- @result = false
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
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  module Rspec
3
- VERSION = "1.5.0"
3
+ VERSION = "1.6.0"
4
4
  end
5
5
  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'
@@ -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, :minimum => 8, :maximum => 16
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
- end
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
@@ -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
- end
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 }
@@ -4,6 +4,7 @@ describe "Indexes" do
4
4
  describe Article do
5
5
  it { should have_index_for(published: 1) }
6
6
  it { should have_index_for(title: 1).with_options(unique: true, background: true) }
7
+ it { should have_index_for('permalink._id' => 1) }
7
8
  end
8
9
 
9
10
  describe Profile do
@@ -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.5.0
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: 2012-07-27 00:00:00.000000000 Z
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: &70123218181600 !ruby/object:Gem::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: *70123218181600
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: &70123218180220 !ruby/object:Gem::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: *70123218180220
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: &70123218179440 !ruby/object:Gem::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: *70123218179440
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.10
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