rspec-sleeping_king_studios 1.0.0.rc.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +323 -0
  4. data/lib/rspec/sleeping_king_studios.rb +5 -0
  5. data/lib/rspec/sleeping_king_studios/matchers.rb +5 -0
  6. data/lib/rspec/sleeping_king_studios/matchers/active_model.rb +5 -0
  7. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors.rb +219 -0
  8. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors/error_expectation.rb +60 -0
  9. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors/message_expectation.rb +17 -0
  10. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors/require.rb +7 -0
  11. data/lib/rspec/sleeping_king_studios/matchers/active_model/require.rb +8 -0
  12. data/lib/rspec/sleeping_king_studios/matchers/base_matcher.rb +43 -0
  13. data/lib/rspec/sleeping_king_studios/matchers/built_in.rb +5 -0
  14. data/lib/rspec/sleeping_king_studios/matchers/built_in/be_kind_of.rb +68 -0
  15. data/lib/rspec/sleeping_king_studios/matchers/built_in/include.rb +92 -0
  16. data/lib/rspec/sleeping_king_studios/matchers/built_in/require.rb +7 -0
  17. data/lib/rspec/sleeping_king_studios/matchers/built_in/respond_to.rb +187 -0
  18. data/lib/rspec/sleeping_king_studios/matchers/core.rb +5 -0
  19. data/lib/rspec/sleeping_king_studios/matchers/core/be_boolean.rb +41 -0
  20. data/lib/rspec/sleeping_king_studios/matchers/core/construct.rb +138 -0
  21. data/lib/rspec/sleeping_king_studios/matchers/core/have_property.rb +84 -0
  22. data/lib/rspec/sleeping_king_studios/matchers/core/have_reader.rb +76 -0
  23. data/lib/rspec/sleeping_king_studios/matchers/core/have_writer.rb +101 -0
  24. data/lib/rspec/sleeping_king_studios/matchers/core/require.rb +7 -0
  25. data/lib/rspec/sleeping_king_studios/matchers/meta.rb +5 -0
  26. data/lib/rspec/sleeping_king_studios/matchers/meta/fail_with_actual.rb +142 -0
  27. data/lib/rspec/sleeping_king_studios/matchers/meta/pass_with_actual.rb +96 -0
  28. data/lib/rspec/sleeping_king_studios/matchers/meta/require.rb +7 -0
  29. data/lib/rspec/sleeping_king_studios/matchers/require.rb +12 -0
  30. data/lib/rspec/sleeping_king_studios/matchers/shared/match_parameters.rb +69 -0
  31. data/lib/rspec/sleeping_king_studios/matchers/shared/require.rb +7 -0
  32. data/lib/rspec/sleeping_king_studios/mocks/custom_double.rb +13 -0
  33. data/lib/rspec/sleeping_king_studios/require.rb +7 -0
  34. data/lib/rspec/sleeping_king_studios/version.rb +7 -0
  35. metadata +151 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a201081c88d39452f78afa3150316e817901a52d
4
+ data.tar.gz: 1ea674d3e88024e1d945b17e1ecd10d5c09d722a
5
+ SHA512:
6
+ metadata.gz: ee4bdd1817d0d128b1e30304be501c63990545464bb7fa69dc272939073f487f26e5c32480aa7d00324c4d32d24a2cbc27738bb8ec374a671801ff09c03c1756
7
+ data.tar.gz: 8003b45634d319d7619a712dfece3d51df24e91394c294667e64e26e73770a2b99d6ae8986ded60be8902a055f5829a1fc25777d16f5a281d8ec2a404a47b523
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2013 Rob Smith
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,323 @@
1
+ # RSpec::SleepingKingStudios
2
+
3
+ A collection of matchers and extensions to ease TDD/BDD using RSpec.
4
+
5
+ ## The Extensions
6
+
7
+ To enable an extension, simply require the associated file.
8
+
9
+ ### Mocks
10
+
11
+ These extensions support the creation and use of mock objects.
12
+
13
+ #### custom\_double
14
+
15
+ require 'rspec/sleeping_king_studios/mocks/custom_double'
16
+
17
+ As the built-in 'double' method, but accepts a block that is passed to
18
+ Class.new when the double is created, allowing you to create functional class
19
+ and instance methods on the double. Useful when you need to test a function or
20
+ sequence that repeatedly updates or checks the state of the injected object.
21
+
22
+ **How To Use:**
23
+
24
+ custom_double('My Double', :foo => "Foo") { attr_accessor :bar }
25
+
26
+ ## The Matchers
27
+
28
+ To enable a custom matcher, simply require the associated file. Matchers can be
29
+ required individually or by category:
30
+
31
+ require 'rspec/sleeping_king_studios/matchers/core'
32
+ #=> requires all of the core matchers
33
+
34
+ require 'rspec/sleeping_king_studios/matchers/core/construct'
35
+ #=> requires only the :construct matcher
36
+
37
+ ### ActiveModel
38
+
39
+ require 'rspec/sleeping_king_studios/matchers/active_model'
40
+
41
+ These matchers validate ActiveModel functionality, such as validations.
42
+
43
+ #### have\_errors Matcher
44
+
45
+ require 'rspec/sleeping_king_studios/matchers/active_model/have_errors'
46
+
47
+ Verifies that the actual object has validation errors. Optionally can specify
48
+ individual fields to validate, or even specific messages for each attribute.
49
+
50
+ **How To Use:**
51
+
52
+ expect(instance).to have_errors
53
+
54
+ expect(instance).to have_errors.on(:name)
55
+
56
+ expect(instance).to have_errors.on(:name).with_message('not to be nil')
57
+
58
+ **Chaining:**
59
+
60
+ * **on:** [String, Symbol] Adds a field to validate; the matcher only passes if
61
+ all validated fields have errors.
62
+ * **with\_message:** [String] Adds a message to the previously-defined field
63
+ validation. Raises ArgumentError if no field was previously set.
64
+
65
+ ### BuiltIn
66
+
67
+ require 'rspec/sleeping_king_studios/matchers/built_in'
68
+
69
+ These extend the built-in RSpec matchers with additional functionality.
70
+
71
+ #### be\_kind\_of Matcher
72
+
73
+ require 'rspec/sleeping_king_studios/matchers/built_in/be_kind_of'
74
+
75
+ Now accepts an Array of types. The matcher passes if the actual object is
76
+ any of the parameter types.
77
+
78
+ Also allows nil parameter as a shortcut for NilClass.
79
+
80
+ **How To Use:**
81
+
82
+ expect(instance).to be_kind_of [String, Symbol, nil]
83
+ #=> passes iff instance is a String, a Symbol, or is nil
84
+
85
+ #### include Matcher
86
+
87
+ require 'rspec/sleeping_king_studios/matchers/built_in/include'
88
+
89
+ Now accepts Proc parameters; items in the actual object are passed into
90
+ proc#call, with a truthy response considered a match to the item. In addition,
91
+ now accepts an optional block as a shortcut for adding a proc expectation.
92
+
93
+ **How To Use:**
94
+
95
+ expect(instance).to include { |item| item =~ /pattern/ }
96
+
97
+ #### respond\_to Matcher
98
+
99
+ require 'rspec/sleeping_king_studios/matchers/built_in/respond_to'
100
+
101
+ Now has additional chaining functionality to validate the number of arguments
102
+ accepted by the method, and whether the method accepts a block argument.
103
+
104
+ **How To Use:**
105
+
106
+ expect(instance).to respond_to(:foo).with(2..3).arguments.and.a_block
107
+
108
+ **Chaining:**
109
+
110
+ * **a\_block:** No parameters. Verifies that the method requires a block
111
+ argument of the form &my_argument. _Important note:_ A negative result does
112
+ _not* mean the method cannot accept a block, merely that it does not require
113
+ one. Also, does _not_ check whether the block is called or yielded.
114
+ * **with:** Expects one Integer or Range argument. If an Integer, verifies that
115
+ the method accepts that number of arguments; if a Range, verifies that the
116
+ method accepts both the minimum and maximum number of arguments.
117
+
118
+ ##### Ruby 2.0
119
+
120
+ Has additional functionality to support Ruby 2.0 keyword arguments.
121
+
122
+ **How To Use:**
123
+ expect(instance).to respond_to(:foo).with(0, :bar, :baz)
124
+
125
+ **Chaining:**
126
+
127
+ * **with:** Expects one Integer, Range, or nil argument, and zero or more
128
+ Symbol arguments corresponding to optional keywords. Verifies that the method
129
+ accepts that keyword, or has a variadic keyword of the form \*\*params.
130
+
131
+ _Important note:_ If you do not wish to validate the number of arguments,
132
+ make sure to use nil as the first argument to #with; otherwise, the matcher
133
+ will interpret your first keyword as the number of arguments to expect. And
134
+ then explode.
135
+
136
+ ### Core
137
+
138
+ require 'rspec/sleeping_king_studios/matchers/core'
139
+
140
+ These matchers check core functionality, such as object boolean-ness, the
141
+ existence of properties, and so on.
142
+
143
+ #### be_boolean Matcher
144
+
145
+ require 'rspec/sleeping_king_studios/matchers/core/be_boolean'
146
+
147
+ Checks if the provided object is true or false.
148
+
149
+ **How To Use:**
150
+
151
+ expect(object).to be_boolean
152
+
153
+ **Parameters:** None.
154
+
155
+ #### construct Matcher
156
+
157
+ require 'rspec/sleeping_king_studios/matchers/core/construct'
158
+
159
+ Verifies that the actual object can be constructed using :new. Can take an
160
+ optional number of arguments.
161
+
162
+ **How To Use:**
163
+
164
+ expect(described_class).to construct.with(1).arguments
165
+
166
+ **Parameters:** None.
167
+
168
+ **Chaining:**
169
+
170
+ * **with:** Expects one Integer or Range argument. If an Integer, verifies that
171
+ the class's constructor accepts that number of arguments; if a Range,
172
+ verifies that the constructor accepts both the minimum and maximum number of
173
+ arguments.
174
+
175
+ ##### Ruby 2.0
176
+
177
+ Has additional functionality to support Ruby 2.0 keyword arguments.
178
+
179
+ **How To Use:**
180
+ expect(instance).to construct.with(0, :bar, :baz)
181
+
182
+ **Chaining:**
183
+
184
+ * **with:** Expects one Integer, Range, or nil argument, and zero or more
185
+ Symbol arguments corresponding to optional keywords. Verifies that the
186
+ class's constructor accepts that keyword, or has a variadic keyword of the
187
+ form \*\*params.
188
+
189
+ _Important note:_ If you do not wish to validate the number of arguments,
190
+ make sure to use nil as the first argument to #with; otherwise, the matcher
191
+ will interpret your first keyword as the number of arguments to expect. And
192
+ then explode.
193
+
194
+ #### have\_property Matcher
195
+
196
+ require 'rspec/sleeping_king_studios/matchers/core/have_property'
197
+
198
+ Checks if the actual object responds to :property and :property=, and
199
+ optionally if a value written to actual.property= can then be read by
200
+ actual.property.
201
+
202
+ **How To Use:**
203
+
204
+ expect(instance).to have_property(:foo).with("foo")
205
+
206
+ **Parameters:** Property. Expects a string or symbol that is a valid
207
+ identifier.
208
+
209
+ **Chaining:**
210
+
211
+ * **with:** Expects one object, which is written to actual.property= and then
212
+ read from actual.property.
213
+
214
+ #### have\_reader Matcher
215
+
216
+ require 'rspec/sleeping_king_studios/matchers/core/have_reader'
217
+
218
+ Checks if the actual object responds to :property, and optionally if the
219
+ current value of actual.property is equal to a specified value.
220
+
221
+ **How To Use:**
222
+
223
+ expect(instance).to have_reader(:foo).with("foo")
224
+
225
+ **Parameters:** Property. Expects a string or symbol that is a valid
226
+ identifier.
227
+
228
+ **Chaining:**
229
+
230
+ * **with:** Expects one object, which is checked against the current value of
231
+ actual.property if actual responds to :property.
232
+
233
+ #### have\_writer Matcher
234
+
235
+ require 'rspec/sleeping_king_studios/matchers/core/have_writer'
236
+
237
+ Checks if the actual object responds to :property=, and optionally if setting
238
+ object.property = value sets object.property to value.
239
+
240
+ **How To Use:**
241
+
242
+ expect(instance).to have_writer(:foo=).with("foo")
243
+
244
+ **Parameters:** Property. Expects a string or symbol that is a valid
245
+ identifier. An equals sign '=' is automatically added if the identifier does
246
+ not already terminate in '='.
247
+
248
+ **Chaining:**
249
+
250
+ * **with:** Expects one object. The matcher attempts to set the actual's value
251
+ using actual.property=, then compare the value with actual.property.
252
+
253
+ _Note:_ Currently, write-only properties cannot be checked using with().
254
+ Attempting to do so will raise an exception.
255
+
256
+ #### include\_matching Matcher
257
+
258
+ require 'rspec/sleeping_king_studios/matchers/core/include_matching'
259
+
260
+ Loops through an enumerable actual object and checks if any of the items
261
+ matches the given pattern.
262
+
263
+ **How To Use:**
264
+
265
+ expect(instance).to include_matching(/[01]+/)
266
+
267
+ **Parameters:** Pattern. Expects a Regexp.
268
+
269
+ ### Meta
270
+
271
+ require 'rspec/sleeping_king_studios/matchers/meta'
272
+
273
+ These meta-matchers are used to test other custom matchers.
274
+
275
+ #### fail\_with\_actual Matcher
276
+
277
+ require 'rspec/sleeping_king_studios/matchers/meta/fail_with_actual'
278
+
279
+ Checks if the given matcher will fail to match a specified actual object. Can
280
+ take an optional string to check the expected failure message when the matcher
281
+ is expected to pass, but does not.
282
+
283
+ _Note:_ Do not use the not\_to syntax for this matcher; instead, use the
284
+ pass\_with\_actual matcher, below.
285
+
286
+ **How To Use:**
287
+
288
+ expect(matcher).to fail_with_actual(actual).with_message(/expected to/)
289
+
290
+ **Parameters:** Matcher. Expects an object that, at minimum, responds to
291
+ :matches? and :failure\_message\_for\_should.
292
+
293
+ **Chaining:**
294
+
295
+ * **with\_message:** Expects one String or Regexp argument, which is matched
296
+ against the given matcher's failure\_message\_for\_should.
297
+
298
+ #### pass\_with\_actual Matcher
299
+
300
+ require 'rspec/sleeping_king_studios/matchers/meta/pass_with_actual'
301
+
302
+ Checks if the given matcher will match a specified actual object. Can take an
303
+ optional string to check the expected failure message when the matcher is
304
+ expected to fail, but does not.
305
+
306
+ _Note:_ Do not use the not\_to syntax for this matcher; instead, use the
307
+ fail\_with\_actual matcher, above.
308
+
309
+ **How To Use:**
310
+
311
+ expect(matcher).to pass_with_actual(actual)
312
+
313
+ **Parameters:** Matcher. Expects an object that, at minimum, responds to
314
+ :matches? and :failure\_message\_for\_should\_not.
315
+
316
+ **Chaining:**
317
+
318
+ * **with\_message:** Expects one String or Regexp argument, which is matched
319
+ against the given matcher's failure\_message\_for\_should\_not.
320
+
321
+ ## License
322
+
323
+ RSpec::SleepingKingStudios is released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -0,0 +1,5 @@
1
+ # lib/rspec/sleeping_king_studios.rb
2
+
3
+ require 'rspec/sleeping_king_studios/matchers'
4
+
5
+ require 'rspec/sleeping_king_studios/mocks/custom_double'
@@ -0,0 +1,5 @@
1
+ # lib/rspec/sleeping_king_studios/matchers.rb
2
+
3
+ %w(active_model built_in core meta).each do |dir_name|
4
+ require File.join File.dirname(__FILE__), 'matchers', dir_name
5
+ end # each
@@ -0,0 +1,5 @@
1
+ # lib/rspec/sleeping_king_studios/matchers/active_model.rb
2
+
3
+ Dir[File.join File.dirname(__FILE__), 'active_model', '*.rb'].each do |file|
4
+ require file
5
+ end # end each
@@ -0,0 +1,219 @@
1
+ # lib/rspec/sleeping_king_studios/matchers/active_model/have_errors.rb
2
+
3
+ require 'rspec/sleeping_king_studios/matchers/base_matcher'
4
+ require 'rspec/sleeping_king_studios/matchers/active_model/require'
5
+ require 'rspec/sleeping_king_studios/matchers/active_model/have_errors/error_expectation'
6
+
7
+ module RSpec::SleepingKingStudios::Matchers::ActiveModel
8
+ # Matcher for testing ActiveModel object validations.
9
+ #
10
+ # @since 1.0.0
11
+ class HaveErrorsMatcher < RSpec::SleepingKingStudios::Matchers::BaseMatcher
12
+ include RSpec::SleepingKingStudios::Matchers::ActiveModel::HaveErrors
13
+
14
+ def initialize
15
+ super
16
+
17
+ # The error and message expectations set up through #on and
18
+ # #with_message.
19
+ @error_expectations = []
20
+ end # constructor
21
+
22
+ # Checks if the object can be validated, whether the object is valid, and
23
+ # checks the errors on the object against the expected errors and messages
24
+ # from #on and #with_message, if any.
25
+ #
26
+ # @param [Object] actual the object to test against the matcher
27
+ #
28
+ # @return [Boolean] true if the object responds to :valid?, is not valid,
29
+ # and object.errors matches the specified errors and messages (if any);
30
+ # otherwise false
31
+ # @see RSpec::SleepingKingStudios::Matchers::BaseMatcher#matches?
32
+ def matches? actual
33
+ super
34
+
35
+ return false unless @validates = actual.respond_to?(:valid?)
36
+
37
+ @actual.invalid? && attributes_have_errors?
38
+ end # method matches?
39
+
40
+ # Adds an error expectation. If the actual object does not have an error on
41
+ # the specified attribute, #matches? will return false.
42
+ #
43
+ # @param [String, Symbol] attribute
44
+ #
45
+ # @return [HaveErrorsMatcher] self
46
+ #
47
+ # @example Setting an error expectation
48
+ # expect(actual).to have_errors.on(:foo)
49
+ def on attribute
50
+ @error_expectations << ErrorExpectation.new(attribute)
51
+
52
+ self
53
+ end # method on
54
+
55
+ # Adds a message expectation for the most recently added error attribute.
56
+ # If the actual object does not have an error on the that attribute with
57
+ # the specified message, #matches? will return false.
58
+ #
59
+ # @param [String, Regexp] message the expected error message. If a string,
60
+ # matcher will check for an exact match; if a regular expression, matcher
61
+ # will check if the message matches the regexp
62
+ #
63
+ # @raise [ArgumentError] if no error attribute has been added
64
+ #
65
+ # @return [HaveErrorsMatcher] self
66
+ #
67
+ # @example Setting an error and a message expectation
68
+ # expect(actual).to have_errors.on(:foo).with("can't be blank")
69
+ #
70
+ # @see #on
71
+ def with_message message
72
+ raise ArgumentError.new "no attribute specified for error message" if
73
+ @error_expectations.empty?
74
+
75
+ @error_expectations.last.messages << MessageExpectation.new(message)
76
+
77
+ self
78
+ end # method with_message
79
+
80
+ # Adds a set of message expectations for the most recently added error
81
+ # attribute.
82
+ #
83
+ # @param [Array<String, Regexp>] messages
84
+ #
85
+ # @see #with_message
86
+ def with_messages *messages
87
+ messages.each do |message| self.with_message(message); end
88
+
89
+ self
90
+ end # method with_message
91
+
92
+ # @see BaseMatcher#failure_message_for_should
93
+ def failure_message_for_should
94
+ # Failure cases:
95
+ # * object is not a model ("to respond to valid")
96
+ # * expected one or more errors, but received none ("to have errors")
97
+ # * expected one or more messages on :attribute, but received none or a
98
+ # subset ("to have errors on")
99
+
100
+ if !@validates
101
+ "expected #{@actual.inspect} to respond to :valid?"
102
+ elsif expected_errors.empty?
103
+ "expected #{@actual.inspect} to have errors"
104
+ else
105
+ "expected #{@actual.inspect} to have errors#{expected_errors_message}#{received_errors_message}"
106
+ end # if-elsif-else
107
+ end # method failure_message_for_should
108
+
109
+ # @see BaseMatcher#failure_message_for_should_not
110
+ def failure_message_for_should_not
111
+ # Failure cases:
112
+ # * expected one or more errors, received one or more ("not to have
113
+ # errors")
114
+ # * expected one or more messages on attribute, received one or more
115
+ # ("not to have errors on")
116
+ # * expected specific messages on attribute, received all ("not to have
117
+ # errors on")
118
+
119
+ if expected_errors.empty?
120
+ return "expected #{@actual.inspect} not to have errors#{received_errors_message}"
121
+ else
122
+ return "expected #{@actual.inspect} not to have errors#{expected_errors_message}#{received_errors_message}"
123
+ end # if-else
124
+ end # method failure_message_for_should_not
125
+
126
+ private
127
+
128
+ def attributes_have_errors?
129
+ # Iterate through the received errors and match them against the expected
130
+ # errors and messages.
131
+ @actual.errors.messages.each do |attribute, messages|
132
+ # Find the matching error expectation, if any.
133
+ error_expectation = @error_expectations.detect do |error_expectation|
134
+ error_expectation.attribute == attribute
135
+ end # detect
136
+
137
+ if error_expectation
138
+ error_expectation.received = true
139
+
140
+ # If the error includes message expectations, iterate through the
141
+ # received messages.
142
+ unless error_expectation.messages.empty?
143
+ messages.each do |message|
144
+ # Find the matching message expectation, if any.
145
+ message_expectation = error_expectation.messages.detect do |message_expectation|
146
+ if Regexp === message_expectation.message
147
+ message =~ message_expectation.message
148
+ else
149
+ message == message_expectation.message
150
+ end # if-else
151
+ end # detect
152
+
153
+ if message_expectation
154
+ message_expectation.received = true
155
+ else
156
+ error_expectation.messages << MessageExpectation.new(message, false, true)
157
+ end # if-else
158
+ end # each
159
+ end # unless
160
+ else
161
+ error_expectation = ErrorExpectation.new attribute, false, true
162
+ messages.each do |message|
163
+ error_expectation.messages << MessageExpectation.new(message, false, true)
164
+ end # each
165
+
166
+ @error_expectations << error_expectation
167
+ end # if-else
168
+ end # each
169
+
170
+ missing_errors.empty? && missing_messages.empty?
171
+ end # method attributes_have_errors
172
+
173
+ def expected_errors
174
+ @error_expectations.select do |error_expectation|
175
+ error_expectation.expected
176
+ end # select
177
+ end # method expected_errors
178
+
179
+ def missing_errors
180
+ @error_expectations.select do |error_expectation|
181
+ error_expectation.expected && !error_expectation.received
182
+ end # select
183
+ end # method missing_errors
184
+
185
+ def missing_messages
186
+ @error_expectations.select do |error_expectation|
187
+ !error_expectation.messages.missing.empty?
188
+ end # select
189
+ end # method missing_messages
190
+
191
+ def unexpected_errors
192
+ @error_expectations.select do |error_expectation|
193
+ !error_expectation.expected && error_expectation.received
194
+ end # select
195
+ end # method unexpected_errors
196
+
197
+ def expected_errors_message
198
+ "\n expected errors:" + expected_errors.map do |error_expectation|
199
+ "\n #{error_expectation.attribute}: " + (error_expectation.messages.empty? ?
200
+ "(any)" :
201
+ error_expectation.messages.expected.map(&:message).map(&:inspect).join(", "))
202
+ end.join # map
203
+ end # method expected_errors_message
204
+
205
+ def received_errors_message
206
+ return "" unless @validates
207
+ "\n received errors:" + @actual.errors.messages.map do |attr, ary|
208
+ "\n #{attr}: " + ary.map(&:inspect).join(", ")
209
+ end.join # map
210
+ end # method received_errors_message
211
+ end # class
212
+
213
+ module RSpec::SleepingKingStudios::Matchers
214
+ # @see RSpec::SleepingKingStudios::Matchers::ActiveModel::HaveErrorsMatcher#matches?
215
+ def have_errors
216
+ RSpec::SleepingKingStudios::Matchers::ActiveModel::HaveErrorsMatcher.new
217
+ end # method have_errors
218
+ end # module
219
+ end # module