rspec-sleeping_king_studios 2.1.1 → 2.2.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +52 -0
  3. data/DEVELOPMENT.md +26 -17
  4. data/LICENSE +1 -1
  5. data/README.md +198 -19
  6. data/lib/rspec/sleeping_king_studios/configuration.rb +63 -2
  7. data/lib/rspec/sleeping_king_studios/examples/property_examples.rb +115 -27
  8. data/lib/rspec/sleeping_king_studios/examples/rspec_matcher_examples.rb +66 -51
  9. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors.rb +8 -269
  10. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors_matcher.rb +268 -0
  11. data/lib/rspec/sleeping_king_studios/matchers/base_matcher.rb +5 -15
  12. data/lib/rspec/sleeping_king_studios/matchers/built_in/be_kind_of.rb +3 -63
  13. data/lib/rspec/sleeping_king_studios/matchers/built_in/be_kind_of_matcher.rb +65 -0
  14. data/lib/rspec/sleeping_king_studios/matchers/built_in/include.rb +3 -108
  15. data/lib/rspec/sleeping_king_studios/matchers/built_in/include_matcher.rb +134 -0
  16. data/lib/rspec/sleeping_king_studios/matchers/built_in/respond_to.rb +3 -258
  17. data/lib/rspec/sleeping_king_studios/matchers/built_in/respond_to_matcher.rb +116 -0
  18. data/lib/rspec/sleeping_king_studios/matchers/core/alias_method.rb +11 -0
  19. data/lib/rspec/sleeping_king_studios/matchers/core/alias_method_matcher.rb +107 -0
  20. data/lib/rspec/sleeping_king_studios/matchers/core/be_boolean.rb +9 -36
  21. data/lib/rspec/sleeping_king_studios/matchers/core/be_boolean_matcher.rb +37 -0
  22. data/lib/rspec/sleeping_king_studios/matchers/core/construct.rb +3 -210
  23. data/lib/rspec/sleeping_king_studios/matchers/core/construct_matcher.rb +113 -0
  24. data/lib/rspec/sleeping_king_studios/matchers/core/delegate_method.rb +11 -0
  25. data/lib/rspec/sleeping_king_studios/matchers/core/delegate_method_matcher.rb +311 -0
  26. data/lib/rspec/sleeping_king_studios/matchers/core/have_constant.rb +16 -0
  27. data/lib/rspec/sleeping_king_studios/matchers/core/have_constant_matcher.rb +225 -0
  28. data/lib/rspec/sleeping_king_studios/matchers/core/have_predicate.rb +11 -0
  29. data/lib/rspec/sleeping_king_studios/matchers/core/have_predicate_matcher.rb +97 -0
  30. data/lib/rspec/sleeping_king_studios/matchers/core/have_property.rb +3 -104
  31. data/lib/rspec/sleeping_king_studios/matchers/core/have_property_matcher.rb +108 -0
  32. data/lib/rspec/sleeping_king_studios/matchers/core/have_reader.rb +3 -74
  33. data/lib/rspec/sleeping_king_studios/matchers/core/have_reader_matcher.rb +96 -0
  34. data/lib/rspec/sleeping_king_studios/matchers/core/have_writer.rb +4 -59
  35. data/lib/rspec/sleeping_king_studios/matchers/core/have_writer_matcher.rb +55 -0
  36. data/lib/rspec/sleeping_king_studios/matchers/description.rb +62 -0
  37. data/lib/rspec/sleeping_king_studios/matchers/macros.rb +32 -0
  38. data/lib/rspec/sleeping_king_studios/matchers/shared/match_parameters.rb +168 -66
  39. data/lib/rspec/sleeping_king_studios/matchers/shared/match_property.rb +25 -0
  40. data/lib/rspec/sleeping_king_studios/matchers.rb +0 -4
  41. data/lib/rspec/sleeping_king_studios/support/method_signature.rb +51 -0
  42. data/lib/rspec/sleeping_king_studios/support/method_signature_expectation.rb +158 -0
  43. data/lib/rspec/sleeping_king_studios/support.rb +9 -0
  44. data/lib/rspec/sleeping_king_studios/version.rb +10 -4
  45. metadata +46 -30
@@ -2,6 +2,9 @@
2
2
 
3
3
  require 'rspec/sleeping_king_studios/concerns/shared_example_group'
4
4
  require 'rspec/sleeping_king_studios/examples'
5
+ require 'rspec/sleeping_king_studios/matchers/core/have_constant'
6
+ require 'rspec/sleeping_king_studios/matchers/core/have_predicate'
7
+ require 'rspec/sleeping_king_studios/matchers/core/have_property'
5
8
  require 'rspec/sleeping_king_studios/matchers/core/have_reader'
6
9
  require 'rspec/sleeping_king_studios/matchers/core/have_writer'
7
10
  require 'sleeping_king_studios/tools/object_tools'
@@ -15,50 +18,135 @@ module RSpec::SleepingKingStudios::Examples::PropertyExamples
15
18
  #
16
19
  # Internal object used to differentiate a nil expectation from a default
17
20
  # value expectation.
18
- UNDEFINED_PROPERTY_EXPECTATION = Object.new.freeze
21
+ UNDEFINED_VALUE_EXPECTATION = Object.new.freeze
19
22
 
20
- shared_examples 'has reader' do |property, expected_value = UNDEFINED_PROPERTY_EXPECTATION|
21
- it "has reader :#{property}" do
22
- object = defined?(instance) ? instance : subject
23
+ private def format_expected_value expected_value
24
+ if expected_value.is_a?(Proc)
25
+ object_tools = SleepingKingStudios::Tools::ObjectTools
26
+
27
+ if 0 == expected_value.arity
28
+ comparable_value = object_tools.apply self, expected_value
29
+ else
30
+ comparable_value = satisfy do |actual_value|
31
+ object_tools.apply self, expected_value, actual_value
32
+ end # satisfy
33
+ end # if-else
34
+ else
35
+ comparable_value = expected_value
36
+ end # if
37
+
38
+ comparable_value
39
+ end # method format_expected_value
40
+
41
+ shared_examples 'should have constant' do |constant_name, expected_value = UNDEFINED_VALUE_EXPECTATION|
42
+ it "should have constant :#{constant_name}" do
43
+ if defined?(described_class) && described_class.is_a?(Module)
44
+ object = described_class
45
+ else
46
+ object = subject
47
+ end # if-else
48
+
49
+ if expected_value == UNDEFINED_VALUE_EXPECTATION
50
+ expect(object).to have_constant(constant_name)
51
+ else
52
+ expected_value = format_expected_value(expected_value)
23
53
 
24
- expect(object).to have_reader(property)
54
+ expect(object).to have_constant(constant_name).with_value(expected_value)
55
+ end # if-else
56
+ end # it
57
+ end # shared_examples
25
58
 
26
- next if expected_value == UNDEFINED_PROPERTY_EXPECTATION
59
+ shared_examples 'should have immutable constant' do |constant_name, expected_value = UNDEFINED_VALUE_EXPECTATION|
60
+ it "should have immutable constant :#{constant_name}" do
61
+ if defined?(described_class) && described_class.is_a?(Module)
62
+ object = described_class
63
+ else
64
+ object = subject
65
+ end # if-else
27
66
 
28
- actual_value = instance.send property
67
+ if expected_value == UNDEFINED_VALUE_EXPECTATION
68
+ expect(object).to have_immutable_constant(constant_name)
69
+ else
70
+ expected_value = format_expected_value(expected_value)
29
71
 
30
- if expected_value.is_a?(Proc)
31
- args = [self, expected_value]
32
- args.push actual_value unless 0 == expected_value.arity
72
+ expect(object).to have_immutable_constant(constant_name).with_value(expected_value)
73
+ end # if-else
74
+ end # it
75
+ end # shared_examples
33
76
 
34
- expected_value = SleepingKingStudios::Tools::ObjectTools.apply *args
35
- end # if
77
+ shared_examples 'should have predicate' do |property, expected_value = UNDEFINED_VALUE_EXPECTATION|
78
+ it "should have predicate :#{property}?" do
79
+ object = defined?(instance) ? instance : subject
36
80
 
37
- case expected_value
38
- when ->(obj) { obj.respond_to?(:matches?) }
39
- expect(actual_value).to expected_value
40
- when true, false
41
- expected_value
81
+ if expected_value == UNDEFINED_VALUE_EXPECTATION
82
+ expect(object).to have_predicate(property)
42
83
  else
43
- expect(actual_value).to be == expected_value
44
- end # case
84
+ expected_value = format_expected_value(expected_value)
85
+
86
+ expect(object).to have_predicate(property).with_value(expected_value)
87
+ end # if-else
45
88
  end # it
46
89
  end # shared_examples
47
- alias_shared_examples 'should have reader', 'has reader'
90
+ alias_shared_examples 'has predicate', 'should have predicate'
48
91
 
49
- shared_examples 'has writer' do |property|
50
- it "has writer :#{property}=" do
92
+ shared_examples 'should have reader' do |property, expected_value = UNDEFINED_VALUE_EXPECTATION|
93
+ it "should have reader :#{property}" do
94
+ object = defined?(instance) ? instance : subject
95
+
96
+ if expected_value == UNDEFINED_VALUE_EXPECTATION
97
+ expect(object).to have_reader(property)
98
+ else
99
+ expected_value = format_expected_value(expected_value)
100
+
101
+ expect(object).to have_reader(property).with_value(expected_value)
102
+ end # if-else
103
+ end # it
104
+ end # shared_examples
105
+ alias_shared_examples 'has reader', 'should have reader'
106
+
107
+ shared_examples 'should not have reader' do |property|
108
+ it "should not have reader :#{property}" do
109
+ object = defined?(instance) ? instance : subject
110
+
111
+ expect(object).not_to have_reader(property)
112
+ end # it
113
+ end # shared_examples
114
+ alias_shared_examples 'does not have reader', 'should not have reader'
115
+
116
+ shared_examples 'should have writer' do |property|
117
+ property_name = property.to_s.sub /\=\z/, ''
118
+
119
+ it "should have writer :#{property_name}=" do
51
120
  object = defined?(instance) ? instance : subject
52
121
 
53
122
  expect(object).to have_writer(property)
54
123
  end # it
55
124
  end # shared_examples
56
- alias_shared_examples 'should have writer', 'has writer'
125
+ alias_shared_examples 'has writer', 'should have writer'
57
126
 
58
- shared_examples 'has property' do |property, expected_value = UNDEFINED_PROPERTY_EXPECTATION|
59
- include_examples 'has reader', property, expected_value
127
+ shared_examples 'should not have writer' do |property|
128
+ property_name = property.to_s.sub /\=\z/, ''
60
129
 
61
- include_examples 'has writer', property
130
+ it "should not have writer :#{property}=" do
131
+ object = defined?(instance) ? instance : subject
132
+
133
+ expect(object).not_to have_writer(property)
134
+ end # it
135
+ end # shared_examples
136
+ alias_shared_examples 'does not have writer', 'should not have writer'
137
+
138
+ shared_examples 'should have property' do |property, expected_value = UNDEFINED_VALUE_EXPECTATION|
139
+ it "should have property :#{property}" do
140
+ object = defined?(instance) ? instance : subject
141
+
142
+ if expected_value == UNDEFINED_VALUE_EXPECTATION
143
+ expect(object).to have_property(property)
144
+ else
145
+ expected_value = format_expected_value(expected_value)
146
+
147
+ expect(object).to have_property(property).with_value(expected_value)
148
+ end # if-else
149
+ end # it
62
150
  end # shared_examples
63
- alias_shared_examples 'should have property', 'has property'
151
+ alias_shared_examples 'has property', 'should have property'
64
152
  end # module
@@ -8,54 +8,74 @@ require 'rspec/sleeping_king_studios/matchers/base_matcher'
8
8
  module RSpec::SleepingKingStudios::Examples::RSpecMatcherExamples
9
9
  extend RSpec::SleepingKingStudios::Concerns::SharedExampleGroup
10
10
 
11
- shared_examples 'passes with a positive expectation' do
11
+ private def config
12
+ RSpec.configuration.sleeping_king_studios
13
+ end # method config
14
+
15
+ private def compare_message actual, expected
16
+ case expected
17
+ when String
18
+ if config.examples.match_string_failure_message_as == :exact
19
+ expect(actual).to be == expected
20
+ else
21
+ expect(actual).to include expected
22
+ end # if-else
23
+ when Regexp
24
+ expect(actual).to be =~ expected
25
+ when ->(obj) { obj.respond_to?(:matches?) && obj.respond_to?(:failure_message) }
26
+ expect(actual).to expected
27
+ else
28
+ expect(actual).to match expected
29
+ end # when
30
+ end # method compare_message
31
+
32
+ private def handle_missing_failure_message message
33
+ case config.examples.handle_missing_failure_message_with
34
+ when :pending
35
+ skip message
36
+ when :exception
37
+ raise StandardError.new message
38
+ end # case
39
+ end # method handle_missing_failure_message
40
+
41
+ shared_examples 'should pass with a positive expectation' do
12
42
  let(:matcher_being_examined) { defined?(instance) ? instance : subject }
13
43
 
14
- it 'passes with a positive expectation' do
44
+ it 'should pass with positive expectation' do
15
45
  expect(matcher_being_examined.matches? actual).to be true
16
46
  end # it
17
47
  end # shared_examples
18
- alias_shared_examples 'should pass with a positive expectation', 'passes with a positive expectation'
48
+ alias_shared_examples 'passes with a positive expectation', 'should pass with a positive expectation'
19
49
 
20
- shared_examples 'fails with a positive expectation' do
50
+ shared_examples 'should fail with a positive expectation' do
21
51
  let(:matcher_being_examined) { defined?(instance) ? instance : subject }
22
52
 
23
- it 'fails with a positive expectation' do
53
+ it 'should fail with a positive expectation' do
24
54
  expect(matcher_being_examined.matches? actual).to be false
25
55
  end # it
26
56
 
27
- it 'has a failure message with a positive expectation' do
57
+ it 'should have a failure message with a positive expectation' do
28
58
  if defined?(failure_message)
29
59
  matcher_being_examined.matches?(actual)
30
60
 
31
- expected = failure_message.is_a?(String) ?
32
- Regexp.new(Regexp.escape(failure_message)) :
33
- failure_message
34
-
35
- expect(matcher_being_examined.failure_message).to match expected
61
+ compare_message(matcher_being_examined.failure_message, failure_message)
36
62
  else
37
- message = <<-MESSAGE
38
- expected to match #{matcher_being_examined.class}#failure_message, but the expected
39
- value was undefined. Define a failure message using
40
- let(:failure_message) or set
41
- config.handle_missing_failure_message_with to :ignore or :pending.
42
- MESSAGE
43
- message = message.split("\n").map(&:strip).join(' ')
44
- case RSpec.configuration.sleeping_king_studios.examples.handle_missing_failure_message_with
45
- when :pending
46
- skip message
47
- when :exception
48
- raise StandardError.new message
49
- end # case
63
+ message =
64
+ "expected to match #{matcher_being_examined.class}#failure_message, "\
65
+ "but the expected value was undefined. Define a failure message "\
66
+ "using let(:failure_message) or set "\
67
+ "config.handle_missing_failure_message_with to :ignore or :pending."
68
+
69
+ handle_missing_failure_message(message)
50
70
  end # if
51
71
  end # it
52
72
  end # shared_examples
53
- alias_shared_examples 'should fail with a positive expectation', 'fails with a positive expectation'
73
+ alias_shared_examples 'fails with a positive expectation', 'should fail with a positive expectation'
54
74
 
55
- shared_examples 'passes with a negative expectation' do
75
+ shared_examples 'should pass with a negative expectation' do
56
76
  let(:matcher_being_examined) { defined?(instance) ? instance : subject }
57
77
 
58
- it 'passes with a negative expectation' do
78
+ it 'should pass with a negative expectation' do
59
79
  if matcher_being_examined.respond_to?(:does_not_match?)
60
80
  expect(matcher_being_examined.does_not_match? actual).to be true
61
81
  else
@@ -63,12 +83,12 @@ module RSpec::SleepingKingStudios::Examples::RSpecMatcherExamples
63
83
  end # if-else
64
84
  end # it
65
85
  end # shared_examples
66
- alias_shared_examples 'should pass with a negative expectation', 'passes with a negative expectation'
86
+ alias_shared_examples 'passes with a negative expectation', 'should pass with a negative expectation'
67
87
 
68
- shared_examples 'fails with a negative expectation' do
88
+ shared_examples 'should fail with a negative expectation' do
69
89
  let(:matcher_being_examined) { defined?(instance) ? instance : subject }
70
90
 
71
- it 'fails with a negative expectation' do
91
+ it 'should fail with a negative expectation' do
72
92
  if matcher_being_examined.respond_to?(:does_not_match?)
73
93
  expect(matcher_being_examined.does_not_match? actual).to be false
74
94
  else
@@ -76,31 +96,26 @@ module RSpec::SleepingKingStudios::Examples::RSpecMatcherExamples
76
96
  end # if-else
77
97
  end # it
78
98
 
79
- it 'has a failure message with a negative expectation' do
99
+ it 'should have a failure message with a negative expectation' do
80
100
  if defined?(failure_message_when_negated)
81
- matcher_being_examined.respond_to?(:does_not_match?) ? matcher_being_examined.does_not_match?(actual) : matcher_being_examined.matches?(actual)
82
-
83
- expected = failure_message_when_negated.is_a?(String) ?
84
- Regexp.new(Regexp.escape(failure_message_when_negated)) :
85
- failure_message_when_negated
101
+ if matcher_being_examined.respond_to?(:does_not_match?)
102
+ matcher_being_examined.does_not_match?(actual)
103
+ else
104
+ matcher_being_examined.matches?(actual)
105
+ end # if-else
86
106
 
87
- expect(matcher_being_examined.failure_message_when_negated).to match expected
107
+ compare_message(matcher_being_examined.failure_message_when_negated, failure_message_when_negated)
88
108
  else
89
- message = <<-MESSAGE
90
- expected to match #{matcher_being_examined.class}#failure_message_when_negated, but
91
- the expected value was undefined. Define a failure message using
92
- let(:failure_message_when_negated) or set
93
- config.handle_missing_failure_message_with to :ignore or :pending.
94
- MESSAGE
95
- message = message.split("\n").map(&:strip).join(' ')
96
- case RSpec.configuration.sleeping_king_studios.examples.handle_missing_failure_message_with
97
- when :pending
98
- skip message
99
- when :exception
100
- raise StandardError.new message
101
- end # case
109
+ message =
110
+ "expected to match #{matcher_being_examined.class}#"\
111
+ "failure_message_when_negated, but the expected value was undefined."\
112
+ " Define a failure message using let(:failure_message_when_negated) "\
113
+ "or set config.handle_missing_failure_message_with to :ignore or "\
114
+ ":pending."
115
+
116
+ handle_missing_failure_message(message)
102
117
  end # if
103
118
  end # it
104
119
  end # shared_examples
105
- alias_shared_examples 'should fail with a negative expectation', 'fails with a negative expectation'
120
+ alias_shared_examples 'fails with a negative expectation', 'should fail with a negative expectation'
106
121
  end # module
@@ -1,272 +1,11 @@
1
1
  # lib/rspec/sleeping_king_studios/matchers/active_model/have_errors.rb
2
2
 
3
- require 'rspec/sleeping_king_studios/matchers/base_matcher'
4
- require 'rspec/sleeping_king_studios/matchers/active_model'
5
- require 'rspec/sleeping_king_studios/matchers/active_model/have_errors/error_expectation'
6
- require 'sleeping_king_studios/tools/enumerable_tools'
7
- require 'sleeping_king_studios/tools/string_tools'
8
-
9
- module RSpec::SleepingKingStudios::Matchers::ActiveModel
10
- # Matcher for testing ActiveModel object validations.
11
- #
12
- # @since 1.0.0
13
- class HaveErrorsMatcher < RSpec::SleepingKingStudios::Matchers::BaseMatcher
14
- include RSpec::SleepingKingStudios::Matchers::ActiveModel::HaveErrors
15
- include SleepingKingStudios::Tools::EnumerableTools
16
- include SleepingKingStudios::Tools::StringTools
17
-
18
- def initialize
19
- super
20
-
21
- # The error and message expectations are set up through #on and
22
- # #with_message.
23
- @error_expectations = []
24
- end # constructor
25
-
26
- # (see BaseMatcher#description)
27
- def description
28
- message = 'have errors'
29
-
30
- attribute_messages = @error_expectations.select(&:expected).map do |expectation|
31
- attribute_message = ":#{expectation.attribute}"
32
-
33
- error_messages = expectation.messages.select(&:expected).map do |message_expectation|
34
- %{"#{message_expectation.message}"}
35
- end # map
36
-
37
- unless error_messages.empty?
38
- attribute_message << " with #{pluralize(error_messages.count, 'message', 'messages')} #{humanize_list error_messages}"
39
- end # unless
40
-
41
- attribute_message
42
- end # each
43
- message << " on #{attribute_messages.join(", and on ")}" unless attribute_messages.empty?
44
-
45
- message
46
- end # method description
47
-
48
- # Checks if the object can be validated, whether the object is valid, and
49
- # checks the errors on the object against the expected errors and messages
50
- # from #on and #with_message, if any.
51
- #
52
- # @param [Object] actual The object to test against the matcher.
53
- #
54
- # @return [Boolean] True if the object responds to :valid? and is valid
55
- # or object.errors does not match the specified errors and messages (if
56
- # any); otherwise false.
57
- #
58
- # @see #matches?
59
- def does_not_match? actual
60
- @negative_expectation = true
61
-
62
- return false unless @validates = actual.respond_to?(:valid?)
63
-
64
- !matches?(actual)
65
- end # method does_not_match?
66
-
67
- # Checks if the object can be validated, whether the object is valid, and
68
- # checks the errors on the object against the expected errors and messages
69
- # from #on and #with_message, if any.
70
- #
71
- # @param [Object] actual The object to test against the matcher.
72
- #
73
- # @return [Boolean] True if the object responds to :valid?, is not valid,
74
- # and object.errors matches the specified errors and messages (if any);
75
- # otherwise false.
76
- #
77
- # @see RSpec::SleepingKingStudios::Matchers::BaseMatcher#matches?
78
- def matches? actual
79
- super
80
-
81
- return false unless @validates = actual.respond_to?(:valid?)
82
-
83
- !@actual.valid? && attributes_have_errors?
84
- end # method matches?
85
-
86
- # Adds an error expectation. If the actual object does not have an error on
87
- # the specified attribute, #matches? will return false.
88
- #
89
- # @param [String, Symbol] attribute
90
- #
91
- # @return [HaveErrorsMatcher] self
92
- #
93
- # @example Setting an error expectation
94
- # expect(actual).to have_errors.on(:foo)
95
- def on attribute
96
- @error_expectations << ErrorExpectation.new(attribute)
97
-
98
- self
99
- end # method on
100
-
101
- # Adds a message expectation for the most recently added error attribute.
102
- # If the actual object does not have an error on the that attribute with
103
- # the specified message, #matches? will return false.
104
- #
105
- # @param [String, Regexp] message The expected error message. If a string,
106
- # matcher will check for an exact match; if a regular expression, matcher
107
- # will check if the message matches the regexp.
108
- #
109
- # @raise [ArgumentError] If no error attribute has been added.
110
- #
111
- # @return [HaveErrorsMatcher] self
112
- #
113
- # @example Setting an error and a message expectation
114
- # expect(actual).to have_errors.on(:foo).with("can't be blank")
115
- #
116
- # @see #on
117
- def with_message message
118
- raise ArgumentError.new "no attribute specified for error message" if
119
- @error_expectations.empty?
120
-
121
- @error_expectations.last.messages << MessageExpectation.new(message)
122
-
123
- self
124
- end # method with_message
125
-
126
- # Adds a set of message expectations for the most recently added error
127
- # attribute.
128
- #
129
- # @param [Array<String, Regexp>] messages
130
- #
131
- # @see #with_message
132
- def with_messages *messages
133
- messages.each do |message| self.with_message(message); end
134
-
135
- self
136
- end # method with_message
137
- alias_method :with, :with_messages
138
-
139
- # (see BaseMatcher#failure_message)
140
- def failure_message
141
- # Failure cases:
142
- # * object is not a model ("to respond to valid")
143
- # * expected one or more errors, but received none ("to have errors")
144
- # * expected one or more messages on :attribute, but received none or a
145
- # subset ("to have errors on")
146
-
147
- if !@validates
148
- "expected #{@actual.inspect} to respond to :valid?"
149
- elsif expected_errors.empty?
150
- "expected #{@actual.inspect} to have errors"
151
- else
152
- "expected #{@actual.inspect} to have errors#{expected_errors_message}#{received_errors_message}"
153
- end # if-elsif-else
154
- end # method failure_message
155
-
156
- # (see BaseMatcher#failure_message_when_negated)
157
- def failure_message_when_negated
158
- # Failure cases:
159
- # * object is not a model ("to respond to valid")
160
- # * expected one or more errors, received one or more ("not to have
161
- # errors")
162
- # * expected one or more messages on attribute, received one or more
163
- # ("not to have errors on")
164
- # * expected specific messages on attribute, received all ("not to have
165
- # errors on")
166
-
167
- if !@validates
168
- "expected #{@actual.inspect} to respond to :valid?"
169
- elsif expected_errors.empty?
170
- return "expected #{@actual.inspect} not to have errors#{received_errors_message}"
171
- else
172
- return "expected #{@actual.inspect} not to have errors#{expected_errors_message}#{received_errors_message}"
173
- end # if-else
174
- end # method failure_message_when_negated
175
-
176
- private
177
-
178
- def attributes_have_errors?
179
- # Iterate through the received errors and match them against the expected
180
- # errors and messages.
181
- @actual.errors.messages.each do |attribute, messages|
182
- # Find the matching error expectation, if any.
183
- error_expectation = @error_expectations.detect do |error_expectation|
184
- error_expectation.attribute == attribute
185
- end # detect
186
-
187
- if error_expectation
188
- error_expectation.received = true
189
-
190
- # If the error includes message expectations, iterate through the
191
- # received messages.
192
- unless error_expectation.messages.empty?
193
- messages.each do |message|
194
- # Find the matching message expectation, if any.
195
- message_expectation = error_expectation.messages.detect do |message_expectation|
196
- if Regexp === message_expectation.message
197
- message =~ message_expectation.message
198
- else
199
- message == message_expectation.message
200
- end # if-else
201
- end # detect
202
-
203
- if message_expectation
204
- message_expectation.received = true
205
- else
206
- error_expectation.messages << MessageExpectation.new(message, false, true)
207
- end # if-else
208
- end # each
209
- end # unless
210
- else
211
- error_expectation = ErrorExpectation.new attribute, false, true
212
- messages.each do |message|
213
- error_expectation.messages << MessageExpectation.new(message, false, true)
214
- end # each
215
-
216
- @error_expectations << error_expectation
217
- end # if-else
218
- end # each
219
-
220
- missing_errors.empty? && missing_messages.empty?
221
- end # method attributes_have_errors
222
-
223
- def expected_errors
224
- @error_expectations.select do |error_expectation|
225
- error_expectation.expected
226
- end # select
227
- end # method expected_errors
228
-
229
- def missing_errors
230
- @error_expectations.select do |error_expectation|
231
- error_expectation.expected && !error_expectation.received
232
- end # select
233
- end # method missing_errors
234
-
235
- def missing_messages
236
- @error_expectations.select do |error_expectation|
237
- !error_expectation.messages.missing.empty?
238
- end # select
239
- end # method missing_messages
240
-
241
- def unexpected_errors
242
- @error_expectations.select do |error_expectation|
243
- !error_expectation.expected && error_expectation.received
244
- end # select
245
- end # method unexpected_errors
246
-
247
- def expected_errors_message
248
- "\n expected errors:" + expected_errors.map do |error_expectation|
249
- "\n #{error_expectation.attribute}: " + (error_expectation.messages.empty? ?
250
- "(#{@negative_expectation ? 'none' : 'any'})" :
251
- error_expectation.messages.expected.map(&:message).map(&:inspect).join(", "))
252
- end.join # map
253
- end # method expected_errors_message
254
-
255
- def received_errors_message
256
- return "" unless @validates
257
-
258
- return "\n received errors:\n (none)" if @actual.errors.messages.empty?
259
-
260
- "\n received errors:" + @actual.errors.messages.map do |attr, ary|
261
- "\n #{attr}: " + ary.map(&:inspect).join(", ")
262
- end.join # map
263
- end # method received_errors_message
264
- end # class
265
-
266
- module RSpec::SleepingKingStudios::Matchers
267
- # @see RSpec::SleepingKingStudios::Matchers::ActiveModel::HaveErrorsMatcher#matches?
268
- def have_errors
269
- RSpec::SleepingKingStudios::Matchers::ActiveModel::HaveErrorsMatcher.new
270
- end # method have_errors
271
- end # module
3
+ require 'rspec/sleeping_king_studios/matchers/active_model/have_errors_matcher'
4
+ require 'rspec/sleeping_king_studios/matchers/macros'
5
+
6
+ module RSpec::SleepingKingStudios::Matchers::Macros
7
+ # @see RSpec::SleepingKingStudios::Matchers::ActiveModel::HaveErrorsMatcher#matches?
8
+ def have_errors
9
+ RSpec::SleepingKingStudios::Matchers::ActiveModel::HaveErrorsMatcher.new
10
+ end # method have_errors
272
11
  end # module