warp 1.1.0 → 1.2.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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/Gemfile +4 -0
  4. data/README.md +99 -2
  5. data/gemfiles/rails_3.2_rspec_2.14.gemfile +3 -0
  6. data/gemfiles/rails_3.2_rspec_2.99.0.beta1.gemfile +3 -0
  7. data/gemfiles/rails_3.2_rspec_3.0.0.beta1.gemfile +3 -0
  8. data/gemfiles/rails_3.2_rspec_master.gemfile +3 -0
  9. data/gemfiles/rails_4.0_rspec_2.14.gemfile +3 -0
  10. data/gemfiles/rails_4.0_rspec_2.99.0.beta1.gemfile +3 -0
  11. data/gemfiles/rails_4.0_rspec_3.0.0.beta1.gemfile +3 -0
  12. data/gemfiles/rails_4.0_rspec_master.gemfile +3 -0
  13. data/gemfiles/rails_4.1.0.beta1_rspec_2.14.gemfile +3 -0
  14. data/gemfiles/rails_4.1.0.beta1_rspec_2.99.0.beta1.gemfile +3 -0
  15. data/gemfiles/rails_4.1.0.beta1_rspec_3.0.0.beta1.gemfile +3 -0
  16. data/gemfiles/rails_4.1.0.beta1_rspec_master.gemfile +3 -0
  17. data/lib/warp/controller_matchers.rb +4 -0
  18. data/lib/warp/matcher.rb +1 -1
  19. data/lib/warp/model_matchers/association_matcher.rb +27 -19
  20. data/lib/warp/model_matchers/attribute_matcher.rb +20 -13
  21. data/lib/warp/model_matchers/matcher.rb +7 -1
  22. data/lib/warp/model_matchers/validation_matcher.rb +88 -2
  23. data/lib/warp/model_matchers.rb +10 -3
  24. data/lib/warp/version.rb +1 -1
  25. data/spec/spec_helper.rb +8 -0
  26. data/spec/support/match_helpers.rb +1 -1
  27. data/spec/support/model_helpers.rb +5 -0
  28. data/spec/support/with_contexts_helpers.rb +12 -2
  29. data/spec/warp/model_helpers/association_matcher_spec.rb +3 -3
  30. data/spec/warp/model_helpers/attribute_matcher_spec.rb +2 -2
  31. data/spec/warp/model_helpers/validation_matcher_spec.rb +172 -0
  32. data/warp.gemspec +1 -7
  33. metadata +8 -34
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f12aad08ee52c87c70887a3be0718247b7dc78d7
4
- data.tar.gz: 3179971a7cd9251f48252413a27c15298c74d4ff
3
+ metadata.gz: 5c7c3c6f9e427418e76e0be7e7a5f14fe6cc669b
4
+ data.tar.gz: 1ce6c0bf3dec5650c89f3016f27bd3735840808b
5
5
  SHA512:
6
- metadata.gz: d9b2432dca61f39830d3514b83d99337b6397fda5942f333d06fe78bf296d8b483b32f155a2ec9937a80b3e5eeab4012cba89286cde5122c8f68e1369b5124f8
7
- data.tar.gz: 6f45e4c01f15a0fc44a2e382ea67b5ce802a7d13d353ac7e7aaa26e35ee7bf290437794c839499454fd4dde6437e6066db2d5edddd77d77a82913556105bb7b8
6
+ metadata.gz: f53d6173f69d9da373f3632bb406a002ff55417ef7f1adba46eb01e5c6ff2576f6eb9d7101d2a9388ec2c2652d65166b09c2d2d2cf2941c659e17ce1a04ecc31
7
+ data.tar.gz: 6a9eaf01f40faf8866608e8f03c1b0579702f8f92f18fbe3d1e5d82caeac436b57aaa1a325a9e89cbc3284000fe738dce3d2e72a87138afec123ed8a21e8bc25
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ - 1.2.0
2
+ - Updated model descriptions and failure messages.
3
+
4
+ - 1.1.0
5
+ - Added model association matchers.
6
+ - Added model attribute matchers.
7
+
1
8
  - 1.0.1
2
9
  - Fixed issue where matchers would error unless explicitly passed the controller object.
3
10
 
data/Gemfile CHANGED
@@ -2,8 +2,12 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
+ gem "bundler", "~> 1.5.1"
5
6
  gem "appraisal", "1.0.0.beta2"
6
7
 
8
+ gem "rake"
9
+ gem "fuubar"
10
+
7
11
  gem "simplecov", require: false
8
12
  gem "coveralls", require: false
9
13
 
data/README.md CHANGED
@@ -21,7 +21,7 @@ And then execute:
21
21
 
22
22
  ## Usage
23
23
 
24
- ### Controller Matchers
24
+ ### Assign Matchers
25
25
 
26
26
  #### assigns(key)
27
27
 
@@ -55,6 +55,8 @@ Ensures that the specific assign is set with a instance of the specified class t
55
55
  specify { expect(controller).to assign(:post).with_a_new(Post) }
56
56
  ```
57
57
 
58
+ ### Flash Matchers
59
+
58
60
  #### set_flash(key)
59
61
 
60
62
  Ensure that the specific flash key is set:
@@ -70,7 +72,7 @@ Ensure that the specific flash key is set:
70
72
  specify { expect(controller).to set_flash(:notice).to("Your order has been processed.") }
71
73
  ```
72
74
 
73
- ### Model Matchers
75
+ ### Association Matchers
74
76
 
75
77
  #### belongs_to(association)
76
78
 
@@ -108,6 +110,8 @@ specify { expect(group).to have_and_belong_to_many(:users) }
108
110
 
109
111
  This matcher is not avaliable on Rails 4.1+, as these versions of Rails will create a `has_many :though` association instead of a 'has_and_belongs_to_many' association.
110
112
 
113
+ ### Attribute Matchers
114
+
111
115
  #### have_attribute(attribute)
112
116
 
113
117
  Checks if a certain attribute is present on a model. Works against models or model instances.
@@ -116,6 +120,99 @@ Checks if a certain attribute is present on a model. Works against models or mod
116
120
  specify { expect(user).to have_attribute(:name) }
117
121
  ```
118
122
 
123
+ ### Validation Matchers
124
+
125
+ All validation matchers can be specified with, or without options to verify.
126
+
127
+ #### validate_acceptance_of
128
+
129
+ Ensures that a `validates_acceptance_of` validator is present on the attribute.
130
+
131
+ ```ruby
132
+ specify { expect(user).to validate_acceptance_of(:terms) }
133
+ ```
134
+
135
+ #### validate_absence_of
136
+
137
+ Ensures that a `validates_absence_of` validator is present on the attribute.
138
+ Only avaliable on Rails 4+.
139
+
140
+ ```ruby
141
+ specify { expect(user).to validate_absence_of(:postcode, if: :non_us_address) }
142
+ ```
143
+
144
+ #### validate_confirmation_of
145
+
146
+ Ensures that a `validates_confirmation_of` validator is present on the attribute.
147
+
148
+ ```ruby
149
+ specify { expect(user).to validate_confirmation_of(:password) }
150
+ ```
151
+
152
+ #### validate_exclusion_of
153
+
154
+ Ensures that a `validates_exclusion_of` validator is present on the attribute.
155
+
156
+ ```ruby
157
+ specify { expect(user).to validate_exclusion_of(:age, in: 0..17) }
158
+ ```
159
+
160
+ #### validate_format_of
161
+
162
+ Ensures that a `validates_format_of` validator is present on the attribute.
163
+
164
+ ```ruby
165
+ specify { expect(user).to validate_format_of(:postcode, with: /\d{5,8}/) }
166
+ ```
167
+
168
+ #### validate_inclusion_of
169
+
170
+ Ensures that a `validates_inclusion_of` validator is present on the attribute.
171
+
172
+ ```ruby
173
+ specify { expect(user).to validate_inclusion_of(:role, in: ["develop", "design"]) }
174
+ ```
175
+
176
+ #### validate_length_of
177
+
178
+ Ensures that a `validates_length_of` validator is present on the attribute.
179
+
180
+ ```ruby
181
+ specify { expect(user).to validate_length_of(:name, in: 5..25) }
182
+ ```
183
+
184
+ #### validate_numericality_of
185
+
186
+ Ensures that a `validates_numericality_of` validator is present on the attribute.
187
+
188
+ ```ruby
189
+ specify { expect(user).to validate_numericality_of(:age) }
190
+ ```
191
+
192
+ #### validate_presence_of
193
+
194
+ Ensures that a `validates_presence_of` validator is present on the attribute.
195
+
196
+ ```ruby
197
+ specify { expect(user).to validate_presence_of(:name) }
198
+ ```
199
+
200
+ #### validate_association_of
201
+
202
+ Ensures that a `validates_association_of` validator is present on the attribute.
203
+
204
+ ```ruby
205
+ specify { expect(user).to validate_association_of(:profile) }
206
+ ```
207
+
208
+ #### validate_uniqueness_of
209
+
210
+ Ensures that a `validates_uniqueness_of` validator is present on the attribute.
211
+
212
+ ```ruby
213
+ specify { expect(user).to validate_uniqueness_of(:email, scope: :company) }
214
+ ```
215
+
119
216
  ## Contributing
120
217
 
121
218
  1. Fork it
@@ -2,7 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "bundler", "~> 1.5.1"
5
6
  gem "appraisal", "1.0.0.beta2"
7
+ gem "rake"
8
+ gem "fuubar"
6
9
  gem "simplecov", :require=>false
7
10
  gem "coveralls", :require=>false
8
11
  gem "activesupport", "~> 3.2", :require=>"active_support/all"
@@ -2,7 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "bundler", "~> 1.5.1"
5
6
  gem "appraisal", "1.0.0.beta2"
7
+ gem "rake"
8
+ gem "fuubar"
6
9
  gem "simplecov", :require=>false
7
10
  gem "coveralls", :require=>false
8
11
  gem "activesupport", "~> 3.2", :require=>"active_support/all"
@@ -2,7 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "bundler", "~> 1.5.1"
5
6
  gem "appraisal", "1.0.0.beta2"
7
+ gem "rake"
8
+ gem "fuubar"
6
9
  gem "simplecov", :require=>false
7
10
  gem "coveralls", :require=>false
8
11
  gem "activesupport", "~> 3.2", :require=>"active_support/all"
@@ -2,7 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "bundler", "~> 1.5.1"
5
6
  gem "appraisal", "1.0.0.beta2"
7
+ gem "rake"
8
+ gem "fuubar"
6
9
  gem "simplecov", :require=>false
7
10
  gem "coveralls", :require=>false
8
11
  gem "activesupport", "~> 3.2", :require=>"active_support/all"
@@ -2,7 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "bundler", "~> 1.5.1"
5
6
  gem "appraisal", "1.0.0.beta2"
7
+ gem "rake"
8
+ gem "fuubar"
6
9
  gem "simplecov", :require=>false
7
10
  gem "coveralls", :require=>false
8
11
  gem "activesupport", "~> 4.0", :require=>"active_support/all"
@@ -2,7 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "bundler", "~> 1.5.1"
5
6
  gem "appraisal", "1.0.0.beta2"
7
+ gem "rake"
8
+ gem "fuubar"
6
9
  gem "simplecov", :require=>false
7
10
  gem "coveralls", :require=>false
8
11
  gem "activesupport", "~> 4.0", :require=>"active_support/all"
@@ -2,7 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "bundler", "~> 1.5.1"
5
6
  gem "appraisal", "1.0.0.beta2"
7
+ gem "rake"
8
+ gem "fuubar"
6
9
  gem "simplecov", :require=>false
7
10
  gem "coveralls", :require=>false
8
11
  gem "activesupport", "~> 4.0", :require=>"active_support/all"
@@ -2,7 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "bundler", "~> 1.5.1"
5
6
  gem "appraisal", "1.0.0.beta2"
7
+ gem "rake"
8
+ gem "fuubar"
6
9
  gem "simplecov", :require=>false
7
10
  gem "coveralls", :require=>false
8
11
  gem "activesupport", "~> 4.0", :require=>"active_support/all"
@@ -2,7 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "bundler", "~> 1.5.1"
5
6
  gem "appraisal", "1.0.0.beta2"
7
+ gem "rake"
8
+ gem "fuubar"
6
9
  gem "simplecov", :require=>false
7
10
  gem "coveralls", :require=>false
8
11
  gem "activesupport", "4.1.0.beta1", :require=>"active_support/all"
@@ -2,7 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "bundler", "~> 1.5.1"
5
6
  gem "appraisal", "1.0.0.beta2"
7
+ gem "rake"
8
+ gem "fuubar"
6
9
  gem "simplecov", :require=>false
7
10
  gem "coveralls", :require=>false
8
11
  gem "activesupport", "4.1.0.beta1", :require=>"active_support/all"
@@ -2,7 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "bundler", "~> 1.5.1"
5
6
  gem "appraisal", "1.0.0.beta2"
7
+ gem "rake"
8
+ gem "fuubar"
6
9
  gem "simplecov", :require=>false
7
10
  gem "coveralls", :require=>false
8
11
  gem "activesupport", "4.1.0.beta1", :require=>"active_support/all"
@@ -2,7 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "bundler", "~> 1.5.1"
5
6
  gem "appraisal", "1.0.0.beta2"
7
+ gem "rake"
8
+ gem "fuubar"
6
9
  gem "simplecov", :require=>false
7
10
  gem "coveralls", :require=>false
8
11
  gem "activesupport", "4.1.0.beta1", :require=>"active_support/all"
@@ -1,3 +1,7 @@
1
+ unless defined?(ActionController)
2
+ raise RuntimeError, "ActionController is required to use Warp::ControllerMatchers."
3
+ end
4
+
1
5
  require "warp/controller_matchers/assign_matcher"
2
6
  require "warp/controller_matchers/set_flash_matcher"
3
7
 
data/lib/warp/matcher.rb CHANGED
@@ -17,7 +17,7 @@ module Warp
17
17
  # RSpec 2 and 3 have different methods
18
18
  # that they call on matcher to get the
19
19
  # failure messages.
20
- if RSpec::Version::STRING[0] == "2"
20
+ if RSpec::Version::STRING[0] == "2" || RSpec::Version::STRING == "3.0.0.beta1"
21
21
  def failure_message_for_should
22
22
  failure_message
23
23
  end
@@ -1,35 +1,43 @@
1
1
  module Warp
2
2
  module ModelMatchers
3
3
  class AssociationMatcher < Warp::ModelMatchers::Matcher
4
- attr_reader :macro, :key
5
- attr_reader :failure_message, :failure_message_when_negated, :description
6
-
7
- def initialize(macro, key)
8
- @macro = macro
4
+ attr_reader :expected_macro, :key
5
+
6
+ def initialize(expected_macro, key)
7
+ @expected_macro = expected_macro
9
8
  @key = key
10
9
  end
11
10
 
12
11
  def matches?(model_or_instance)
13
- if association = model(model_or_instance).reflect_on_association(key)
14
- actual_macro = association.macro
15
- @failure_message = "expected to have association #{macro} :#{key}, but had #{actual_macro} :#{key}"
16
- @failure_message_when_negated = "expected to not have association #{macro} :#{key}"
17
- actual_macro == macro
12
+ @model_or_instance = model_or_instance
13
+
14
+ association && values_match?(expected_macro, assocation_macro)
15
+ end
16
+
17
+ def description
18
+ "have a #{expected_macro} association with :#{key}"
19
+ end
20
+
21
+ def failure_message
22
+ if association
23
+ "expected #{model_name} to #{description}, but had a #{assocation_macro} association with :#{key}"
18
24
  else
19
- @failure_message = "expected to have association #{macro} :#{key}"
20
- @failure_message_when_negated = "expected to not have association #{macro} :#{key}"
21
- false
25
+ "expected #{model_name} to #{description}"
22
26
  end
23
27
  end
24
28
 
29
+ def failure_message_when_negated
30
+ "expected #{model_name} to not #{description}"
31
+ end
32
+
25
33
  private
26
34
 
27
- def model(model_or_instance)
28
- if model_or_instance.is_a? Class
29
- model_or_instance
30
- else
31
- model_or_instance.class
32
- end
35
+ def association
36
+ model.reflect_on_association(key)
37
+ end
38
+
39
+ def assocation_macro
40
+ association.macro
33
41
  end
34
42
  end
35
43
 
@@ -1,27 +1,34 @@
1
- module Warp
1
+ module Warp
2
2
  module ModelMatchers
3
3
  class AttributeMatcher < Warp::ModelMatchers::Matcher
4
4
  attr_reader :attr_name
5
- attr_reader :failure_message, :failure_message_when_negated, :description
6
5
 
7
6
  def initialize(attr_name)
8
7
  @attr_name = attr_name.to_sym
9
8
  end
10
9
 
11
10
  def matches?(model_or_instance)
12
- if attributes(model_or_instance).any? {|actual| values_match?(attr_name, actual) }
13
- @failure_message = "expected to have attribute #{description_of(attr_name)}"
14
- @failure_message_when_negated = "expected to not have attribute #{description_of(attr_name)}"
15
- true
16
- else
17
- @failure_message = "expected to have attribute #{description_of(attr_name)}"
18
- @failure_message_when_negated = "expected to not have attribute #{description_of(attr_name)}"
19
- false
20
- end
11
+ @model_or_instance = model_or_instance
12
+
13
+ attributes.any? {|actual| values_match?(attr_name, actual) }
14
+ end
15
+
16
+ def description
17
+ "have attribute #{description_of(attr_name)}"
18
+ end
19
+
20
+ def failure_message
21
+ "expected #{model_name} to #{description}"
22
+ end
23
+
24
+ def failure_message_when_negated
25
+ "expected #{model_name} to not #{description}"
21
26
  end
27
+
28
+ private
22
29
 
23
- def attributes(model_or_instance)
24
- model(model_or_instance).column_names.map(&:to_sym)
30
+ def attributes
31
+ model.column_names.map(&:to_sym)
25
32
  end
26
33
  end
27
34
 
@@ -1,15 +1,21 @@
1
1
  module Warp
2
2
  module ModelMatchers
3
3
  class Matcher < Warp::Matcher
4
+ attr_reader :model_or_instance
5
+
4
6
  private
5
7
 
6
- def model(model_or_instance)
8
+ def model
7
9
  if model_or_instance.is_a? Class
8
10
  model_or_instance
9
11
  else
10
12
  model_or_instance.class
11
13
  end
12
14
  end
15
+
16
+ def model_name
17
+ model.name
18
+ end
13
19
  end
14
20
  end
15
21
  end
@@ -1,12 +1,98 @@
1
1
  module Warp
2
2
  module ModelMatchers
3
- class ValidationMatcher < Warp::Matcher
3
+ class ValidationMatcher < Warp::ModelMatchers::Matcher
4
+ VALIDATORS = [
5
+ ActiveModel::Validations::AcceptanceValidator,
6
+ ActiveModel::Validations::ConfirmationValidator,
7
+ ActiveModel::Validations::ExclusionValidator,
8
+ ActiveModel::Validations::FormatValidator,
9
+ ActiveModel::Validations::InclusionValidator,
10
+ ActiveModel::Validations::LengthValidator,
11
+ ActiveModel::Validations::NumericalityValidator,
12
+ ActiveModel::Validations::PresenceValidator
13
+ ]
4
14
 
15
+ # AbsenceValidator added in Rails 4
16
+ if defined?(ActiveModel::Validations::AbsenceValidator)
17
+ VALIDATORS << ActiveModel::Validations::AbsenceValidator
18
+ end
5
19
 
20
+ if defined?(ActiveRecord)
21
+ VALIDATORS.concat [
22
+ ActiveRecord::Validations::AssociatedValidator,
23
+ ActiveRecord::Validations::UniquenessValidator
24
+ ]
25
+ end
26
+
27
+ # In Rails 4 PresenceValidator is subclassed by AR
28
+ if defined?(ActiveRecord::Validations::PresenceValidator)
29
+ VALIDATORS.delete(ActiveModel::Validations::PresenceValidator)
30
+ VALIDATORS.push(ActiveRecord::Validations::PresenceValidator)
31
+ end
32
+
33
+ VALIDATORS.freeze
34
+
35
+ attr_reader :attr_name, :validator_class, :validator_options, :display_options
36
+
37
+ def initialize(attr_name, validator_class, validator_options, display_options)
38
+ @attr_name = attr_name
39
+ @validator_class = validator_class
40
+ @validator_options = validator_options
41
+ @display_options = display_options
42
+ end
43
+
44
+ def matches?(model_or_instance)
45
+ @model_or_instance = model_or_instance
46
+
47
+ validators.any? do |validator|
48
+ if values_match?(validator_class, validator.class)
49
+ validator_options.nil? || values_match?(validator_options, validator.options)
50
+ else
51
+ false
52
+ end
53
+ end
54
+ end
55
+
56
+ def failure_message
57
+ "expected #{model_name} to #{description}"
58
+ end
59
+
60
+ def failure_message_when_negated
61
+ "expected #{model_name} to not #{description}"
62
+ end
63
+
64
+ def description
65
+ str = "have validator #{validator_class.name} on :#{attr_name}"
66
+ str << " with options #{description_of(display_options)}" if display_options.present?
67
+ str
68
+ end
69
+
70
+ private
71
+
72
+ def validators
73
+ model._validators[attr_name]
74
+ end
6
75
  end
7
76
 
8
- def validate
77
+ ValidationMatcher::VALIDATORS.each do |validator|
78
+ validator_name = validator.name.match(/::(?<name>\w+)Validator/)[:name].underscore.to_sym
79
+ method_name = (validator_name == :associated) ? "validate_associated" : "validate_#{validator_name}_of"
80
+
81
+ define_method method_name do |attr_name, *options|
82
+ display_options = options.first
83
+ options = display_options.try(:dup) || {}
84
+
85
+ case validator_name
86
+ when :uniqueness
87
+ options = {case_sensitive: true}.merge(options)
88
+ when :acceptance
89
+ options = {allow_nil: true, accept: "1"}.merge(options)
90
+ end
91
+
92
+ options = nil if options.empty?
9
93
 
94
+ ValidationMatcher.new(attr_name, validator, options, display_options)
95
+ end
10
96
  end
11
97
  end
12
98
  end
@@ -1,9 +1,16 @@
1
+ unless defined?(ActiveModel)
2
+ raise RuntimeError, "ActiveModel is required to use Warp::ModelMatchers."
3
+ end
4
+
1
5
  require "warp/model_matchers/matcher"
2
6
 
3
- require "warp/model_matchers/association_matcher"
4
- require "warp/model_matchers/attribute_matcher"
5
7
  # require "warp/model_matchers/error_matcher"
6
- # require "warp/model_matchers/validation_matcher"
8
+ require "warp/model_matchers/validation_matcher"
9
+
10
+ if defined?(ActiveRecord)
11
+ require "warp/model_matchers/association_matcher"
12
+ require "warp/model_matchers/attribute_matcher"
13
+ end
7
14
 
8
15
  RSpec.configure do |config|
9
16
  config.include Warp::ModelMatchers
data/lib/warp/version.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Warp
2
2
  module VERSION
3
3
  MAJOR = 1
4
- MINOR = 1
4
+ MINOR = 2
5
5
  PATCH = 0
6
6
 
7
7
  BETA = nil
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,13 @@
1
1
  require "bundler"
2
2
 
3
+ unless ENV["TRAVIS_CI"]
4
+ if RUBY_VERSION[0] == "2"
5
+ require "byebug"
6
+ else
7
+ require "debugger"
8
+ end
9
+ end
10
+
3
11
  require "simplecov"
4
12
 
5
13
  if ENV["TRAVIS_CI"]
@@ -1,5 +1,5 @@
1
1
  module MatchHelpers
2
- class MatchMatcher
2
+ class MatchMatcher < Warp::Matcher
3
3
  attr_reader :value, :matcher
4
4
 
5
5
  def initialize(value)
@@ -14,6 +14,11 @@ module ModelHelpers
14
14
  @columns ||= []
15
15
  end
16
16
 
17
+ def self.attribute_method?(method)
18
+ method = method.to_s.sub("=", "")
19
+ columns.any? {|c| c.name == method }
20
+ end
21
+
17
22
  def self.column(name, sql_type = nil, default = nil, null = true)
18
23
  columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
19
24
  end
@@ -2,8 +2,6 @@ module WithContextsHelpers
2
2
  class WithContextsBuilder
3
3
  attr_accessor :contexts, :examples, :group
4
4
 
5
- delegate :let, :before, :after, :subject, to: :group
6
-
7
5
  def initialize(group)
8
6
  @contexts = {}
9
7
  @group = group
@@ -21,6 +19,18 @@ module WithContextsHelpers
21
19
  self.examples = blk
22
20
  end
23
21
 
22
+ def let(*args, &blk)
23
+ group.let(*args, &blk)
24
+ end
25
+
26
+ def before(*args, &blk)
27
+ group.before(*args, &blk)
28
+ end
29
+
30
+ def after(*args, &blk)
31
+ group.after(*args, &blk)
32
+ end
33
+
24
34
  def execute
25
35
  contexts.each do |name, blk|
26
36
  context = group.context(name)
@@ -70,7 +70,7 @@ describe Warp::ModelMatchers::AssociationMatcher do
70
70
  specify { expect(subject).to match(model_or_instance) }
71
71
 
72
72
  describe_failure_message_when_negated do
73
- specify { expect(subject).to eq "expected to not have association #{matcher_macro} :#{key}" }
73
+ specify { expect(subject).to eq "expected TestModel to not have a #{matcher_macro} association with :#{key}" }
74
74
  end
75
75
  end
76
76
 
@@ -81,7 +81,7 @@ describe Warp::ModelMatchers::AssociationMatcher do
81
81
  specify { expect(subject).to_not match(model_or_instance) }
82
82
 
83
83
  describe_failure_message do
84
- specify { expect(subject).to eq "expected to have association #{matcher_macro} :#{key}, but had #{actual_macro} :#{key}" }
84
+ specify { expect(subject).to eq "expected TestModel to have a #{matcher_macro} association with :#{key}, but had a #{actual_macro} association with :#{key}" }
85
85
  end
86
86
  end
87
87
  end
@@ -92,7 +92,7 @@ describe Warp::ModelMatchers::AssociationMatcher do
92
92
  specify { expect(subject).to_not match(model_or_instance) }
93
93
 
94
94
  describe_failure_message do
95
- specify { expect(subject).to eq "expected to have association #{matcher_macro} :#{key}" }
95
+ specify { expect(subject).to eq "expected TestModel to have a #{matcher_macro} association with :#{key}" }
96
96
  end
97
97
  end
98
98
  end
@@ -25,7 +25,7 @@ describe Warp::ModelMatchers::AttributeMatcher do
25
25
  specify { expect(subject).to match(model_or_instance) }
26
26
 
27
27
  describe_failure_message_when_negated do
28
- specify { expect(subject).to eq "expected to not have attribute :#{attr_name}" }
28
+ specify { expect(subject).to eq "expected TestModel to not have attribute :#{attr_name}" }
29
29
  end
30
30
  end
31
31
 
@@ -35,7 +35,7 @@ describe Warp::ModelMatchers::AttributeMatcher do
35
35
  specify { expect(subject).to_not match(model_or_instance) }
36
36
 
37
37
  describe_failure_message do
38
- specify { expect(subject).to eq "expected to have attribute :#{attr_name}" }
38
+ specify { expect(subject).to eq "expected TestModel to have attribute :#{attr_name}" }
39
39
  end
40
40
  end
41
41
  end
@@ -0,0 +1,172 @@
1
+ require "spec_helper"
2
+
3
+ describe Warp::ModelMatchers::ValidationMatcher do
4
+ build_model do
5
+ column :foo
6
+ end
7
+
8
+ let(:attr_name) { :foo }
9
+
10
+ let(:matcher) { send(matcher_method, attr_name) }
11
+ let(:matcher_with_options) { send(matcher_method, attr_name, matcher_options) }
12
+
13
+ let(:validator_name) { matcher.validator_class.name }
14
+
15
+ with_contexts do
16
+ context "with model" do
17
+ let(:model_or_instance) { model }
18
+ end
19
+
20
+ context "with model instance" do
21
+ let(:model_or_instance) { model.new }
22
+ end
23
+
24
+ behaviour do
25
+ with_contexts do
26
+ # AbsenceValidator added in Rails 4
27
+ if defined?(ActiveModel::Validations::AbsenceValidator)
28
+ context "#validate_absence_of" do
29
+ let(:matcher_method) { :validate_absence_of }
30
+ let(:matcher_options) { {message: "must be blank"} }
31
+ let(:validation_method) { :validates_absence_of }
32
+ let(:validation_base_options) { {} }
33
+ end
34
+ end
35
+
36
+ context "#validate_acceptance_of" do
37
+ let(:matcher_method) { :validate_acceptance_of }
38
+ let(:matcher_options) { {if: :enabled?} }
39
+ let(:validation_method) { :validates_acceptance_of }
40
+ let(:validation_base_options) { {} }
41
+ end
42
+
43
+ context "#validate_confirmation_of" do
44
+ let(:matcher_method) { :validate_confirmation_of }
45
+ let(:matcher_options) { {unless: :tuesday?} }
46
+ let(:validation_method) { :validates_confirmation_of }
47
+ let(:validation_base_options) { {} }
48
+ end
49
+
50
+ context "#validate_exclusion_of" do
51
+ let(:matcher_method) { :validate_exclusion_of }
52
+ let(:matcher_options) { {in: 12..500} }
53
+ let(:validation_method) { :validates_exclusion_of }
54
+ let(:validation_base_options) { {in: [12, 500]} }
55
+ end
56
+
57
+ context "#validate_format_of" do
58
+ let(:matcher_method) { :validate_format_of }
59
+ let(:matcher_options) { {with: /foo[bar]*/} }
60
+ let(:validation_method) { :validates_format_of }
61
+ let(:validation_base_options) { {with: /qu+x/} }
62
+ end
63
+
64
+ context "#validate_inclusion_of" do
65
+ let(:matcher_method) { :validate_inclusion_of }
66
+ let(:matcher_options) { {in: ["foo", "bar", "baz", "qux"]} }
67
+ let(:validation_method) { :validates_inclusion_of }
68
+ let(:validation_base_options) { {in: 1..10} }
69
+ end
70
+
71
+ context "#validate_length_of" do
72
+ let(:matcher_method) { :validate_length_of }
73
+ let(:matcher_options) { {maximum: 32} }
74
+ let(:validation_method) { :validates_length_of }
75
+ let(:validation_base_options) { {is: 32} }
76
+ end
77
+
78
+ context "#validate_numericality_of" do
79
+ let(:matcher_method) { :validate_numericality_of }
80
+ let(:matcher_options) { {even: true} }
81
+ let(:validation_method) { :validates_numericality_of }
82
+ let(:validation_base_options) { {} }
83
+ end
84
+
85
+ context "#validate_presence_of" do
86
+ let(:matcher_method) { :validate_presence_of }
87
+ let(:matcher_options) { {unless: :not_required} }
88
+ let(:validation_method) { :validates_presence_of }
89
+ let(:validation_base_options) { {} }
90
+ end
91
+
92
+ context "#validate_association_of" do
93
+ let(:matcher_method) { :validate_associated }
94
+ let(:matcher_options) { {message: "it's neither here nor there"} }
95
+ let(:validation_method) { :validates_associated }
96
+ let(:validation_base_options) { {} }
97
+ end
98
+
99
+ context "#validate_uniqueness_of" do
100
+ let(:matcher_method) { :validate_uniqueness_of }
101
+ let(:matcher_options) { {scope: :post_id} }
102
+ let(:validation_method) { :validates_uniqueness_of }
103
+ let(:validation_base_options) { {} }
104
+ end
105
+
106
+ behaviour do
107
+ context "when matching without options" do
108
+ subject { matcher.tap {|m| m.matches?(model_or_instance) } }
109
+
110
+ context "with no matching validation" do
111
+ specify { expect(subject).to_not match(model_or_instance) }
112
+
113
+ describe_failure_message do
114
+ specify { expect(subject).to eq "expected TestModel to have validator #{validator_name} on :#{attr_name}" }
115
+ end
116
+ end
117
+
118
+ context "with a matching validation" do
119
+ before do
120
+ model.send(validation_method, attr_name, validation_base_options)
121
+ end
122
+
123
+ specify { expect(subject).to match(model_or_instance) }
124
+
125
+ describe_failure_message_when_negated do
126
+ specify { expect(subject).to eq "expected TestModel to not have validator #{validator_name} on :#{attr_name}" }
127
+ end
128
+ end
129
+ end
130
+
131
+ context "when matching with options" do
132
+ subject { matcher_with_options.tap {|m| m.matches?(model_or_instance) } }
133
+
134
+ context "with no matching validation" do
135
+ specify { expect(subject).to_not match(model_or_instance) }
136
+
137
+ describe_failure_message do
138
+ specify { expect(subject).to eq "expected TestModel to have validator #{validator_name} on :#{attr_name} with options #{matcher_options.inspect}" }
139
+ end
140
+ end
141
+
142
+ context "with a matching validation" do
143
+ context "with incorrect options" do
144
+ before do
145
+ model.send(validation_method, attr_name, validation_base_options)
146
+ end
147
+
148
+ specify { expect(subject).to_not match(model_or_instance) }
149
+
150
+ describe_failure_message do
151
+ specify { expect(subject).to eq "expected TestModel to have validator #{validator_name} on :#{attr_name} with options #{matcher_options.inspect}" }
152
+ end
153
+ end
154
+
155
+ context "with correct options" do
156
+ before do
157
+ model.send(validation_method, attr_name, matcher_options)
158
+ end
159
+
160
+ specify { expect(subject).to match(model_or_instance) }
161
+
162
+ describe_failure_message_when_negated do
163
+ specify { expect(subject).to eq "expected TestModel to not have validator #{validator_name} on :#{attr_name} with options #{matcher_options.inspect}" }
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
data/warp.gemspec CHANGED
@@ -14,14 +14,8 @@ Gem::Specification.new do |spec|
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
17
  spec.test_files = spec.files.grep(%r{^(spec)/})
19
18
  spec.require_paths = ["lib"]
20
19
 
21
- # TODO: When RSpec 3 is released.
22
- # spec.add_runtime_dependency "rspec", "~> 3.0.0"
23
-
24
- spec.add_development_dependency "bundler", "~> 1.5.1"
25
- spec.add_development_dependency "rake"
26
- spec.add_development_dependency "fuubar"
20
+ spec.add_runtime_dependency "rspec", ">= 2.14.0"
27
21
  end
metadata CHANGED
@@ -1,57 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: warp
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Drake-Brockman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-11 00:00:00.000000000 Z
11
+ date: 2014-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: 1.5.1
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: 1.5.1
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: fuubar
14
+ name: rspec
43
15
  requirement: !ruby/object:Gem::Requirement
44
16
  requirements:
45
17
  - - ">="
46
18
  - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
19
+ version: 2.14.0
20
+ type: :runtime
49
21
  prerelease: false
50
22
  version_requirements: !ruby/object:Gem::Requirement
51
23
  requirements:
52
24
  - - ">="
53
25
  - !ruby/object:Gem::Version
54
- version: '0'
26
+ version: 2.14.0
55
27
  description: Rails matchers for your RSpec specs.
56
28
  email:
57
29
  - thom@sfedb.com
@@ -105,6 +77,7 @@ files:
105
77
  - spec/warp/controller_matchers/set_flash_matcher_spec.rb
106
78
  - spec/warp/model_helpers/association_matcher_spec.rb
107
79
  - spec/warp/model_helpers/attribute_matcher_spec.rb
80
+ - spec/warp/model_helpers/validation_matcher_spec.rb
108
81
  - warp.gemspec
109
82
  homepage: ''
110
83
  licenses:
@@ -141,3 +114,4 @@ test_files:
141
114
  - spec/warp/controller_matchers/set_flash_matcher_spec.rb
142
115
  - spec/warp/model_helpers/association_matcher_spec.rb
143
116
  - spec/warp/model_helpers/attribute_matcher_spec.rb
117
+ - spec/warp/model_helpers/validation_matcher_spec.rb