warp 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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